MySQLのJSON型の値をGenerated Columnsを使ってカラムにデータを追加してみる

MySQLのGenerated Columnsを使う必要があり、動作が気になったので検証してみました。

Generated Columns(生成カラム)とは

Values of a generated column are computed from an expression included in the column definition. [翻訳] 生成された列の値は、列定義に含まれている式から計算されます。

つまり、Generated Columnsの値には、そのカラムを定義したときに定義した関数や式の計算結果の値が入るということ。

MySQL :: MySQL 5.7 Reference Manual :: 13.1.18.8 CREATE TABLE and Generated Columns

なるほど、もう少し手を動かして掴んでみましょう。

作業

MySQLに接続するまで

試すには、Generated Columnsが追加されたバージョン 5.7.6 以上のMySQLをインストールします。

Dockerでサクッとやる。

docker pull mysql

これで最新のMySQLのイメージを取得。

docker run --name mysql -e MYSQL_ROOT_PASSWORD=mysql -d -p 3306:3306 mysql

これでMySQLを起動。 rootのパスワードはmysql

次は、MySQLのコンテナに入る。

docker exec -it `CONTAINER ID` /bin/bash

MySQLに接続する。 パスワードはさっき書いたものを入力する。

mysql -u root -p

データベースを作成する

以下のコマンドでデータベースを作成する。

create database gc_db;

テーブルを作成する

以下のコマンドでテーブルを作成する。

create table gc_test(id int unsigned auto_increment not null primary key, json_data json);

カラムは id , json_data のみでひとまず作成する。

データを追加する

以下のコマンドでデータを追加する。

insert into gc_test(json_data) values ('{"demo": {"id": 1}}'), ('{"demo": {"id": 2}}'), ('{"demo": {"id": 3}}');

これでJSONデータを含むテーブルができました。

mysql> select * from gc_test;
+----+---------------------+
| id | json_data           |
+----+---------------------+
|  1 | {"demo": {"id": 1}} |
|  2 | {"demo": {"id": 2}} |
|  3 | {"demo": {"id": 3}} |
+----+---------------------+

次は、Generated Columnsを定義します。

Generated Columnsを定義する

今回、Generated Columnsを定義するとき、 json_data カラムの demo オブジェクト中の id を取り出すように定義します。

次のコマンドでテーブルにGenerated Columnsを追加します。

alter table gc_test add column demo_id varchar(255) GENERATED ALWAYS AS (json_extract(`json_data`, '$.demo.id')) STORED;

STORED というキーワードを書いているが、他にもVIRTUALが存在します。 デフォルトでは、VIRTUALが選択されます。

このキーワードで、生成された値をストレージに格納するかを決めることができます。

VIRTUAL

VIRTUAL の場合は、ストレージには保存されず、BEFOREトリガーの後に行が読まれたときに評価されます。

VIRTUAL: Column values are not stored, but are evaluated when rows are read, immediately after any BEFORE triggers. A virtual column takes no storage.

引用 MySQL :: MySQL 5.7 Reference Manual :: 13.1.18.8 CREATE TABLE and Generated Columns

行が読み込まれたときに評価だと、Generated Columnsの値で検索を絞り込むときにパフォーマンスは悪いのかな? そこらへんはデータを大量に用意して後日試してみたい。

STORED

STOREDの場合は、行がINSERTまたはUPDATEされたときに評価されて値が格納されます。

STORED: Column values are evaluated and stored when rows are inserted or updated. A stored column does require storage space and can be indexed.

引用 MySQL :: MySQL 5.7 Reference Manual :: 13.1.18.8 CREATE TABLE and Generated Columns

Generated Columnsを定義した後はこんな感じになります。

mysql> select * from gc_test;
+----+---------------------+---------+
| id | json_data           | demo_id |
+----+---------------------+---------+
|  1 | {"demo": {"id": 1}} | 1       |
|  2 | {"demo": {"id": 2}} | 2       |
|  3 | {"demo": {"id": 3}} | 3       |
+----+---------------------+---------+

json_dataのdemoオブジェクトの中のidが、demo_id として取り出されてカラムに格納されているのが分かりますね。

検索のパフォーマンスがどうなるのかがモヤモヤしてきたので、 そこらへんはドキュメント読むなり実際に試してみて計測したほうが良さそうだな。

以上です。

[Android] [Kotlin] Android開発でRoomとKoinの設定

今、UdemyのAndroid開発コースをやっていて、そのコースではRoomとToothPickというライブラリを使って開発が進むのですが、個人的にKoinを使いたくてドキュメント見ながらやると見事に設定の記述漏れでハマったので、備忘録として書いておきます。

Kotlinのバージョンは、1.3.20 を使用。

Module: appbuild.gradle に以下の記述を追加する。

// Room
def room_version = "2.1.0-alpha05"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"

// Koin
def koin_version = "1.0.2"
implementation "org.koin:koin-android:$koin_version"
implementation "org.koin:koin-android-scope:$koin_version"
implementation "org.koin:koin-android-viewmodel:$koin_version"

今回、以下の設定が抜けていたためビルドは通る?けど、アプリが起動しないため原因が最初どこかわからなくて1時間ぐらい時間溶かしてしまいました。

// Room
kapt "androidx.room:room-compiler:$room_version"

ちなみに、kapt を利用するには以下の記述が必要です。

apply plugin: 'kotlin-kapt'

kaptは Kotlin Annotation Processing Tool(であってる?)で、 Java6から導入された Pluggable Annotation Processing API を Kotlinからも利用できるようにしたものです。

Koinは Applicationクラスを継承したAppクラスに設定を記述しました。

class App : Application() {
    override fun onCreate() {
        super.onCreate()

        startKoin(this,
            listOf(AppModule.module())
        )
    }

    companion object {
        lateinit var instance: Application
    }

    init {
        instance = this
    }
}

AppModulemodule() 関数内にDIの設定を記述しました。

object AppModule {
    fun module() = module {
        single<ITaskModel> { TaskLocalModel() }
        single<INoteModel> { NoteLocalModel() }
        single {
            RoomDatabaseClient.getInstance(App.instance.applicationContext)
        }
    }
}

これで合っているのかよく分からないので、間違っていたらコメントとかもらえると嬉しいです。

以上です。

UdemyのKotlin for Android O Developmentというコースが良かった!

普段はWeb開発しかしていないのだけれど、モバイルアプリを開発する必要性が出てきたので最近いろいろサンプルアプリを作ったり、ライブラリを試しに動かしたりしている。

そのいった中で、Udemyの「Kotlin for Android O Development」というコースが個人的に総合して良いと思ったので、良かった点・気になった点に分けて感想をまとめてみる。

良かった点

Kotlinを使ったAndroidの開発コースであること

このコースはKotlinを使って1からサンプルアプリを開発していくため、KotlinでAndroidアプリを開発していきたいと思っていた僕にはちょうどよかった。

Kotlinで書かれた書籍はいつくかあるもののまだまだJavaで説明されているものも多いので、Udemyのような動画で学ぶことには意味がある。

サンプル数が多い

なにか新しい言語や仕組みを学ぶときは本を読むのも良いが、実際にものを作って動かしてから書籍を読んだ方が個人的には理解力が高まると思っているので、とにかくサンプルアプリを作りまくりたかった。

このコースでは、10個以上のサンプルアプリを作ることが可能なので、とりあえず手を動かして覚えたい人におすすめしたい。

DBを使ったサンプルがある

モバイルアプリを開発するにあたってDBを使うことは多々あるのではないかと思う。

このコースでは簡単ではあるがSQLiteを使ってアプリを作ることもできるので良かった。

Firebaseを使ったアプリも作れる

コースの総まとめとして、今まで作ってきたサンプルアプリの機能を駆使して、そしてFirebaseも利用してアプリを作ることができる。

実際に使ってみると分かるが、Firebase簡単すぎっ!!ってなる。

少し気になったのは、コースで使っているFirebaseのライブラリのバージョンが古いので、 deprecated になっているメソッドを呼び出していたりしていた。

僕がアプリを作ったときは最新バージョンを使うようにしていたので、値がうまく取れないなと思ったら上記のような理由が原因だった。Firebaseドキュメントや他の方の記事を参考にすれば解決できるはずだ。

Android でファイルをアップロードする  |  Firebase

気になった点

ListViewのみを使っていた

おそらくBeginner向けのコースであるからだと思うが、RecyclerViewもコースに盛り込めばいいのにと思った。 おそらく普段Androidアプリを開発されている方はListViewとか使うのか?と思ったりしたのでここらへんは気になった。

Fragmentは扱われていない

普通はAcitivityのみを使って開発は行わないと思うのでFragmentについてのチャプターもあってもいいんじゃないかと思った。 このコースではFragmentは学べないため、記事を見るなり本を読むなりして学ぶのが良いだろう。

最後に

Kotlin for Android O Development: From Beginner to Advanced

このコースは講師の方が英語で説明するため、英語字幕を出しながら動画を視聴していた。話すスピードはゆっくりで難しいことは話さないので、そんなに英語が得意でない僕でも理解できたのでおすすめである。

RecyclerViewやCardViewはAndroid Developersの記事を読むのが良さげ。

developer.android.com

まだまだ知らないといけない部分があるので、このまま継続してAndroid開発の学習・開発を進めていく。

おすすめの記事やこれだけはやっておけみたいなのがあれば、 ブログのコメントかTwitterに投げつけてくださると嬉しいです!

では!

AWS CloudFrontのキャッシュを削除する方法

静的ページをCloudFront + S3でホストしていて画像を更新したけど、キャッシュのせいで反映されないということがありそうです。

そんなときにキャッシュの有効期限まで待つのではなく、自分でキャッシュを削除して反映させたいはず。

この記事では、AWSのCloudFrontでどうやってキャッシュを削除するかを知ることができます。

では、いってみましょう。

ファイルを無効化

CloudFrontにはInvalidationというものがあり、これをCreateすることでキャッシュを削除することができます。 Edgeサーバーにあるファイルを無効化するからInvalidation。

手順

1. コンソールで [CloudFront Distributes]を開く。

f:id:ryskit:20190209171501j:plain

2. [ディストリビューション] を選択する。

選択したディストリビューションの概要が表示されます。

f:id:ryskit:20190209171840j:plain

3. [Invalidations] タブを選択する。

f:id:ryskit:20190209171915j:plain

4. [Create Invalidation] ボタンをクリックする。

f:id:ryskit:20190209172213j:plain

ボックスの中にキャッシュを削除したいファイルのパスを入力してください。

画像のように記述すると、 /images/xxxx.jpg のキャッシュを削除することになります。

まとめてキャッシュを削除したいときは、 /* のような指定をするとすべてキャッシュを削除できます。

5. [Invalidate] ボタンをクリックする。

選択すると、CloudFrontのEdgeサーバーのキャッシュ削除処理が開始されます。 Status が In Progress の場合はまだ削除処理中で、 Complete になれば完了です。

こちらにAWSの公式ドキュメントがあるので、詳細を知りたい場合は参考にしてみてください。

Databindingを利用したアプリをビルドするとUnresolved reference: BR エラーになった

Androidアプリの開発を始めて、Databindingが便利そうというかMVVMなどのアーキテクチャで実装しようとすると必須?みたいなので、とりあえず簡単なサンプルアプリを実装して、どんなものか簡単に実装を理解しようとした。

アプリを書き終わったのでビルドしようとすると Unresolved reference: BR というエラーに出くわしてしまった。

結論から言うと、

(Module: app) build.gradle に apply plugin: 'kotlin-kapt' の記載を書いたら解決した。

経緯

Googleのドキュメントを見る限り、 (Module: app) build.gradleに、

android {
    ....
    dataBinding {
        enabled = true
    }
}

を書くだけでデータバインディングの準備はOKなのかなと思っていた。

そのため、以下のようにViewHolderクラスで ViewDataBinding に変数をセットするコードを書いてビルドしてみるとエラーになった。

class WeatherViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {

    fun bind(data: Any) {
        binding.setVariable(BR.data, data) // ここで kotlin compiler にUnresolved reference: BR と表示された
        binding.executePendingBindings()     
    }
}

どうやら、BRクラスファイルの参照解決ができてないということで、 うーんとうなりながらぐぐってみると以下の記事に行き着きました。

medium.com

どうやらこいつが必要らしい。

apply plugin: 'kotlin-kapt'

ということで、build.gradleに記載してビルドしてみるとすんなりエラーなくビルドできました。

いろいろ昔の記事を見ていると、

kapt 'com.android.databinding:compiler:x.x.x'

を書いてる記事とかあるんだけど、これはもう書かなくて良いっぽい。

最後に

不慣れなことをすると、すぐバグ踏んだり躓いたりしやすいから、早く慣れていきたい。 友達とサービス作るときに、キダくんAndroidアプリ開発で参加してよ!って声がいっぱいかかるぐらいにはスキルアップしていくぞ!

Rustをインストールして始めてみる

会社の人から、Rustはすごくいいぞ〜と言われ、O'Reillyから出てるプログラミングRustを読んだりしている。

Rustをインストールしたとき、すごく簡単だったので手順を記しておく。 といっても、以下のコマンド叩くだけ。

curl https://sh.rustup.rs -sSf | sh

すごく簡単なので、すぐにRustを始められるのが良かったと思う。

あとRustをインストールすると、CargoというRustのビルドシステム兼パッケージマネージャが一緒にインストールされるけど、これがいろいろ面倒なことを代わりにやってくれるので、プロジェクトのセットアップに躓くことがなかったのは嬉しい。

案件のどこかで使えるようにしておきたい。

GoLand 2018.2 でDebugを起動できなくなった

Goならわかるシステムプログラミングって本を読んでて、 一章には、fmt.Println("Hello World")をデバッガーを使ってシステムコールの「見る」と書いてあったので、 素直にGoLandでデバッガーを起動すると以下のようなエラーが出た。

could not launch process: debugserver or lldb-server not found: install XCode's command line tools or lldb-server

解決策としては以下のチェックボックスにチェックを入れれば解決するよ!

Preferences > Build, Execution, Deployment > Debuggerを開いて、 Use native backend にチェックを入れてApplyすればOK!

f:id:ryskit:20180820013324j:plain

【Golang】RequestからQueryStringを取得するには

最近Golangでコマンドラインツールを作りたくて、Golangのサンプルコードとかを動かしていろいろ遊びながら覚えているところなのですが、たまたまEchoサーバーのプログラムがあったので試したのですがすごく簡単にかけますね!

そのとき、リクエストからQuery Stringをどう抜き出すんだろと思って試しに書いてみました。

package main

import (
    "net/http"
    "log"
    "fmt"
)

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe("localhost:8000", nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s %s %s\n", r.Method, r.URL, r.Proto)
    v := r.URL.Query()
    if v == nil {
        return
    }
    for key, vs := range v {
        fmt.Fprintf(w, "%s = %s\n", key, vs[0])
    }
}

r.URL.Query()type Values map[string][]string を受け取ることができるので、rangeでループ回して表示しています。

個別にキーを指定して取得したい場合は以下のようにキーを指定してあげれば取得できるはず

r.URL.Query().Get(キー)