0

I need to perform complicated aggregation on Mongo DB collection. I also need to go through the results twice. After first pass, I execute rewind() on a cursor. Then I try to perform second pass. This is where I get the error. What is strange that if I replace each(), with couple of next(). Then everything works as expected.

Is it a bug in each(), which I should submit to MongoDB bugtracker? Or it is some sort of my error?

Much simplified sample, but still reproduce the error:

var MongoClient = require('mongodb').MongoClient;
var ObjectId = require('mongodb').ObjectId;

MongoClient.connect('mongodb://localhost:27017/test', function(err, db) {
  // Create a collection
  let collection = db.collection('aggregation_each_example');
  // collection.drop();

  // Some docs for insertion
  function createData(callback) {
    let docs = [
      {
        "oid" : new ObjectId("59883f2e7d8c6325200b81e4"),
        "tod" : new Date("2017-08-07T10:21:34.877Z")
      },  
      {
        "veryImportanta" : "newOne",
        "oid" : new ObjectId("59883f2e7d8c6325200b81e4")
      }  
    ];

    // Insert the docs
    collection.insertMany(docs, callback);
  }

  function getData(callback) {
    return function(err) {
      if (err) {
        console.error(err);
      } else {
        let cursor = collection.aggregate([
                                            {
                                              "$match": {
                                                "oid": new  ObjectId("59883f2e7d8c6325200b81e4"),
                                                "tod": {
                                                  "$exists": 0
                                                }
                                              }
                                            }
                                          ], {cursor: {batchSize: 1}});
        let count = 0;
        cursor.each(function(err, doc) {
          if(doc) {
            console.log(doc);
            count++;
          } else {
            console.log(cursor.isClosed());
            cursor.rewind();
            console.log(cursor.isClosed());
            callback(count, cursor);
          }
        });

      }
    }
  }

  createData(getData(function(count, cursor) {
    console.log("Count: "+ count);
    console.log("Cursor is closed: " + cursor.isClosed());
    cursor.next(function(err, doc) {
      if (err) console.log(err);
      else console.log(doc);
      // db.dropDatabase();
      db.close();
    });
  }));

});

Output:

{ _id: 598851ad48a1841c18b50bcf,
  veryImportanta: 'newOne',
  oid: 59883f2e7d8c6325200b81e4 }
true
false
Count: 1
Cursor is closed: false
{ MongoError: Cursor is closed
    at Function.MongoError.create (error.js:31:11)
    at nextObject (node_modules\mongodb\lib\cursor.js:669:112)
    at AggregationCursor.Cursor.next (node_modules\mongodb\lib\cursor.js:269:12)
    at error.js:61:12
    at error.js:50:13
    at handleCallback (node_modules\mongodb\lib\utils.js:120:56)
    at node_modules\mongodb\lib\cursor.js:748:16
    at handleCallback (node_modules\mongodb\lib\utils.js:120:56)
    at node_modules\mongodb\lib\cursor.js:682:5
    at handleCallback (node_modules\mongodb-core\lib\cursor.js:171:5) name: 'MongoError', message: 'Cursor is closed', driver: true }

Environment:

  • nodejs: v6.6.0
  • mongodb: 2.2.30
  • os: windows 10
  • mongodb engine: 3.4
Aleksander Gralak
  • 1,509
  • 10
  • 26
  • Don't do that. Simply run a regular query and return the `.count()` property from that instead. Don't force iteration of a cursor simply to "count". Also all `rewind()` does is effectively "run the query or aggregation pipeline **again**". So it's not exactly like "skipping back to the start" because it actually "re-executes" the whole thing again. – Neil Lunn Aug 07 '17 at 12:06
  • @Neil Lunn: Thx for the reply. I can't do real thing with a simple query, it has to be aggregate. The example is simplified version of what I want to do and the aggragation pipeline will be much longer. However the information what rewind really do is important. Anyway I still have no confirmation if this is a bug or my mistake. – Aleksander Gralak Aug 07 '17 at 13:06
  • **It's your mistake**. Aggregation or simple query, the point is "run it again" and do that yourself. There are other more efficient to achieve a "count" than iterating the cursor anyway. – Neil Lunn Aug 08 '17 at 01:09
  • Forget about count, this is just example. Where is my mistake? Why should I do it myself if there is `rewind` method for it? Why it works while using recursive function with `next`, but it stops working while using `each`? For me it looks like a bug, probably in `each` method. – Aleksander Gralak Aug 08 '17 at 06:08

0 Answers0