W przypadku stosunkowo małych danych można to osiągnąć, iterując kolekcję za pomocą snapshot
z kursorem forEach()
metody i aktualizowania każdego dokumentu w następujący sposób:
db.wholesalers.find({
"brands": { "$exists": true, "$type": 4 }
}).snapshot().forEach(function(doc){
db.wholesalers.updateOne(
{ "_id": doc._id },
{ "$set": { "brandsNetherlands": doc.brands } }
);
});
Chociaż jest to optymalne dla małych kolekcji, wydajność w przypadku dużych kolekcji jest znacznie zmniejszona, ponieważ pętla przez duży zestaw danych i wysyłanie każdej operacji aktualizacji na żądanie do serwera wiąże się z karą obliczeniową.
Bulk()
Z pomocą przychodzi interfejs API, który znacznie poprawia wydajność, ponieważ operacje zapisu są wysyłane na serwer tylko raz zbiorczo. Wydajność jest osiągana, ponieważ metoda nie wysyła każdego żądania zapisu do serwera (jak w przypadku bieżącej instrukcji aktualizacji w forEach()
pętla), ale tylko raz na 1000 żądań, dzięki czemu aktualizacje są wydajniejsze i szybsze niż obecnie.
Używając tej samej koncepcji powyżej z forEach()
pętla do tworzenia partii, możemy zbiorczo zaktualizować kolekcję w następujący sposób.
W tej demonstracji Bulk()
API dostępne w wersjach MongoDB >= 2.6 and < 3.2
używa initializeUnorderedBulkOp()
metoda do wykonywania równolegle, a także w niedeterministycznej kolejności, operacji zapisu w partiach:
var bulk =db.wholesalers.initializeUnorderedBulkOp(),counter =0; // licznik do śledzenia rozmiaru aktualizacji zbiorczej
db.wholesalers.find({
"brands": { "$exists": true, "$type": 4 }
}).snapshot().forEach(function(doc){
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "brandsNetherlands": doc.brands }
});
counter++; // increment counter
if (counter % 1000 == 0) {
bulk.execute(); // Execute per 1000 operations and re-initialize every 1000 update statements
bulk = db.wholesalers.initializeUnorderedBulkOp();
}
});
Następny przykład dotyczy nowej wersji MongoDB 3.2
który od tego czasu wycofał Bulk()
API i dostarczył nowszy zestaw interfejsów API przy użyciu bulkWrite()
.
Używa tych samych kursorów, co powyżej, ale tworzy tablice z operacjami zbiorczymi przy użyciu tego samego forEach()
metoda kursora, aby wypchnąć każdy dokument zapisu zbiorczego do tablicy. Ponieważ polecenia zapisu mogą akceptować nie więcej niż 1000 operacji, należy pogrupować operacje tak, aby miały maksymalnie 1000 operacji i ponownie zainicjować tablicę, gdy pętla osiągnie 1000 iteracji:
var cursor = db.wholesalers.find({
"brands": { "$exists": true, "$type": 4 }
}),
bulkUpdateOps = [];
cursor.snapshot().forEach(function(doc){
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": { "brandsNetherlands": doc.brands } }
}
});
if (bulkUpdateOps.length === 1000) {
db.wholesalers.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) { db.wholesalers.bulkWrite(bulkUpdateOps); }