How can I use a cursor.forEach() in MongoDB using Node.js?

前端 未结 10 855
你的背包
你的背包 2020-11-27 14:04

I have a huge collection of documents in my DB and I\'m wondering how can I run through all the documents and update them, each document with a different value.

10条回答
  •  时光说笑
    2020-11-27 14:56

    Leonid's answer is great, but I want to reinforce the importance of using async/promises and to give a different solution with a promises example.

    The simplest solution to this problem is to loop forEach document and call an update. Usually, you don't need close the db connection after each request, but if you do need to close the connection, be careful. You must just close it if you are sure that all updates have finished executing.

    A common mistake here is to call db.close() after all updates are dispatched without knowing if they have completed. If you do that, you'll get errors.

    Wrong implementation:

    collection.find(query).each(function(err, doc) {
      if (err) throw err;
    
      if (doc) {
        collection.update(query, update, function(err, updated) {
          // handle
        });
      } 
      else {
        db.close(); // if there is any pending update, it will throw an error there
      }
    });
    

    However, as db.close() is also an async operation (its signature have a callback option) you may be lucky and this code can finish without errors. It may work only when you need to update just a few docs in a small collection (so, don't try).


    Correct solution:

    As a solution with async was already proposed by Leonid, below follows a solution using Q promises.

    var Q = require('q');
    var client = require('mongodb').MongoClient;
    
    var url = 'mongodb://localhost:27017/test';
    
    client.connect(url, function(err, db) {
      if (err) throw err;
    
      var promises = [];
      var query = {}; // select all docs
      var collection = db.collection('demo');
      var cursor = collection.find(query);
    
      // read all docs
      cursor.each(function(err, doc) {
        if (err) throw err;
    
        if (doc) {
    
          // create a promise to update the doc
          var query = doc;
          var update = { $set: {hi: 'there'} };
    
          var promise = 
            Q.npost(collection, 'update', [query, update])
            .then(function(updated){ 
              console.log('Updated: ' + updated); 
            });
    
          promises.push(promise);
        } else {
    
          // close the connection after executing all promises
          Q.all(promises)
          .then(function() {
            if (cursor.isClosed()) {
              console.log('all items have been processed');
              db.close();
            }
          })
          .fail(console.error);
        }
      });
    });
    

提交回复
热议问题