[英]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.