在MongoDB中,更新單個doc的操作是原子性的。默認情況下,如果一個update操作更新多個doc,那么對每個doc的更新是原子性的,但是對整個update 操作而言,不是原子性的,可能存在前面的doc更新成功,而后面的doc更新失敗的情況。由於更新單個doc的操作是原子性的,如果兩個更新同時發生,那么一個更新操作會阻塞另外一個,doc的最終結果值是由時間靠后的更新操作決定的。
通過使用 $isolated option,能夠確保更新多個doc的寫操作是原子性的,任何查詢操作都會讀取到更新操作,直到該操作完成(成功或失敗)。
Prevents a write operation that affects multiple documents from yielding to other reads or writes once the first document is written. By using the $isolated option, you can ensure that no client sees the changes until the operation completes or errors out.
MongoDB在新增和更新數據的時候,不會實時寫入到Disk中,可能會丟失數據。
一,語法
默認情況下,update只會更新single doc,如果需要更新多個doc,必須顯式設置doc: multi:true。
db.collection.update( <query>, <update>, { upsert: <boolean>, multi: <boolean>, writeConcern: <document> } )
upsert:Optional. If set to true, creates a new document when no document matches the query criteria. The default value is false, which does not insert a new document when no match is found.
multi:Optional. If set to true, updates multiple documents that meet the query criteria. If set to false, updates one document. The default value is false.
二,更新示例
在users collection中有三個doc,插入代碼如下
user1={ name:"t1", age:21} user2={ name:"t2", age:22} user3={ name:"t3", age:23} db.users.insert([user1,user2,user3])
1,upsert option usage
upsert option的含義是,如果collection中存在匹配的doc,那么更新該doc;如果不匹配任何doc,那么插入一條新的doc。
使用update命令和 upsert選項,插入一條新的user,name=“t4”
db.users.update({name:"t4"},{name:"t4"},{upsert:true})
對新插入的user新增field:age=24,必須將doc的所有field都顯式指定。
db.users.update({age:24},{name:"t4",age:24})
如果在Update doc中,只包含age=24,那么將失去name field,例如
db.users.update({name:"t4"},{age:24})
2,multi option usage
在使用multi option更新多個doc之前,先考慮一個問題,如果把age的年紀都加1,那么在age加1時,保持其他field不變。這種情況需要用到$inc operator,用於將指定字段的值遞增,同時不會影響其他字段。
{ $inc: { <field1>: <amount1>, <field2>: <amount2>, ... } }
示例,將符合條件的User的age 加 1
db.users.update({age:{$lt:24}},{$inc:{age:1}},{multi:true})
3,為所有的user 增加字段
這種scenario需要用到$set operator,用於替換指定字段的值,或新增字段。
{ $set: { <field1>: <value1>, ... } }
The $set operator replaces the value of a field with the specified value. If the field does not exist, $set will add a new field with the specified value, provided that the new field does not violate a type constraint. If you specify a dotted path for a non-existent field, $set will create the embedded documents as needed to fulfill the dotted path to the field.
示例,為所有的user增加sex字段,默認值是femal。
db.users.update({},{$set:{sex:"femal"}},{multi:true})
三,原子更新multiple doc
在query filter中加入 $isolated:1,表示對於查詢到的所有doc,update操作將會在一個原子操作中完成。
db.users.update({$isolated:1},{$set:{sex:"femal"}},{multi:true})
四,更新doc的結構
1,將doc的sex field刪除
Step1,使用FindOne找到name=t4的User
t4=db.users.findOne({name:"t4"})
Step2,使用delete command 刪除sex field
delete t4.sex;
Step3,使用Updae 替換原來的doc
db.users.update({name:"t4"},t4);
step4,使用find 查看doc的數據更新
2,使用db.collection.replaceOne替換doc
db.collection.replaceOne( <filter>, <replacement>, { upsert: <boolean>, writeConcern: <document> } )
step1,使用findOne()查找一個doc
t4=db.users.findOne({name:"t4"})
step2,為doc增加一個sex field
t4.sex="femal"
step3,使用replaceOne函數替換doc
db.users.replaceOne({name:"t4"},t4)
3,使用$set對所有符合query filter的doc批量修改doc結構
db.users.update({age:{$lte:23,$gte:21}},{$set:{sex:"femal"}},{multi:true});
4,使用$unset對所有符合query filter的doc批量刪除doc的field
db.users.update({$and:[{age:{$lte:23}},{age:{$gte:21}}]},{$unset:{sex:"femal"}},{multi:true}) --or db.users.update({age:{$lte:23,$gte:21}},{$set:{sex:"femal"}},{multi:true});
參考doc: