LoginSignup
18
12

More than 3 years have passed since last update.

MongoDB の null, empty を整理する

Last updated at Posted at 2019-12-03

https://qiita.com/risou/items/d1d0b0173039d68ed81c$exists の挙動について触れたが、他のケースについてもまとめておく。

まず、以下のようなデータを想定する(前回と同じ)。

> db.items.find()
{ "_id" : ObjectId("5de50feab2e406088d483c44"), "name" : "item01", "color" : "red", "size" : "M" }
{ "_id" : ObjectId("5de51001b2e406088d483c45"), "name" : "item02", "color" : "blue", "size" : "S", "memo" : null }
{ "_id" : ObjectId("5de51012b2e406088d483c46"), "name" : "item03", "color" : "yellow", "size" : "L", "memo" : "" }
{ "_id" : ObjectId("5de51029b2e406088d483c47"), "name" : "item04", "color" : "green", "size" : "M", "memo" : "hoge" }

それぞれのドキュメントの memo は以下のようになる。

name memo
item01 (存在しない)
item02 null
item03 empty(空文字)
item04 "hoge"

memo が null のドキュメントを取得する

普通に条件に memo: null を追加すると以下のようになる。

> db.items.find({memo: null})
{ "_id" : ObjectId("5de50feab2e406088d483c44"), "name" : "item01", "color" : "red", "size" : "M" }
{ "_id" : ObjectId("5de51001b2e406088d483c45"), "name" : "item02", "color" : "blue", "size" : "S", "memo" : null }

null を指定すると 対象フィールドが存在しないドキュメント・対象フィールドの値が null のドキュメント の両方がとれる。

memo が empty のドキュメントを取得する

そのまま指定すると意図通りの挙動になる。

> db.items.find({memo: ""})
{ "_id" : ObjectId("5de51012b2e406088d483c46"), "name" : "item03", "color" : "yellow", "size" : "L", "memo" : "" }

ここまでの情報を整理すると以下のようになる。

name memo $exists: true null ""
item01 (存在しない) :x: :o: :x:
item02 null :o: :o: :x:
item03 empty(空文字) :o: :x: :o:
item04 "hoge" :o: :x: :x:

この情報を元に、それぞれを正確に抽出したい。

対象フィールドが存在しないドキュメントを抽出する

これは簡単で $exists: false を設定してあげれば良い。

> db.items.find({memo: {$exists: false}})
{ "_id" : ObjectId("5de50feab2e406088d483c44"), "name" : "item01", "color" : "red", "size" : "M" }

対象フィールドが null のドキュメントを抽出する

先に書いたように memo: null では対応できないので $and を使って条件を絞る必要がある。

> db.items.find({$and: [{memo: {$exists: true}}, {memo: null}]})
{ "_id" : ObjectId("5de51001b2e406088d483c45"), "name" : "item02", "color" : "blue", "size" : "S", "memo" : null }

対象フィールドが空のドキュメントを抽出する

これは先に書いたように memo: '' でいける。

> db.items.find({memo: ''})
{ "_id" : ObjectId("5de51012b2e406088d483c46"), "name" : "item03", "color" : "yellow", "size" : "L", "memo" : "" }

対象フィールドが null でも空でもないドキュメントを抽出する

Ruby の present? のような条件だ。
これも $and を使って実現できる。

> db.items.find({$and: [{memo: {$exists: true}}, {memo: {$ne: null}}, {memo: {$ne: ''}}]})
{ "_id" : ObjectId("5de51029b2e406088d483c47"), "name" : "item04", "color" : "green", "size" : "M", "memo" : "hoge" }

対象フィールドが存在しないか値が null か空のドキュメントを抽出する

こちらは Ruby の blank? のような条件。
先の条件の逆なので難しくない。

> db.items.find({$or: [{memo: null}, {memo: ''}]})
{ "_id" : ObjectId("5de50feab2e406088d483c44"), "name" : "item01", "color" : "red", "size" : "M" }
{ "_id" : ObjectId("5de51001b2e406088d483c45"), "name" : "item02", "color" : "blue", "size" : "S", "memo" : null }
{ "_id" : ObjectId("5de51012b2e406088d483c46"), "name" : "item03", "color" : "yellow", "size" : "L", "memo" : "" }

上で整理した $exists と null の挙動をきちんと把握すれば、あとは条件を組み合わせればできることがわかる。

18
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
12