MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Jakie jest właściwe podejście do aktualizacji wielu rekordów w MongoDB za pomocą Mongoose?

Podejście polegające na zbudowaniu kryterium składającego się ze wszystkich identyfikatorów dokumentów, a następnie wykonaniu aktualizacji, może powodować potencjalne problemy. Kiedy iterujesz listę dokumentów wysyłając operację aktualizacji z każdym dokumentem, w Mongoose ryzykujesz wysadzenie serwera, zwłaszcza gdy masz do czynienia z dużym zbiorem danych, ponieważ nie czekasz na zakończenie asynchronicznego wywołania przed przejściem do następnego iteracja. Zasadniczo będziesz budować „stos” nierozwiązanych operacji, dopóki nie spowoduje to problemu - Stackoverflow.

Weźmy na przykład, załóżmy, że masz tablicę identyfikatorów dokumentów, które chcesz zaktualizować pasujący dokument w polu stanu:

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

gdzie możesz użyć updateMany() metoda

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

lub alternatywnie dla naprawdę małych zestawów danych możesz użyć forEach() metoda na tablicy, aby ją iterować i aktualizować swoją kolekcję:

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 serwera kodu asynchronicznego w pętli.

Aby rozwiązać ten problem, użyj czegoś takiego jak eachLimit i iteruj po tablicy, wykonując operację aktualizacji MongoDB dla każdego elementu, nigdy nie wykonując jednocześnie więcej niż x równoległych aktualizacji.

Najlepszym podejściem byłoby użycie do tego celu zbiorczego interfejsu API, który jest niezwykle wydajny w przetwarzaniu zbiorczych aktualizacji. Różnica w wydajności w porównaniu z wywoływaniem operacji aktualizacji na każdym z wielu dokumentów polega na tym, że zamiast wysyłać żądania aktualizacji do serwera w każdej iteracji, zbiorczy interfejs API wysyła żądania raz na 1000 żądań (wsadowo).

Dla wersji Mongoose >=4.3.0 które obsługują serwer MongoDB 3.2.x , możesz użyć bulkWrite() o aktualizacje. Poniższy przykład pokazuje, jak możesz się do tego zabrać:

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

Dla wersji Mongoose ~3.8.8 , ~3.8.22 , 4.x które obsługują serwer MongoDB >=2.6.x , możesz użyć Bulk API w następujący sposób

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. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Korzystanie z poleceń powłoki MongoDB w sterowniku MongoDB 10Gen

  2. Wyjątek Mongodb, MongoCursorException' z komunikatem 'Operator $ uczynił obiekt zbyt dużym Co to oznacza?

  3. Nie można pobrać wartości właściwości dirtyPropertyNames dla pól asocjacyjnych w Grails

  4. jak posortować tablicę obiektów według dowolnej listy w mongo

  5. Ile kolekcji jest możliwych w MongoDB bez utraty wydajności?