簡體   English   中英

使用 Mongoose 更新 MongoDB 中的許多記錄的正確方法是什么

[英]What is the right approach to update many records in MongoDB using Mongoose

我正在使用 Mongoose 從 MongoDB 中提取一些記錄,將它們導入另一個系統,然后我想為所有這些要processed文檔設置狀態(文檔屬性)。

我可以找到這個解決方案: 通過 id 集更新多個文檔。 貓鼬

我想知道這是否是正確的方法,建立一個由所有文檔 ID 組成的標准,然后執行更新。 還請考慮一個事實,即它將是許多文件。

(更新查詢的限制是什么?在任何地方都找不到。官方文檔: http : //mongoosejs.com/docs/2.7.x/docs/updating-documents.html

建立一個由所有文檔 id 組成的標准然后執行更新的方法必然會導致潛在的問題。 當您對每個文檔發送更新操作的文檔列表進行迭代時,在 Mongoose 中,您會冒着炸毀服務器的風險,尤其是在處理大型數據集時,因為您沒有等待異步調用完成后再繼續下一個迭代。 您將基本上構建一個未解決操作的“堆棧”,直到這導致問題 - Stackoverflow。

舉個例子,假設你有一個文檔 id 數組,你想更新 status 字段上的匹配文檔:

const processedIds = [
  "57a0a96bd1c6ef24376477cd",
  "57a052242acf5a06d4996537",
  "57a052242acf5a06d4996538"
];

您可以在其中使用updateMany()方法

Model.updateMany(
  { _id: { $in: processedIds } }, 
  { $set: { status: "processed" } }, 
  callback
);

或者對於非常小的數據集,您可以在數組上使用forEach()方法來迭代它並更新您的集合:

processedIds.forEach(function(id)){
  Model.update({ _id: id}, { $set: { status: "processed" } }, callback);
});

以上對於小數據集是可以的。 但是,當您面臨數千或數百萬個要更新的文檔時,這就會成為一個問題,因為您將在循環中重復服務器調用異步代碼。

為了克服這個問題,請使用 async 的eachLimit類的eachLimit並迭代數組,為每個項目執行 MongoDB 更新操作,同時永遠不會執行超過 x 個並行更新。


最好的方法是為此使用批量 API,這在處理批量更新時非常有效。 性能與對眾多文檔中的每一個調用更新操作的區別在於,批量 API 不是在每次迭代時向服務器發送更新請求,而是每 1000 個請求(批處理)發送一次請求。

對於支持 MongoDB Server 3.2.x Mongoose 版本>=4.3.0 ,您可以使用bulkWrite()進行更新。 以下示例顯示了如何進行此操作:

const bulkUpdateCallback = function(err, r){
  console.log(r.matchedCount);
  console.log(r.modifiedCount);
}

// Initialize the bulk operations array
const bulkUpdateOps = [], counter = 0;

processedIds.forEach(function (id) {
  bulkUpdateOps.push({
    updateOne: {
      filter: { _id: id },
      update: { $set: { status: "processed" } }
    }
  });
  counter++;

  if (counter % 500 == 0) {
    // Get the underlying collection via the Node.js driver collection object
    Model.collection.bulkWrite(bulkUpdateOps, { ordered: true, w: 1 }, bulkUpdateCallback);
    bulkUpdateOps = []; // re-initialize
  }
})

// Flush any remaining bulk ops
if (counter % 500 != 0) {
  Model.collection.bulkWrite(bulkOps, { ordered: true, w: 1 }, bulkUpdateCallback);
}

對於支持 MongoDB Server >=2.6.x Mongoose 版本~3.8.8 , ~3.8.22 , 4.x ,您可以使用 Bulk API 如下

var bulk = Model.collection.initializeOrderedBulkOp(),
    counter = 0;

processedIds.forEach(function(id) {
    bulk.find({ "_id": id }).updateOne({ 
        "$set": { "status": "processed" }
    });

    counter++;
    if (counter % 500 == 0) {
        bulk.execute(function(err, r) {
           // do something with the result
           bulk = Model.collection.initializeOrderedBulkOp();
           counter = 0;
        });
    }
});

// Catch any docs in the queue under or over the 500's
if (counter > 0) {
    bulk.execute(function(err,result) {
       // do something with the result here
    });
}

您可以在更新查詢中使用{multi: true}選項進行批量更新。

示例

employees.update({ _id: { $gt: 3 } },{$inc: { sortOrder: -1 }},{'multi':true});

上面mongoose中的代碼等價於下面mongodb中的代碼:

db.employees.updateMany({ _id: { $gt: 3 } },{$inc: { sortOrder: -1 }});

要更新許多記錄, $in是我所知的最佳選擇。

db.collectionName.updateMany(
{
    _id:
        {
            $in:
                [
                    ObjectId("your object id"),
                    ObjectId("your object id")

                ]
        }
},
{
    $inc: { quantity: 100 }

})

我想再補充一點,你可以使用$in來獲取多個文檔

db.collectionName.find(
        {
            _id:
                {
                    $in:
                        [
                            ObjectId("your object id"),
                            ObjectId("your object id")

                        ]
                }
        })

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM