[MongoDB] 値無しはnullかundefinedか
2014年7月9日
検証バージョンは、MongoDB 2.4.3 と mongoose 3.8.1 です。
オプションなどで動作が変わるものもあるかもしれませんが、特に何も設定していません。
undefined で更新すると null になる
> db.sandboxes.insert({ foo: undefined }) { "_id" : ObjectId("53bd2e0d7e3d4816a9d41206"), "foo" : null }
まず、前提として undefined という値は入りません。
undefined で更新してもエラーにならず、null になっています。
null 条件で検索するとフィールド未定義の行もヒットする
> db.sandboxes.insert({}) > db.sandboxes.find({foo: null}) { "_id" : ObjectId("53bd2f837e3d4816a9d41207") }
「foo フィールドが null の行」を検索していますが、それが未定義な行も抽出されます。
「フィールド未定義」と書きましたが、マニュアル上は「not contained」(日本語だと「値無し」?)と表現されることが多いです。
ここではSQL脳に配慮して「行」と書いていますが、普通は「ドキュメント」と呼ばれます。
Refs) How do I query for fields that have null values?
定義/未定義を条件に含めたい場合は $exists を使います。
オブジェクトを評価する際、未定義は undefined である
> db.sandboxes.insert({foo:1, bar:2}) > doc = db.sandboxes.findOne({foo:1}) { "_id" : ObjectId("53bd35177e3d4816a9d41209"), "foo" : 1, "bar" : 2 } > doc.baz === null false > doc.baz === undefined true
えー。
mongoose では、ドキュメントオブジェクトがラップされて返されますが、普通に評価する限りは undefined です。(null で統一してくれるアクセサがあるかもしれないが、知らない or あまり使われてない)
mongoose でフィールドに default を設定しても既存データには反映されない
title: { type: String, default: '--' },
データ作成時にその値が初期値として入るだけで、既に存在する行には mongoose の抽出メソッドを使っても反映されません。
つまり、「値無し」の状態が null or undefined
1. フィールド追加前に保存されたドキュメントでは doc.foo === undefined
2. 一度 null/undefined で更新した場合は doc.foo === null
3. それに関わらず、MongoDB で find する場合は {foo:null}
という判定を全て考慮しなければならないことになります。
最初に考えておけ
これを放置しておくと、テンプレのレベルで
(doc.foo === null || doc.foo === undefined) ? 'None' : doc.foo
こういう感じのコードが蔓延するようになるので、どう結論を出すにせよ、早めに整理しておいた方が良いと思います。
RDB脳なら、フィールドを増減する度に migration する、なのかなぁ。