Node.js NodeJS批处理Mongo操作,等待回调

Node.js NodeJS批处理Mongo操作,等待回调,node.js,mongodb,Node.js,Mongodb,我正在尝试对mongo数据库执行批处理操作。其想法是迭代每个用户,然后找到学习同一课程或上同一所大学的其他用户,并存储有关这些匹配的信息 所有内容都包含在如下循环中: User.find({}, function(err, doc){ doc.forEach(function(candidate){ //other find operations in here ... } } 其中“User”是在站点上注册的用户的集合。我遇到的问题是forEa

我正在尝试对mongo数据库执行批处理操作。其想法是迭代每个用户,然后找到学习同一课程或上同一所大学的其他用户,并存储有关这些匹配的信息

所有内容都包含在如下循环中:

User.find({}, function(err, doc){
    doc.forEach(function(candidate){
        //other find operations in here
        ...
    }
}
其中“User”是在站点上注册的用户的集合。我遇到的问题是forEach循环正在为每个用户分派所有回调,而我希望在进入下一个文档之前,等待forEach循环中的所有回调完成

我尝试过使用异步,但我似乎无法理解这一点


如何一次处理一个用户?

您可以使用
async
,例如
async.eachSeries

async.eachSeries(doc, function (candidate, cb) {
    //other find operations in here
    ...
    // and you call cb() once they're done (important!)
    // or call cb('some error') if it failed 
}, function (err) {
    if (err) {
        // this means that some cb() above was called with error
    } else {
        // here all candidates are processed successfully
    }
});

请参阅:

将函数推入数组并稍后调用它们的一种方法是使用Observable,这对于循环异步操作非常有用

var candidatesOps = [];
User.find({}, function(err, doc){
    doc.forEach(function(candidate){
    var func =      function(candidate){
        //other find operations in here
      };

         candidatesOps.push(func);

        ...
    }
}

if(candidatesOps){ //call them candidatesOps[0]() }

无需为每个用户分派所有回调即可轻松完成此任务,在聚合操作中使用管道,在用户集合上创建
“自连接”
,使用管道过滤文档,仅返回与其他用户共享同一课程的用户

例如,如果有一个名为
课程
的字段,下面将返回学习同一课程的所有用户:

User.aggregate([
    { "$match": { "course": { "$exists": true } } },
    {
        "$lookup": {
            "from": "users",
            "localField": "course",
            "foreignField": "course",
            "as": "users_courses"
        }
    },
    { "$match": { "users_courses.1": { "$exists": true } } }
], callback);

在mongo shell中测试

db.test.insert([
    { "name": "a",  "course": "maths" },
    { "name": "b",  "course": "english" },
    { "name": "c",  "course": "maths" },
    { "name": "d",  "course": "science" },
    { "name": "e",  "course": "maths" },
    { "name": "f",  "course": "history" },
    { "name": "g",  "course": "history" }
])
运行聚合操作

db.test.aggregate([
    { "$match": { "course": { "$exists": true } } },
    {
        "$lookup": {
            "from": "users",
            "localField": "course",
            "foreignField": "course",
            "as": "users_courses"
        }
    },
    { "$match": { "users_courses.1": { "$exists": true } } }
])
样本输出

/* 1 */
{
    "_id" : ObjectId("58948c0dd04f1bbdbf331ea7"),
    "name" : "a",
    "course" : "maths",
    "users_courses" : [ 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331ea7"),
            "name" : "a",
            "course" : "maths"
        }, 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331ea9"),
            "name" : "c",
            "course" : "maths"
        }, 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331eab"),
            "name" : "e",
            "course" : "maths"
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("58948c0dd04f1bbdbf331ea9"),
    "name" : "c",
    "course" : "maths",
    "users_courses" : [ 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331ea7"),
            "name" : "a",
            "course" : "maths"
        }, 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331ea9"),
            "name" : "c",
            "course" : "maths"
        }, 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331eab"),
            "name" : "e",
            "course" : "maths"
        }
    ]
}

/* 3 */
{
    "_id" : ObjectId("58948c0dd04f1bbdbf331eab"),
    "name" : "e",
    "course" : "maths",
    "users_courses" : [ 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331ea7"),
            "name" : "a",
            "course" : "maths"
        }, 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331ea9"),
            "name" : "c",
            "course" : "maths"
        }, 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331eab"),
            "name" : "e",
            "course" : "maths"
        }
    ]
}

/* 4 */
{
    "_id" : ObjectId("58948c0dd04f1bbdbf331eac"),
    "name" : "f",
    "course" : "history",
    "users_courses" : [ 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331eac"),
            "name" : "f",
            "course" : "history"
        }, 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331ead"),
            "name" : "g",
            "course" : "history"
        }
    ]
}

/* 5 */
{
    "_id" : ObjectId("58948c0dd04f1bbdbf331ead"),
    "name" : "g",
    "course" : "history",
    "users_courses" : [ 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331eac"),
            "name" : "f",
            "course" : "history"
        }, 
        {
            "_id" : ObjectId("58948c0dd04f1bbdbf331ead"),
            "name" : "g",
            "course" : "history"
        }
    ]
}

非常感谢。混合使用async.eachSeries()和async.serial()实现了这一点。