nodejs中的异步foreach和mongoose

Posted

技术标签:

【中文标题】nodejs中的异步foreach和mongoose【英文标题】:async foreach and mongoose in nodejs 【发布时间】:2021-04-08 09:39:37 【问题描述】:

在猫鼬中,我建立了类似于猫鼬文档的关系,现在我想要一个对象数组

对象是我们拥有的对象的子对象

例如在 tweeter 中,一个用户有很多推文,每条推文都有标题、内容和作者

有人给我们用户 ID,我们给他所有推文用户的标题和内容数组

[
title: 'title01', content: 'aaaaaa',
title: 'title02', content: 'bbbbb',
.
.
.
]

我试试

    const username = req.params.username;
    User.find( username: username , (err, docs) => 
      if (err) return res.json( err: true );
      if (docs.length > 0) 
        let lives: Array<Object> = [];
        docs[0].lives.forEach((live, idx) => 
          Live.find( _id: live , (err, docs) => 
            lives.push(docs[0]);
          );
        );
       else 
        return res.json( err: true );
      
    );

lives 有标题内容和作者(在 DB 中我将其命名为用户) 但是因为 aSync 我无法在 forEach 之后获得生命 :)

更新:

直播模式:

const schema = new mongoose.Schema(
  title: 
    type: String,
    required: true,
  ,
  content: 
    type: String,
    required: true,
  ,
  user: 
    type: mongoose.Schema.Types.ObjectId,
    ref: "users",
    required: true,
  ,
);

用户模式:

import  ArraySortOptions  from "joi";
import mongoose,  Model  from "mongoose";

interface IUser extends mongoose.Document 
  email: string;
  username: string;
  password: string;
  lives: Array<mongoose.Schema.Types.ObjectId>;


const schema: mongoose.Schema = new mongoose.Schema(
  username: 
    type: String,
    required: true,
  ,
  password: 
    type: String,
    required: true,
  ,
  email: 
    type: String,
    required: true,
  ,
  lives: [
    
      type: mongoose.Schema.Types.ObjectId,
      ref: "lives",
    ,
  ],
);
const User: Model<IUser> = mongoose.model("users", schema);
export default User;

【问题讨论】:

【参考方案1】:

我会这样做:

const username = req.params.username;
User.find( username: username , async (err, docs) => 
  if (err) return res.json( err: true );
  if (docs.length > 0) 
    // start with asnyc queries
    let livePromises = [];
    for (let live of docs[0].lives) 
      // push new promise which resolves the docs[0] of this live id
      livePromises.push(new Promise(resolve => 
        Live.find( _id: live , (err, docs) => 
          resolve(docs[0]);
        );
      
    
    // await all query results parallel
    let lives = await Promise.all(livePromises);
    // use lives variable as you want
    return res.json( lives: lives );
   else 
    return res.json( err: true );
  
);

我不确定你使用的是哪种类型的系统(你写了lives: Array&lt;Object&gt;),所以我跳过了。根据需要修改我的建议。 如果您对此答案或一般Promises 有任何疑问,请写评论。

【讨论】:

我用打字稿 Promise.all 做什么? Promise.all() 方法将一个可迭代的 Promise 作为输入,并返回一个 Promise,该 Promise 解析为输入 Promise 的结果数组。【参考方案2】:

最好使用 Mongoose 的内置 populate() 方法,该方法允许您引用其他集合中的文档,类似于 MongoDB 版本 >= 3.2 中的类似联接的 $lookup 聚合运算符。

由于populate() 需要附加查询,因此使用User.findOne() 查询与我们在参数中提供的用户名匹配的单个用户。

使用 async/await 可以如下完成:

const  username  = req.params;
const user = await User.findOne( username ).populate('lives');
console.log(user.lives); // ---> [title: 'title01', content: 'aaaaaa',  ... ]

【讨论】:

以上是关于nodejs中的异步foreach和mongoose的主要内容,如果未能解决你的问题,请参考以下文章

NodeJs, javascript: .forEach 似乎是异步的?需要同步

nodejs中的异步和同步怎么理解

nodejs是同步还是异步

nodejs Async详解之三:集合操作

NodeJS:等待所有带有 Promises 的 foreach 完成,但从未真正完成

如何等到在nodejs中执行流异步[重复]