🧨

Datastoreで虚無値を扱う際のトラップ

2022/04/12に公開

Firestore Datastoreモードで虚無値を扱う際にはトラップが存在するのでまとめます。

クエリで指定されたプロパティがないエンティティは無視される

Datastoreでは、プロパティが存在しない、ということをMySQLでいう IS NULL のようにクエリすることはできません。

ここに書かれている通りではありますが、エンティティがAというキーを持たない場合は、そのエンティティはAキーのインデックスに乗らず、いかなる手段を用いてもAキーでのクエリ結果には乗りません。
将来的にAに虚無値を持つエンティティをクエリしたい可能性がある場合にはAに明示的にnullを指定しておきます。

nullを持つエンティティが想定外のクエリの結果に入る

const query = datastore.createQuery("Foo").filter("Prop", "<", 0);
const [entities] = await datastore.runQuery(query);

上記のような実装で、Propがnullのエンティティが返ります。
どうやら、nullという値は全ての数値よりも小さい値としてインデックスされるようで、 filter("Prop", "<", -9223372036854775295) としてもnullは入ってきます。

これを回避するには、以下のように実装します。

const query = datastore.createQuery("Foo").filter("Prop", "<", 0).filter("Prop", ">", null);

Goではnullをクエリできない?

ドキュメントや実装を読む限りでは、Goのdatastoreライブラリではnullをクエリするための実装が用意されていません。

var entities []Entity
q := datastore.NewQuery("Foo").Filter("Prop =", nil)
if _, err := client.GetAll(ctx, q, &entities); err != nil {
	log.Fatal(err)
}

上記のような実装でnullをクエリできそうな気がするのですが、 panic: reflect: call of reflect.Value.Interface on zero Value とFatalを吐きます。
もしクエリする方法をご存知の方がいらっしゃいましたら教えてください。

擬似的には、 q := datastore.NewQuery("Foo").Filter("Prop <", -9223372036854775808) とすることでクエリできますが、うーん・・・。

Discussion