バージョン3以降対象
use <db_name>
db.auth("<user name>", "<password")
db.<collection name>.find()
db.<collection name>.getIndexes()
db.getCollectionNames()
db.foo.insert([{x:1}, {x:2}]) // {x:1}と{x:2}のドキュメントをfooに追加
db.foo.find({x:1}) // x == 1のドキュメントを検索
db.foo.insert({y:{z:1}}) // 内部ドキュメントのあるドキュメントを追加
db.foo.find({y: {z: 1}}) // y.z == 1のドキュメントを検索
検索条件の値としてリテラルを使うと一致検索になり、他にもクエリオプションを指定することができる。
db.foo.find({x: {$gt: 5}}) // x > 5となる全てのドキュメントを検索
db.foo.find({x: {$ne: 5}}) // x != 5となる全てのドキュメントを検索
SQLのselectのように、検索結果をフィルターするにはfindの第二引数でon/offの指定を行う。_id
は明示的に0を指定しないと消せない。
db.foo.find({x: {$ne: 5}}, {x:1, _id:0}) // 1:on, 0:off.
$exists:<boolean>
を使う。存在しないことを条件にする場合はfalseを指定する
db.foo.find({a: { $exists: true}})
db.foo.find({a: {$gte: x, $lte: y}})
配列に対するフィルタ条件に$slice
を指定することで、取り出す数を絞り込める
db.foo.insert({i:0, a:[1,2,3,4,5]})
db.foo.find({i:0}, {a: {$slice: 3}}) // [1,2,3]
db.foo.find({i:0}, {a: {$slice: -3}}) // [3,4,5]
db.<collection name>.remove({})
※ ドキュメントを全て消してもインデックスは残り続けるので、スキーマを変えて再投入した場合はnull値の重複としてユニーク制約に違反することがある。
db.<collection name>.drop()
※ dropではインデックスも全て消去される
getIndexes
などで見られる"name"
を指定して個別のインデックスを消去する
db.foo.dropIndex("<index name>")
db.<collection name>.dropIndexes()
db.foo.update({i:0}, {$set: {x:1}}, {upsert:true})
複数ドキュメントが見つかった場合は最初の一つがupdateされる。
デフォルトではマッチしたドキュメントのうち一つだけしかupdateできないので、{multi:true}
を指定する。
db.foo.update({i:0}, {$set: {x:1}}, {multi:true})
$
を使わない単純な入れ替え指定はmultiでは使えない
db.foo.update({i:0}, {$inc: {x:1}}) // x = x + 1
db.foo.update({i:0}, {$inc: {x:1, y:-1}}) // x = x + 1, y = y - 1
加算する値は任意の数値が使用可能。$inc
対象フィールドが存在しなかった場合は0を初期値として計算した新しいフィールドが挿入される。
ドキュメント内部のフィールド削除は$unset
を使用する。void 0
やnull
値をセットした場合はnull
が格納されてしまう。
db.foo.update({i:0}, {$unset: {x:""}}) // xを削除。""のところは何でもいい
db.foo.insert(i:0, {a:[1,2,3,4,5]})
db.foo.update({i:0}, {$push:{a:6}})
mongodbのunique indexはドキュメント内部での唯一性を保証しない。このため、配列要素の重複登録を防ぐには次のようにする。
db.foo.insert(i:0, {a:[1,2,3,4,5]})
db.foo.update({i:0, a:{$ne:5}}, {$push:{a:5}}) // 検索に失敗するので更新はされない
ただし、この方法ではドキュメント配列の場合に複雑な検索条件を書く必要が生じる。
別の方法としては、$addToSet
を使用してSetとして要素を登録するというものがある。
db.foo.insert(i:0, {a:[1,2,3,4,5]})
db.foo.update({i:0}, {$addToSet:{a:5}})
ここまでのいずれの方法も�unique制約違反とは異なりエラーを出さないので注意が必要。
クエリは内部ドキュメントと同じ方式で出来る。見つかった要素を更新する場合は$
で参照する
db.foo.insert({a:[1,2,3,4]})
db.foo.update({a:1}, {$set: {'a.$': 100}}) // [100,2,3,4]
db.foo.insert({x:[{i:1},{i:2},{i:3},{i:4}]})
db.foo.update({'x.i':1}, {$set: {'x.$.i': 100}}) // [{i:100},{i:2},{i:3},{i:4}]
$push
に$each
と$sort
を組み合わせる。ドキュメント配列とそれ以外で少し指定の仕方が異なる。
db.foo.insert({i:0, a:[1,2,3,4]})
db.foo.update({i:0}, {$push: {a: {$each: [2], $sort: 1}}}) // $sortで昇順を指定[1,2,2,3,4]
db.bar.insert({i:0, a:[ {x:1},{x:2},{x:3},{x:4}]})
db.bar.update({i:0}, {$push: {a: {$each: [{x:2}], $sort: {x:1}}} }) // [{"x":1},{"x":2},{"x":2},{"x":3},{"x":4}]
upsert
と$setOnInsert
を組み合わせる
db.foo.findAndModify({query: {i:0}, update: {$setOnInsert: {i: 0}}, upsert: true})
デフォルトの挙動では更新前の値が返り、クエリしたドキュメントが無かった場合はnullが返って来る。
クエリオプションでnew
をtrueにすることで、更新後の値をとることができる。
db.foo.findAndModify({query: {i:0}, update: {$setOnInsert: {i: 0}}, upsert: true, new: true})
bar
というフィールドが一致するグループの合計を取る
db.foo.aggregate({$group:{_id: "$bar", count: {$sum:1}}})
bar
とbuzz
が一致するグループの合計を取る
db.foo.aggregate({$group:{_id: {bar: "$bar", buzz: "$buzz"}, count: {$sum:1}}})
bar
の値がtrue
に等しいレコードで、buzz
によるGroup By + Count。
db.foo.aggregate({$match: {"bar": true}}, {$project: {buzz: 1}} , {$group:{_id: "$buzz", count: {$sum:1}}})
db.foo.insert({ a: 1, b:2, c: {d: "a"} })
db.foo.ensureIndex({i:1}) // 単一�インデックス
db.foo.ensureIndex({i:1, b:1}) // 複合インデックス
db.foo.ensureIndex({i:1, 'c.d':-1}) // 内部ドキュメントのフィールドは.区切りで指定
db.foo.ensureIndex({c:1}) // 内部ドキュメントそのものを指定するとその"全てのフィールドの組み合わせ"がインデックスされる
複合インデックスの1
や-1
はソートキーをインデックスする際の昇順・降順の指定となる。
for (var i = 0; i < 10000; ++i) { db.foo.insert({ i: i, j: -i}) }
db.foo.ensureIndex({i:1, j:-1})
db.foo.find().sort({i:1, j:-1}) // インデックス通りのソート
db.foo.find().sort({i:1, j:1}) // インデックスされた順番ではないため、FETCHによる外部ソートが発生する
配列フィールドに対するインデックスは内部ドキュメントのインデックスと同様に貼ることが出来る。
db.bar.insert({ i: 1, array:[1,2,3,4,5]})
db.bar.ensureIndex({array:1})
db.bar.find({array: 2}) // array要素に2を含むものを検索
db.bar.insert({ i: 1, array:[1,2,3,4,5]})
db.bar.ensureIndex({array:1})
db.bar.find({array: 2}) // arrayに対するindexが効いている
また、複合インデックスは先頭からマッチするフィールドについては単一インデックスとしての役割も兼ねる。これをindex prefixと言う。
db.foo.ensureInsex({a:1, b:1})
db.foo.find({a:0, b:1}) // 複合インデックスによるスキャン
db.foo.find({a:0}) // インデックスプリフィックスによるスキャン
db.foo.find({b:0}) // インデックスを使用しないスキャン
このため、次のようなprefixが被るようなインデックスを設定する必要性はない
db.foo.ensureInsex({a:1, b:1})
db.foo.ensureInsex({a:1}) // 既に上のインデックスでaはインデックス対象になっているため、冗長
参考: http://docs.mongodb.org/manual/core/index-compound/#compound-index-prefix
index作成のオプションに{unique: true}
を付ける。
db.foo.ensureIndex({i:1}, {unique:true})
db.foo.insert({i:0})
db.foo.insert({i:0}) // エラー
arrayに対するunique制約は、コレクション中の全ての配列要素でunique制約が満たされている必要がある。
db.foo.ensureIndex({a:1}, {unique:true})
db.foo.insert(a:[1,2,3])
db.foo.insert(a:[2]) // 要素が被っているのでエラー
db.foo.insert(a:[4,4]) // ただし、insertの時点で被っているのは許される(!)
- mongodbではインデックスされているフィールドがinsert時に指定されなかった場合は
null
値を挿入する。 この結果、unique制約がnull
に適用されることになるため、続けてフィールドを省略すると重複レコードとしてエラーが発生する。 - コレクション内でunique制約に矛盾が発生している状態で新たに
ensureIndex
でunique制約を追加しようとするとエラーが発生する
db.<collection>.<query>.explain("executionStats")
IXSCAN
が現れていればインデックスが効いている。COLLSCAN
が見えたらO(N)検索になっているのでヤバい。
inputStage
のindexName
で使用されたインデックスを調べられる。
totalDocsExamined
で検索したドキュメント数が表示される。
参考: http://docs.mongodb.org/manual/reference/explain-results/