mongoDB 方法 -- 更新文檔 update


1. db.collection.update(query, update, options)

1.1 作用:

  修改集合中的一個或多個文檔,根據更新參數,該方法可以修改一個或多個文檔中的特定字段的值,或完全替換現有文檔 。

1.2 語法:

db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>        // Available starting in MongoDB 4.2
   }
)

1.3 參數說明

范圍 類型 描述
query document 使用查詢運算符指定條件。和find()方法,一樣的查詢條件
update 文檔或管道 要修改的內容,以下三者之一。1. 更新操作符表達式的文檔(json對象);2.替換的文檔( : 對);3.聚合管道僅,包含的聚合階段:$addFields及其別名$set,$project及其別名$unset,$replaceRoot及其別名$replaceWith。
upsert 布爾值 可選的。如果設置為true,則在沒有文檔符合查詢條件時會創建一個新文檔。默認值為 false,在找不到匹配項時,不插入文檔。
multi 布爾值 可選。如果設置為true,則更新滿足query條件的多個文檔。如果設置為false,則更新一個文檔。默認值為false
writeConcern document 可選, MongoDB寫入安全機制,如果在事務中運行,請不要為操作明確設置writeConcern
collation document 可選, 允許用戶為字符串比較指定特定於語言的規則,例如字母大寫和重音符號的規則
arrayFilters array of document 可選。過濾文檔數組,在更新數組字段時,用於確定要進行更新的數組元素。
hint Document or string 可選的。一個文檔或字符串,它指定支持查詢謂詞的索引。該選項可以是索引說明文檔(json),或索引名稱字符串。如果指定的索引不存在,則操作錯誤。

1.4 行為表現

#    1. 在分片集合上使用 multi: false, 匹配條件必須准確匹配 _id 字段,或指定單一的分片(如,通過包含 shard key)
#    2. 當db.collection.update()執行更新操作(而不是文檔替換操作)時, db.collection.update()可以針對多個分片
#    3. 從MongoDB 4.2開始,替換文檔操作首先嘗試使用查詢過濾條件來針對單個分片。如果無法通過查詢過濾條件定位到單個分片,則它將嘗試以替換文檔定位。
#    4. 分片集合上的操作(更新文檔,替換文檔(v4.2之后)),db.collection.update()使用 upsert:true,在filter中必須包含完整的分片鍵shard key
#        但是,從版本4.4開始,分片集合中的文檔可能會 缺少分片鍵字段。要定位缺少分片鍵的文檔,可以將null 做相等條件匹配,並與另一個過濾條件(例如_id字段)結合使用,如:{ _id: <value>, <shardkeyfield>: null } // _id of the document missing shard key
#    5.從MongoDB 4.2開始,你可以更新文檔的shard key值,除非shard key字段是不可變的_id字段。在MongoDB 4.2之前,一個文檔的shard key字段值是不可變的。
#          更新存在的shard key:你必須運行在 mongos 上,不能直接在分片上執行操作。必須在事務中執行或作為可重試的方式寫入。必須指定multi: false。查詢條件必須包含一個 使用完整shard key的相等條件匹配(<shardKey>: keyValue)
#          設置不存在的shard key: 你必須運行在 mongos 上,不能直接在分片上執行操作。如果設置成 null, 可以指定 multi: true,且如果  upsert: true ,則在匹配條件中需有 shard key 的相等條件。
#                                               如果設置成 非null , 必須在事務中執行或作為可重試的方式寫入,必須指定multi: false。  如果  upsert: true, 或者 使用替換文檔且設置值為另一個分片的shard key,則在匹配條件中需有 shard key 的相等條件             

1.5 例子

##准備數據
db.books.remove({});

db.books.insertMany([
  {
    "_id" : 1,
    "item" : "TBD",
    "stock" : 0,
    "info" : { "publisher" : "1111", "pages" : 430 },
    "tags" : [ "technology", "computer" ],
    "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
    "reorder" : false
   },
   {
    "_id" : 2,
    "item" : "XYZ123",
    "stock" : 15,
    "info" : { "publisher" : "5555", "pages" : 150 },
    "tags" : [ ],
    "ratings" : [ { "by" : "xyz", "rating" : 5 } ],
    "reorder" : false
   }
]);

###1. 使用更新運算符
## 如果更新內容使用了運算表達式,那就必須全部是運算符表達式。運用了運算符表達式的更新操作,只更新update()方法中出現的字段的值(增量更新)
## 以下出現了 $inc, $set操作符,且只更新 _id = 1的文檔中的 stock, item, info.publisher, tags ratings[1],而 reorder 未更新

db.books.update(
   { _id: 1 },   #條件
   {
     $inc: { stock: 5 },  # 增加: stock + 5
     $set: {              # 設置值,如果某個字段不存在,則會添加進去
       item: "ABC123",
       "info.publisher": "2222",
       tags: [ "software" ],
       "ratings.1": { by: "xyz", rating: 3 }   # ratings.1,設置 ratings[1]
     }
   }
)

## $push 更新操作符  ratings 數組 添加數據
db.books.update(
   { _id: 2 },
   {
     $push: { ratings: { "by" : "jkl", "rating" : 2 } }
   }
)

## $unset 操作符,刪除 tags 字段
db.books.update( { _id: 1 }, { $unset: { tags: 1 } } )


### 2. update 只使用 field:value 鍵值對
## 使用 鍵值對 的 更新內容,會完全替換匹配到的文檔,除了 _id,即 全量更新
## 使用鍵值對,不能更新多個文檔

## 更新后, 該文檔內容: _id =2 , item = "XYZ123", info={ publisher: "2255", pages: 150 }, tags = [ "baking", "cooking" ]
## ratings 和 reorder 不存在了
db.books.update(
   { _id: 2 },
   {
     item: "XYZ123",
     stock: 10,
     info: { publisher: "2255", pages: 150 },
     tags: [ "baking", "cooking" ]
   }
)

### 3. 使用管道 更新
## 從MongoDB 4.2開始,該db.collection.update()方法可以接受一個聚合管道數組 [ <stage1>, <stage2>, ... ]。管道可以包括以下階段:
##$addFields 及其別名 $set
##$project 及其別名 $unset
##$replaceRoot及其別名$replaceWith。
## 使用聚合管道可以實現更具表達力的更新語句,例如根據當前字段值表達條件更新,或使用另一個字段的值更新一個字段。

## 准備數據
db.members.insertMany([
   { "_id" : 1, "member" : "abc123", "status" : "A", "points" : 2, "misc1" : "note to self: confirm status", "misc2" : "Need to activate", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
   { "_id" : 2, "member" : "xyz123", "status" : "A", "points" : 60, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
])

#使用文檔中其他字段的值修改字段
#1、$set 階段: 添加新comments字段,修改lastUpdate字段的值。 comments的值為 misc1 和 misc2 字段組成的數組。 lastUpdate 的值 設為 聚合變量NOW的值  使用聚合變量方式:。$$ + 變量名
#2、$unset階段: 刪除集合中所有文檔的misc1和misc2字段
db.members.update(
   { },
   [
      { $set: { status: "Modified", comments: [ "$misc1", "$misc2" ], lastUpdate: "$$NOW" } },
      { $unset: [ "misc1", "misc2" ] }
   ],
   { multi: true }
)

## 准備數據
db.students3.insert([
   { "_id" : 1, "tests" : [ 95, 92, 90 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
   { "_id" : 2, "tests" : [ 94, 88, 90 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
   { "_id" : 3, "tests" : [ 70, 75, 82 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
]);


##使用聚合管道,可以使用計算出的平均成績和字母成績來更新文檔。
db.students3.update(
   { },
   [
     { $set: { average : { $trunc: [ { $avg: "$tests" }, 0 ] }, lastUpdate: "$$NOW" } },
     { $set: { grade: { $switch: {
                           branches: [
                               { case: { $gte: [ "$average", 90 ] }, then: "A" },
                               { case: { $gte: [ "$average", 80 ] }, then: "B" },
                               { case: { $gte: [ "$average", 70 ] }, then: "C" },
                               { case: { $gte: [ "$average", 60 ] }, then: "D" }
                           ],
                           default: "F"
     } } } }
   ],
   { multi: true }
)

##更新后
{ "_id" : 1, "tests" : [ 95, 92, 90 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 92, "grade" : "A" }
{ "_id" : 2, "tests" : [ 94, 88, 90 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 90, "grade" : "A" }
{ "_id" : 3, "tests" : [ 70, 75, 82 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 75, "grade" : "C" }

2. db.collection.updateOne(filter, update, options)

2.1 作用:

根據篩選條件更新集合中匹配到的第一個文檔

2.2 語法:

db.collection.updateOne(
   <filter>,
   <update>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>        // Available starting in MongoDB 4.2.1
   }
)

2.3 參數說明

參考 update() 方法,但 <update> 更新內容,不能是鍵值對形式(即不能替換文檔),只能是更新操作符表達式 和 聚合管道 中的一種

2.4 行為表現

# 在分片集合上更新 ,如果 upsert: true,需要在filter中必須指定完整的分片鍵shard key。如果不指定 upsert: true,必須 精准匹配 _id 字段 或者 指定一個分片(如,通過在匹配條件中加入 shard key)
#  不兼容 db.collection.explain()
# 其他 參考 update() 方法行為表現的 第 4 、5 條

2.5 例子

# 部分例子可參考 update() 方法,除替換文檔

##准備數據
db.students.insert([
   { "_id" : 1, "grades" : [ 95, 92, 90 ] },
   { "_id" : 2, "grades" : [ 98, 100, 102 ] },
   { "_id" : 3, "grades" : [ 95, 110, 100 ] }
])

# 使用 arrayFilters 和 位置操作符 $[<identifier>] 
# 要修改grade數組中的所有元素,條件是 元素大於或等於100
db.students.updateOne(
   { grades: { $gte: 100 } },
   { $set: { "grades.$[element]" : 100 } },
   { arrayFilters: [ { "element": { $gte: 100 } } ] }
)

# 結果 更新單個文檔
{ "_id" : 1, "grades" : [ 95, 92, 90 ] }
{ "_id" : 2, "grades" : [ 98, 100, 100 ] }  # 修改
{ "_id" : 3, "grades" : [ 95, 110, 100 ] }


##准備數據
db.students2.insert([
   {
      "_id" : 1,
      "grades" : [
         { "grade" : 80, "mean" : 75, "std" : 6 },
         { "grade" : 85, "mean" : 90, "std" : 4 },
         { "grade" : 85, "mean" : 85, "std" : 6 }
      ]
   },
   {
      "_id" : 2,
      "grades" : [
         { "grade" : 90, "mean" : 75, "std" : 6 },
         { "grade" : 87, "mean" : 90, "std" : 3 },
         { "grade" : 85, "mean" : 85, "std" : 4 }
      ]
   }
])

#使用 arrayFilters 和 位置操作符 $[<identifier>] 
# 修改grades 數組中的所有 對象的mean,條件是該對象的grade 大於等於 85
db.students2.updateOne(
   { },
   { $set: { "grades.$[elem].mean" : 100 } },
   { arrayFilters: [ { "elem.grade": { $gte: 85 } } ] }
)

# 結果
{
   "_id" : 1,
   "grades" : [
      { "grade" : 80, "mean" : 75, "std" : 6 },
      { "grade" : 85, "mean" : 100, "std" : 4 }, # 修改
      { "grade" : 85, "mean" : 100, "std" : 6 } # 修改
    ]
}
{
   "_id" : 2,
   "grades" : [
      { "grade" : 90, "mean" : 75, "std" : 6 },
      { "grade" : 87, "mean" : 90, "std" : 3 },
      { "grade" : 85, "mean" : 85, "std" : 4 }
   ]
}

3、 db.collection.updateMany(filter, update, options)

3.1 作用:

更新集合中匹配到的所有文檔

3.2 語法:

db.collection.updateMany(
   <filter>,
   <update>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>        // Available starting in MongoDB 4.2.1
   }
)

3.3 參數說明

 參考 update() 方法,但 <update> 更新內容,不能是鍵值對形式(即不能替換文檔),只能是更新操作符表達式 和 聚合管道 中的一種

3.4 行為說明
不兼容 db.collection.explain()
參考 update()
3.5 例子

參考 update(), updateOne()

update() , updateOne() , updateMany() 總體上的用法是一致的。區別是update()包含了 updateOne() updateMany() 的功能,且還有替換文檔的功能

官網詳情:
https://docs.mongodb.com/manual/reference/method/db.collection.update/
https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/
https://docs.mongodb.com/manual/reference/method/db.collection.updateMany/

查詢操作符:https://docs.mongodb.com/manual/reference/operator/query/
更新操作符:https://docs.mongodb.com/manual/reference/operator/update/
管道操作符:https://docs.mongodb.com/manual/reference/operator/aggregation/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM