Aggregation issue with Mongo 3.6

2020-04-12 10:02发布

问题:

I was using the aggregate function without any problem connecting a 3.4 mongodb.

When I change to a 3.6 db,

I've got the message: The 'cursor' option is required, except for aggregate with the explain argument.

Sorry if it's already posted. I am unable to find any solutions

回答1:

In mongo 3.6 there has been changes while using aggregate you have to use cursor, unless you include the explain option, you must specify the cursor option. I faced same error as you were facing. Now you have to do it like

this.aggregate( [
        { $unwind : "$tags" },
        {$group: {_id: '$tags', count: { $sum: 1} }},
        {$sort: { count: 1 }}
            ] ).cursor({}).exec();

Now you can use cursor method cursor.toArray() to return an array that contains all the documents from a cursor. Cursors returned from aggregation only supports cursor methods that operate on evaluated cursors like cursor.toArray(), to know about more cursor methods you can click here and get further.



回答2:

In Node.js, after upgrade MongoDB from 3.4 to 3.6, there are 2 things that need to check:

  1. Add cursor: {} option in the aggregate statement. In previous MongoDB version, this is optional (Of course, you can define batchSize in cursor object if you want). For example:

    db.collection(collectionName).aggregate(pipelineArray, {
      cursor: {}
    }, function(error, result) {
      ...
    });
    
  2. If the above code hang and the callback is not invoked, please check the mongodb driver version. I get this "not responding" problem in mongodb module v2.2.16. After upgrade mongodb to v2.2.35, it's fixed.



回答3:

For those with issues trying to figure out a complete example on 3.6, this worked for me :

function aggregateLoad(db, collectionName, lookUpOption, matchOption, callback) {
        var defCursor = {};
        var cursor = db.collection(collectionName).aggregate([
            {
                $lookup: lookUpOption
            },
            {
                $match: matchOption
            }
        ],defCursor,null);
        cursor.toArray(function(err, docs) {
            console.log("Some data: ", docs);
            callback(err, docs);
            db.close();
        });

}

then you can call the above function as :

function testAggregateLoad(someId, callback) {
        var match = {
            "localId": someId
        };
        var aggregateQuery = {
            from: "someSecondCollectionName",
            localField: "localId",
            foreignField: "_id",
            as: "someData"
        };
        getConnection(conCallBackEx);
        function conCallBackEx(db) {
           aggregateLoad(db, "someBaseLoadCollection", aggregateQuery, match, onSuccess);
        }
        function onSuccess(err, json) {
            console.log('Loaded data is ', json);
            callback(json);
        }
    }



function getConnection(callback) {
        var MongoClient = require('mongodb').MongoClient;
        return MongoClient.connect(url, function (err, db) {
            if (null === err) {
                callback(db, err);
            } else {
                console.log("failed to get db connection retrying  " + err);
                getConnection(callback);
            }
        });
    }