2016-08-03 93 views
10

我甩開了MongoDB的一些記錄用貓鼬,將它們導入到另一個系統,然後我想所有這些文件processed設置狀態(文件屬性)正確的做法。什麼是更新MongoDB中多條記錄使用貓鼬

我能找到這個解決方案:Update multiple documents by id set. Mongoose

我在想,如果這是正確的做法,建立由所有文件ID的標準,然後進行更新。還請考慮到這將是許多文件的事實。

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

回答

12

建立由所有文件ID的標準,則在更新的方法,勢必導致潛在的問題。當你重複的文件發送,每個文檔的更新操作的列表,貓鼬您運行大型數據集處理上移動到下一個之前,因爲你不等待異步調用完成時,尤其是吹你的服務器的風險迭代。你將基本上建立一個未解決的操作「堆棧」,直到這會導致一個問題 - Stackoverflow。

舉個例子,假設你有文件ID數組,你想更新的狀態字段匹配的文件:

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

那麼對於非常小的數據集,你可以在使用forEach()方法該數組迭代它並更新您的集合:

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

上面的小數據集可以。但是,當您面對數千或數百萬個文檔進行更新時,這會成爲問題,因爲您將在循環內重複執行異步代碼的服務器調用。

另一種方法是使用像異步的eachLimit和迭代每個項目執行MongoDB的更新操作時,切勿進行比個並行更新的同時更在陣列上。


最好的方法是使用批量API來處理批量處理更新的效率。性能與調用更新操作在許多文檔中的每一個上的差別在於,每次迭代時,批量API不會將更新請求發送到服務器,而是每1000次請求(批量)發送一次請求。

對於貓鼬版本>=4.3.0支持MongoDB的服務器3.2.x,您可以使用bulkWrite()更新。下面的例子演示瞭如何去了解這一點:

var bulkUpdateCallback = function(err, r){ 
    console.log(r.matchedCount); 
    console.log(r.modifiedCount); 
} 
// Initialise the bulk operations array 
var 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 native node.js driver collection object 
     Model.collection.bulkWrite(bulkOps, { "ordered": true, w: 1 }, bulkUpdateCallback); 
     bulkUpdateOps = []; // re-initialize 
    } 
}) 

if (counter % 500 != 0) { Model.collection.bulkWrite(bulkOps, { "ordered": true, w: 1 }, bulkUpdateCallback); } 

對於貓鼬版本~3.8.8~3.8.224.x支持MongoDB的服務器>=2.6.x,可以按如下方式

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 
    }); 
} 
+1

這正是我一直在尋找。非常感謝! –

+0

你介意告訴我'bulkWrite'與'insertMany'有什麼不同? –

+0

或者'collection.insert'與'collection.bulkWrite'有什麼不同?我似乎無法找到這些東西的任何官方文檔:(參考:http://www.unknownerror.org/opensource/Automattic/mongoose/q/stackoverflow/16726330/mongoose-mongodb-batch-insert –

0

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

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

貓鼬上面的代碼等同於下面的代碼在MongoDB的

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