NodeJS Batch Mongo 操作,等待回调

Posted

技术标签:

【中文标题】NodeJS Batch Mongo 操作,等待回调【英文标题】:NodeJS Batch Mongo operation, wait for callbacks 【发布时间】:2017-06-20 21:39:34 【问题描述】:

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

一切都包含在这样的循环中:

User.find(, function(err, doc)
    doc.forEach(function(candidate)
        //other find operations in here
        ...
    

“用户”是在网站上注册的用户集合。我遇到的问题是 forEach 循环正在为每个用户分派所有回调,而我想等待 forEach 循环中的所有回调完成,然后再转到下一个文档。

我尝试过使用异步,但我似乎无法弄清楚这一点。

如何一次处理每个用户?

【问题讨论】:

【参考方案1】:

您可以为此使用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
    
);

见:https://caolan.github.io/async/docs.html#eachSeries

【讨论】:

谢谢!混合使用 async.eachSeries() 和 async.serial() 就可以了。【参考方案2】:

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

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]() 

【讨论】:

【参考方案3】:

此任务可以轻松完成,无需为每个用户分派所有回调,在聚合操作中使用 $lookup 管道,您可以在用户集合上创建 "self-join",使用 $match 管道过滤文档以仅返回与其他用户共享同一课程的用户。

例如,假设有一个名为course的字段,以下将返回正在学习同一课程的所有用户:

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"
        
    ]

【讨论】:

以上是关于NodeJS Batch Mongo 操作,等待回调的主要内容,如果未能解决你的问题,请参考以下文章

Mongo 连接流在 NodeJS 应用程序中意外关闭

NodeJS + Mongo - 如何获取集合的内容?

mongodb驱动的正确使用方法

node.js零基础详细教程(7.5):mongo可视化工具webstorm插件nodejs自动重启模块

nodejs入门总结二:事件驱动

NodeJS/Mongo:通过各种集合循环查询