MongoDBの基本操作(その2)

前回の「MongoDB : 基本操作(その1)」の続き
更新処理updateを中心とした忘備録

更新updateコマンドの基本構文

db.collections.update({condition},{$set:{field1:value1,field2:value2,…}})

$setで、フィールドの値を設定(置き換える)する。
nameがtaroのjob.categoryengineerに変更

> db.persons.update({"name":"taro"},{$set:{ "job.category":"engineer"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find({"name":"taro"})
{ "_id" : ObjectId("55cedb7d2aae174a2362856e"), 
 "name" : "taro", "gender" : "m", "age" : 20, 
 "children" : [ "ichiro", "jiro", "saburo" ], 
 "job" : { "name" : "AAA co.", "category" : "engineer" } }

$incは、フィールドの数値を増分する。
nameがtaroのageを-5に設定する

> db.persons.update({"name":"taro"},{$inc:{ "age":-5}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find({"name":"taro"})
{ "_id" : ObjectId("55cedb7d2aae174a2362856e"), 
"name" : "taro", "gender" : "m", "age" : 15, 
"children" : [ "ichiro", "jiro", "saburo" ], 
"job" : { "name" : "AAA co.", "category" : "engineer" } }

$pushで、配列フィールドの値を追加する。フィールドが存在しない場合は、自動的にフィールドを追加する。注意点としては、同一要素があっても追加してしまう。重複を許可しない場合は、$addToSetを使う。

nameがtaroのchildrenフィールドに、配列要素oooを追加 (フィールドも新規追加)

> db.persons.update({"name":"ryo"},{"$push":{"children":"ooo"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
 
> db.persons.find({"name":"ryo"})
{ "_id" : ObjectId("55d16d9a11503fd020ff8ab1"), 
"name" : "ryo", "age" : 34, "gender" : "m", 
"job" : { "name" : "ZZZ co.", "category" : "operator" }, 
"children" : [ "ooo" ] }

$pushAllで、配列フィールドの値を複数同時に追加する。
nameがtaroのchildrenフィールドに配列要素pppとqqqを追加。

> db.persons.update({"name":"ryo"},{"$pushAll ":{"children":["ppp","qqq"]}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find({"name":"ryo"})
{ "_id" : ObjectId("55d16d9a11503fd020ff8ab1"), 
  "name" : "ryo", "age" : 34, "gender" : "m",
  "job" : { "name" : "ZZZ co.", "category" : "operator" },
  "children" : [ "ooo", "ppp", "qqq" ] }

$addToSetで、配列フィールドに値を追加するが、$pushと違うところは、重複を許可しない

> db.persons.update({"name":"ryo"},{"$addToSet":{"children":"ooo"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })

*既に値がある為、「"nModified" : 0」で更新されてない。

> db.persons.update({"name":"ryo"},{"$addToSet":{"children":"mmm"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.persons.find({name:"ryo"})
{ "_id" : ObjectId("55d16d9a11503fd020ff8ab1"),
  "name" : "ryo", "age" : 34, "gender" : "m",
  "job" : { "name" : "ZZZ co.", "category" : "operator" },
  "children" : [ "ooo", "ppp", "qqq", "mmm" ] }

$pullで、配列の要素を削除する。該当する要素が複数ある場合は、全て削除される。

> db.persons.update({"name":"ryo"},{"$pull":{"children":"ooo"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.persons.find({name:"ryo"})
{ "_id" : ObjectId("55d16d9a11503fd020ff8ab1"), 
  "name" : "ryo", "age" : 34, "gender" : "m", 
  "job" : { "name" : "ZZZ co.", "category" : "operator" }, 
  "children" : [ "ppp", "qqq", "mmm" ] }

$pullAllで、指定下複数の要素を削除する

> db.persons.update({"name":"ryo"},{"$pullAll":{"children":["ppp","qqq","mmm"]}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.persons.find({name:"ryo"})
{ "_id" : ObjectId("55d16d9a11503fd020ff8ab1"), 
"name" : "ryo", "age" : 34, "gender" : "m", 
"job" : { "name" : "ZZZ co.", "category" : "operator" }, "children" : [ ] }

$popで、配列の先頭(-1)または末端(1)の要素を削除する

children:["111","222","333"]の状態で、先頭と末端の要素を削除

> db.persons.update({"name":"ryo"},{"$pop":{"children":-1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.persons.find({name:"ryo"})
{ "_id" : ObjectId("55d16d9a11503fd020ff8ab1"), 
"name" : "ryo", "age" : 34, "gender" : "m", 
"job" : { "name" : "ZZZ co.", "category" : "operator" }, 
"children" : [ "222", "333" ] }
 
> db.persons.update({"name":"ryo"},{"$pop":{"children":1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.persons.find({name:"ryo"})
{ "_id" : ObjectId("55d16d9a11503fd020ff8ab1"), 
"name" : "ryo", "age" : 34, "gender" : "m", 
"job" : { "name" : "ZZZ co.", "category" : "operator" }, 
"children" : [ "222" ] }

$renameは、フィールド名を変更する。
nameがtaroのageをage2に変更する

> db.persons.update({"name":"taro"},{$rename:{ "age":"age2"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.persons.find({"name":"taro"})
{ "_id" : ObjectId("55cedb7d2aae174a2362856e"), 
"name" : "taro", "gender" : "m", 
"children" : [ "ichiro", "jiro", "saburo" ], 
"job" : { "name" : "AAA co.", "category" : "engineer" }, "age2" : 15 }

$unsetは、フィールドを削除する。
nameがtaroのage2フィールドを削除する

※フィールドの値を空にするのではなく、フィールドそのものを削除する。
この時指定する値(下記例では””)はなんでも良い。

> db.persons.update({"name":"taro"},{$unset:{ "age2":""}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.persons.find({"name":"taro"})
{ "_id" : ObjectId("55cedb7d2aae174a2362856e"), 
"name" : "taro", "gender" : "m", 
"children" : [ "ichiro", "jiro", "saburo" ], 
"job" : { "name" : "AAA co.", "category" : "engineer" } }

upsert:trueオプションでフィールドを追加する。

nameがtaroのドキュメントに「age=25」を追加する
$upsertオプションは、無ければ追加、あれば更新するオプションである。

> db.persons.update({"name":"taro"},{$set:{"age":25}},{"upsert":true})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.persons.find({"name":"taro"})
{ "_id" : ObjectId("55cedb7d2aae174a2362856e"), 
"name" : "taro", "gender" : "m", 
"children" : [ "ichiro", "jiro", "saburo" ], 
"job" : { "name" : "AAA co.", "category" : "engineer" }, "age" : 25 }

フィールドが存在する状態でupsert:trueで更新すると、フィールド値が更新される。
動作としてはupsert:falseと変わらない

> db.persons.update({"name":"taro"},{$set:{"age":30}},{"upsert":true})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

> db.persons.find({"name":"taro"})
{ "_id" : ObjectId("55cedb7d2aae174a2362856e"), 
"name" : "taro", "gender" : "m", 
"children" : [ "ichiro", "jiro", "saburo" ], 
"job" : { "name" : "AAA co.", "category" : "engineer" }, "age" : 30 }

multi:trueオプションで、条件に該当するすべてのドキュメントを更新する。
※デフォルトでは、multi:falseであり、最初にヒットしたドキュメントだけ更新される。
SQLと違う振る舞いである。multi:trueにすることにより、SQLと同じ振る舞いになる。

以下は、会社名をAAA co.からXXX co.に変更する。AAA co.が複数レコードあるので、multi:trueで該当する全ドキュメントを更新する。

> db.persons.update({"job.name":"AAA co."},{$set:{"job.name":"XXX co."}},{"multi":true})
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })

> db.persons.find({"job.name":"XXX co."})
{ "_id" : ObjectId("55cedb7d2aae174a2362856e"), 
"name" : "taro", "gender" : "m", 
"children" : [ "ichiro", "jiro", "saburo" ], 
"job" : { "name" : "XXX co.", "category" : "engineer" }, "age" : 30 }
{ "_id" : ObjectId("55cedb7d2aae174a2362856f"), 
"name" : "ken", "gender" : "m", "age" : 30, 
"job" : { "name" : "XXX co.", "category" : "engineer" } }