for循环中的多个异步函数后的NodeJS回调

时间:2018-12-20 09:44:17

标签: node.js mongodb promise async-await aggregation-framework

我从mongodb中获得了一个文档,其中包含一个带有对该文档的注释的数组。注释中是编写注释的用户的_id。

我现在需要根据用户的_id获取用户名,但是我遇到了一些问题。

我有以下代码,这些代码显然不起作用,但是我希望它可以使您了解我要完成的工作。

//MORE CODE... (No need to show this here, just a promise, some try catch and so on)
let article = await Article.findOne({_id:articleid})   
    for(var i = 0; i<=article.comment.length-1; i++){
        User.findOne({_id:article.comment[i].user}).then((user)=>{
            article.comment[i].username = user.username
        })
    }
return resolve(article)

我查阅了一些文档,但找不到有效的解决方案。我尝试使用Promise.all,并进行了许多异步处理,等待,试图在for循环中添加一个计数器,并在循环结束后解决了Promise,但到目前为止没有任何效果。

这就是我的数据库中的文章

{
    "_id" : ObjectId("5c18c1cbc47e5e29d42e4b0e"),
    "completed" : false,
    "completedAt" : null,
    "comment" : [ 
        {
            "_id" : ObjectId("5c18c95e328c8319ac07d817"),
            "comment" : "This is a comment",
            "rating" : [ ],
            "user" : ObjectId("5c18b76e73236d2168eda2b4")
        }, 
        {
            "_id" : ObjectId("5c18fb578de5741f20a4e2bd"),
            "comment" : "Another comment",
            "rating" : [ ],
            "user" : ObjectId("5c18b76e73236d2168eda2b4")
        }
    ]
}

我对Node.js和mongodb还是很陌生,所以希望您能帮助像我这样的新手。

感谢您的帮助

2 个答案:

答案 0 :(得分:3)

您可以根据自己的方便在这里使用一些服务器方法

使用异步等待

let article = await Article.findOne({ _id: articleid }).lean().exec()

await Promise.all(
  article.comment.map(async(obj) => {
    const user = await User.findOne({ _id: obj.user })
    obj.username = user.username
  })
)

console.log(article)

使用$lookup聚合3.6

由于mongodb具有自己强大的$lookup聚合运算符,可以加入多个集合,并且可能是无需任何迭代的更好方法

Article.aggregate([
  { "$match": { "_id": mongoose.Types.ObjectId(articleid) }},
  { "$unwind": "$comment" },
  { "$lookup": {
    "from": "users",
    "let": { "userId": "$comment.user" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": ["$$userId", "$_id"] }}}
    ],
    "as": "comment.user"
  }},
  { "$unwind": "$comment.user" },
  { "$group": {
    "_id": "$_id",
    "comment": { "$push": "$comment" },
    "completed": { "$first": "$completed" },
    "completedAt": { "$first": "$completedAt" }
  }}
])

使用$lookup聚合3.4

Article.aggregate([
  { "$match": { "_id": mongoose.Types.ObjectId(articleid) }},
  { "$unwind": "$comment" },
  { "$lookup": {
    "from": "users",
    "localField": "comment.user",
    "foreignField": "_id",
    "as": "comment.user"
  }}
  { "$unwind": "$comment.user" },
  { "$group": {
    "_id": "$_id",
    "comment": { "$push": "$comment" },
    "completed": { "$first": "$completed" },
    "completedAt": { "$first": "$completedAt" }
  }}
])

答案 1 :(得分:-2)

您可以按照以下方式尝试

const d = {
    "_id" : ObjectId("5c18c1cbc47e5e29d42e4b0e"),
    "completed" : false,
    "completedAt" : null,
    "comment" : [ 
        {
            "_id" : ObjectId("5c18c95e328c8319ac07d817"),
            "comment" : "This is a comment",
            "rating" : [ ],
            "user" : ObjectId("5c18b76e73236d2168eda2b4")
        }, 
        {
            "_id" : ObjectId("5c18fb578de5741f20a4e2bd"),
            "comment" : "Another comment",
            "rating" : [ ],
            "user" : ObjectId("5c18b76e73236d2168eda2b4")
        }
    ]
}

d.comment.forEach( async (obj, index) => {
    await new Promise((res) => {
            obj.counter = index;
            res();
    })
});

console.log(d);

作为参考,请查看以下链接 Asycn/Await using forEach