アップデート

Based on v72 (2010-11-14更新) - オリジナル

MongoDBは、ドキュメント全体を入れ替える通常のアップデートと、アトミックでin-place(その場で)のアップデートをサポートします。

update()

update() は、与えられた条件にマッチするドキュメント全体を新しいオブジェクトで置き換えます。一部の項目だけ更新したい場合には、下記のmodifierを使います。

これがMongoDBの update() のシンタックスです。

db.collection.update( criteria, objNew, upsert, multi )

引数:

  • criteria - アップデートするレコードを選択するためのクエリー
  • objNew - 対象のオブジェクトを、アップデートするオブジェクト、または $オペレータ($incなど)
  • upsert - レコードが存在しない場合にインサートするかどうか
  • multi - criteria にマッチするオブジェクトすべてをアップデートするかどうか
もしSQLの経験がある場合、デフォルトでは update()は最初にマッチしたオブジェクトにのみしか更新しないことを理解してください。すべてのマッチするオブジェクトを更新したい場合には、 multi フラグを使ってください。

mongoシェルで、 save()

mongoシェル 上のsave()コマンドは、一つのオブジェクトをupsertするための簡単なシンタックスです。

// x はJSONスタイルのオブジェクト
db.mycollection.save(x); // 存在していたら update、 してなかったらinsert

save() は、x が _id フィールドを持っていたら、upsert をし、持っていなければ、 insert をします。そのため、通常、upsertを明示的にリクエストする必要なはく、単に save() を使ってください。

upsert は、 "存在していたら update。していなかったら、 insert" という意味です。

myColl.update( { _id: X }, { _id: X, name: "Joe", age: 20 }, true );

modifier オペレーション

modifier オペレーションは、既存の値をアップデートをとても効率的に行います。たとえば、数値のインクリメントなどに向いています。

通常の方法だと、このようになります。

var j=myColl.findOne( { name: "Joe" } ); 
j.n++; 
myColl.save(j); 

modifierアップデートは、クエリーをしオブジェクトを返す、という部分の遅延を省くことができることが利点です。また、modifierアップデートは、 アトミックな オペレーションで、ネットワーク帯域も少ししか使いません。

このアトミックなアップデートを実行するためには、専用のアップデートオペレータのどれか(必ず'$'で始まります)を指定します。

db.people.update( { name:"Joe" }, { $inc: { n : 1 } } );

これは、 'name'が'joe'である最初のドキュメント探し、 'n' をインクリメントする、ということなります。

この例ではありませんが、ほとんどのmodifierオペレータで、複数のfield/valueのペアを使うことができます。たとえば、次の操作は、xを1に、yを2にセットします。

{ $set : { x : 1 , y : 2 } }

また、複数のオペレータも可です。

{ $set : { x : 1 }, $inc : { y : 1 } }

$inc

{ $inc : { field : value } }

field が存在している場合、 fieldvalue インクリメントします。存在しない場合、 fieldvalue をセットします。

$set

{ $set : { field : value } }

fieldvalue をセットします。 $set ではすべての型がサポートされています。

$unset

{ $unset : { field : 1} }

fieldを削除します。 v1.3以上の機能です。

$push

{ $push : { field : value } }

field がarrayの場合、 valuefield に追加します。 field が存在しない場合、 field に [value] をセットします。 field は存在するが、arrayではない場合、 errorが発生します。

$pushAll

{ $pushAll : { field : value_array } }

field が存在するarrayの場合、 value_array を一つずつ、 field に追加します。 field が存在しない場合、 field に、 array value_array をセットします。 field は存在するが、arrayではない場合、 errorが発生します。

$addToSet

{ $addToSet : { field : value } }

field}}が配列型でかつ、valueが存在しない場合に追加します。 {{field が存在しない場合には、 value を持つ配列をセットします。 {field}} が存在するが、配列型でない場合、エラーになります。

複数の値を追加。

{ $addToSet : { a : { $each : [ 3 , 5 , 6 ] } } }

$pop

{ $pop : { field : 1 } }

arrayの最後の要素を削除します(バージョン1.1で追加)。

{ $pop : { field : -1 } }

arrayの最初の要素を削除します(バージョン1.1で追加)。

$pull

{ $pull : { field : _value } }

field からすべての value を削除。 field が存在しているが、arrayでない場合、エラーになります。

完全一致する value に加え、いくつかの書式があります。

{ $pull : { field : {field2: value} } } field2 がマッチする値を持つ要素を削除
{ $pull : { field : {$gt: 3} } } 3以上の要素を削除
{ $pull : { field : {<match-criteria>} } } match-criteria に該当する要素を削除

$pullAll

{ $pullAll : { field : value_array } }

field がarrayの場合、 value_array の中の値をそれぞれ field からすべて削除します。 field が存在しているが、arrayではない場合、エラーになります。

$rename

バージョン 1.7.2 以上。

{ $rename : { old_field_name : new_field_name } }

フィールド名を 'old_field_name' から 'new_field_name' へ変更します。 配列内は 'old_field_name' の対象ではありません。

$ ポジションオペレータ

バージョン 1.3.4 以上

$ オペレータは(それ自身で)、 "クエリでマッチしたアイテムの配列の場所" を意味します。 配列の要素を探し、それを操作する場合に使えます。 たとえば、

> t.find()
{ "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC",
"comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] }

> t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true )

> t.find()
{ "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC",
"comments" : [ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }

現在のところ、 $ オペレータは、 クエリでマッチしたアイテムの 最初 のものにのみ適用されます。たとえば、

> t.find();
{ "_id" : ObjectId("4b9e4a1fc583fa1c76198319"), "x" : [ 1, 2, 3, 2 ] }
> t.update({x: 2}, {$inc: {"x.$": 1}}, false, true);
> t.find();
{ "_id" : ObjectId("4b9e4a1fc583fa1c76198319"), "x" : [ 1, 3, 3, 2 ] }

ポジションオペレータは、 upsert と組み合わせることはできません。配列の要素とマッチする必要があるからです。もし、処理の結果、インサートになった場合、 "$" がそのままフィールド名として使われてしまうからです。

"$unset" を "array.$" と一緒に使うと、配列のアイテムが 削除されるのではなく、 null になってしまいます。"{$pull:{x:null}}" とアップデートすることで、すべての null を削除できます。

> t.insert({x: [1,2,3,4,3,2,3,4]})
> t.find()
{ "_id" : ObjectId("4bde2ad3755d00000000710e"), "x" : [ 1, 2, 3, 4, 3, 2, 3, 4 ] }
> t.update({x:3}, {$unset:{"x.$":1}})
> t.find()
{ "_id" : ObjectId("4bde2ad3755d00000000710e"), "x" : [ 1, 2, null, 4, 3, 2, 3, 4 ] }

$pull can now do much of this so this example is now mostly historical (depending on your version).

現在では、 $pull で同じことができるので、この例は歴史的な物になっています(バージョンによります)。

upsert と modifier

modifierオペレーションと一緒にupsertを使うことができます。このケースでは、modifier は criteria でアップデート対象のものに適用されます。そしてinsertされたオブジェクトを返します。次に、 upsertで {name:"Joe",x:1,y:1} を insertする例を示します。

db.people.update( { name:"Joe" }, { $inc: { x:1, y:1 } }, true );

いくつかの制限があります。modifierは、 _id フィールドを参照できません。またupdate内の2つ以上のmodifierが同じフィールドを参照できません。たとえば、次の例はできません。

db.people.update( { name:"Joe" }, { $inc: { x: 1 }, $set: { x: 5 } } );

ユニークな値を追加

存在していない場合にだけ、arrayに値を追加するには、

バージョン1.3.3から、次のようにできます。

update( {_id:'joe'},{"$addToSet": { tags : "baseball" } } );

それより古いバージョンでは、 $ne : <value> をクエリーに加えてください。

update( {_id:'joe', tags: {"$ne": "baseball"}}, 
{"$push": { tags : "baseball" } } ); 

updateリクエストの結果の確認

ここまでで紹介したように、 upsert以外のアップデートは存在するオブジェクトをupdateする場合とupdateしない場合があります。upsertは、存在するオブジェクトを更新するか、新しいオブジェクトを追加します。クライアントは、 getlasterror コマンド( db.runCommand( "getlasterror" ) )を続けて実行することで、そのコネクションで起こった直近のコマンドがオブジェクトをアップデートしたかどうかを判断することができます。 getlasterror コマンドの結果が、 updatedExisting を含んでいる場合、 このコネクションでの最後のコマンドは、updateリクエストだった、ということになります。 また updatedExisting がtrueの場合、updateリクエストは既存のオブジェクトをupdateしたことになり、 updatedExisting がfalseの場合には、どのオブジェクトもアップデートされなかったことになります。
upserted フィールドは、インサートが実行されたとき、新しい _id を含みます(1.5.4から)。

注意

オブジェクトの padding について

MongoDBで、オブジェクトを更新する場合、オブジェクトのサイズが増えない場合には、更新はin-place(同じ場所)で実行されます。これは、コレクションがたくさんのインデックスを持っている場合、insertのパフォーマンスのために有効です。

Mongoは、コレクション内のオブジェクトが増えているかどうかを学習し、もし増える傾向にある場合、今後のデータの移動を防ぐため、予備の空間(padding)を追加します。この統計は、各コレクション毎に行われます。

ブロック

バージョン1.5.2から、大量のデータの更新を安全にできるように、複数のアップデートが同時に起こることがあります。複数のアップデートを、独立して(つまり、処理が行われている間、他の書き込みを許さない)行ないたい場合には、 $atomic フラグを以下のように使います。

db.students.update({score: {$gt: 60}, $atomic: true}, {$set: {pass: true}})

参照


Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

IF YOU HAVE A QUESTION, POST IT TO THE USER GROUP.

These pages are fine for comments, but for questions, your best bet will always be the MongoDB User Group.

blog comments powered by Disqus