Podejście budowania kryterium składają się wszystkie identyfikatory dokumentu, a następnie wykonywania aktualizacji jest związany powodować potencjalne problemy. Kiedy przeglądasz listę dokumentów wysyłających operację aktualizacji z każdym dokumentem, w Mongoose masz ryzyko wysadzenia serwera, szczególnie gdy masz do czynienia z dużym zbiorem danych, ponieważ nie czekasz na zakończenie asynchronicznego połączenia przed przejściem do następnego iteracja. Będziesz zasadniczo budować "stos" nierozwiązanych operacji, dopóki nie spowoduje to problemu - Stackoverflow.
Weźmy na przykład zakładając miałeś tablicę identyfikatorów dokumentu, który chciał, aby zaktualizować dokument pasujący na polu statusu:
var processedIds = [
"57a0a96bd1c6ef24376477cd",
"57a052242acf5a06d4996537",
"57a052242acf5a06d4996538"
];
następnie do bardzo małych zbiorów danych można użyć metody forEach()
na tablica do iteracji i aktualizacji kolekcji:
processedIds.forEach(function(id)){
Model.update({"_id": id}, {"$set": {"status": "processed" }}, callback);
});
Powyższe jest w porządku dla małych zestawów danych. Jednak staje się to problemem, gdy masz do czynienia z tysiącami lub milionami dokumentów do zaktualizowania, ponieważ będziesz wykonywać powtarzające się wywołania serwerów asynchronicznego kodu w pętli.
Alternatywą byłoby użyć czegoś podobnego ASYNC za eachLimit
i iteracyjne nad tablicy wykonującego operację aktualizacji MongoDB dla każdej pozycji podczas wykonywania nie więcej niż x równoległych aktualizacjach tym samym czasie.
Najlepszym rozwiązaniem byłoby wykorzystanie zbiorczego API dla tego, który jest niezwykle skuteczny w przetwarzaniu aktualizacji luzem. Różnica w wydajności i wywoływanie operacji aktualizacji na każdym z wielu dokumentów polega na tym, że zamiast wysyłać żądania aktualizacji do serwera przy każdej iteracji, zbiorczy interfejs API wysyła żądania raz na każde 1000 żądań (w pakiecie).
Dla wersji Mongoose >=4.3.0
które wspierają MongoDB Server 3.2.x
, można użyć bulkWrite()
aktualizacji.Poniższy przykład pokazuje, jak można iść na ten temat:
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); }
Dla wersji Mongoose ~3.8.8
, ~3.8.22
, 4.x
które wspierają MongoDB Server >=2.6.x
, można użyć luzem API następująco
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
});
}
To jest dokładnie to, czego szukałem. Wielkie dzięki! –
Czy mógłbyś powiedzieć mi, jak różni się "bulkWrite" od 'insertMany'? –
Albo w jaki sposób 'collection.insert' różni się od' collection.bulkWrite'? Nie mogę znaleźć żadnej oficjalnej dokumentacji na temat tych rzeczy :(Reference: http://www.unknownerror.org/opensource/Automattic/mongoose/q/stackoverflow/16726330/mongoose-mongodb-batch-insert –