【问题标题】:how can run mongoose query in forEach loop如何在 forEach 循环中运行猫鼬查询
【发布时间】:2017-06-04 06:40:20
【问题描述】:

谁能帮助我如何在nodejs的forEach循环中运行猫鼬查询并建议两个集合的内部连接结果需要

喜欢下面的细节

userSchema.find({}, function(err, users) {
    if (err) throw err;
    users.forEach(function(u,i){
        var users = [];
        jobSchema.find({u_sno:s.u.sno}, function(err, j) {
            if (err) throw err;
            if (!u) {
                res.end(JSON.stringify({
                    status: 'failed:Auction not found.',
                    error_code: '404'
                }));
                console.log("User not found.");
                return 
            }
            users.push(j);
        })
    })
    res.send(JSON.stringify({status:"success",message:"successfully done",data:{jobs:j,users:u}}));
})

【问题讨论】:

    标签: node.js mongodb express mongoose


    【解决方案1】:

    Schema.find() 是一个异步函数。因此,您的最后一行代码将在您等待循环中执行第一次工作搜索时执行。我建议将其更改为 Promises 并使用 Promise.all(array)。

    为此,首先您必须更改为将 Promise 与 mongoose 一起使用。你可以像这样用蓝鸟做到这一点:

    var mongoose = require('mongoose');
    mongoose.Promise = require('bluebird');
    

    然后你可以像这样使用 Promises 而不是回调:

    userSchema.find({}).then(function(users) {
      var jobQueries = [];
    
      users.forEach(function(u) {
        jobQueries.push(jobSchema.find({u_sno:s.u.sno}));
      });
    
      return Promise.all(jobQueries );
    }).then(function(listOfJobs) {
        res.send(listOfJobs);
    }).catch(function(error) {
        res.status(500).send('one of the queries failed', error);
    });
    

    编辑如何同时列出工作和用户

    如果你想要这样的结构:

    [{ 
      user: { /* user object */,
      jobs: [ /* jobs */ ]
    }]
    

    您可以将列表合并在一起。 listOfJobs 与 jobQueries 列表的顺序相同,因此它们与用户的顺序相同。将用户保存到共享范围以访问“then 函数”中的列表,然后合并。

    ..
    }).then(function(listOfJobs) {
      var results = [];
    
      for (var i = 0; i < listOfJobs.length; i++) {
        results.push({
          user: users[i],
          jobs: listOfJobs[i]
        });
      }
    
      res.send(results);
    }).catch(function(error) {
      res.status(500).send('one of the queries failed', error);
    });
    

    【讨论】:

    • 感谢您的帮助,但我有一个问题是如何打印作业和用户列表
    • 显示此错误---->App Started on PORT 8080 express deprecated res.send(status, body): Use res.status(status).send(body) instead App/Controllers/Api /MarketController.js:36:23 (node:15265) UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝 id:1):RangeError:无效状态代码:0(节点:15265) DeprecationWarning:不推荐使用未处理的承诺拒绝。将来,未处理的 Promise 拒绝将使用非零退出代码终止 Node.js 进程。
    • 你仍然需要捕获..让我将我的答案从“...”更新为捕获
    • 我想补充一点,它只有在我向jobQueries.push(jobSchema.find({u_sno:s.u.sno})); 行添加回调后才对我有效,所以它变成了jobQueries.push(jobSchema.find({u_sno:s.u.sno}), () =&gt; {});
    • @LuisEgan 尝试在连接到猫鼬的地方添加 mongoose.Promise = global.Promise。 Bluebird 是一个 es5 Promise 库。但是对于更高版本的节点,您在全局中拥有 Promise
    【解决方案2】:

    一个不错的优雅解决方案是使用cursor.eachAsync() 函数。感谢https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js

    eachAsync() 函数执行一个(可能是异步的)函数 光标返回的每个文档。如果该函数返回一个 承诺,它将等待该承诺解决,然后再获得 下一个文件。这是耗尽光标的最简单方法 猫鼬。

      // A cursor has a `.next()` function that returns a promise. The promise
      // will resolve to the next doc if there is one, or null if they are no
      // more results.
      const cursor = MyModel.find().sort({name: 1 }).cursor();
    
      let count = 0;
      console.log(new Date());
      await cursor.eachAsync(async function(doc) {
        // Wait 1 second before printing first doc, and 0.5 before printing 2nd
        await new Promise(resolve => setTimeout(() => resolve(), 1000 - 500 * (count++)));
        console.log(new Date(), doc);
      });
    

    【讨论】:

      【解决方案3】:

      不需要使用 forEach(),它是同步的并且以异步方式调用,这会给你错误的结果。

      您可以使用聚合框架并使用 $lookup,它对同一数据库中的另一个集合执行左外连接,以过滤来自“已连接”集合的文档进行处理。

      因此,可以使用单个聚合管道完成相同的查询:

      userSchema.aggregate([
          {
              "$lookup": {
                  "from": "jobs", /* underlying collection for jobSchema */
                  "localField": "sno",
                  "foreignField": "u_sno",
                  "as": "jobs"
              }
          }
      ]).exec(function(err, docs){
          if (err) throw err;
          res.send(
              JSON.stringify({
                  status: "success",
                  message: "successfully done",
                  data: docs
              })
          );
      })
      

      【讨论】:

      • 建议我需要内部连接,就像我们需要结果用户和 jos 一对一表一样
      • 您的 MongoDB 服务器版本是多少?
      • 它的 3.2 版本
      • @chridam mongodb 不支持内连接,而是只支持左外连接。
      【解决方案4】:

      你可以用这个:

      db.collection.find(query).forEach(function(err, doc) {
         // ...
      });
      

      【讨论】:

      • 我得到一个错误是:.forEach 不是函数。为什么?
      • 因为 foreach 是原生 mongodb 函数而不是 mongoose 函数
      猜你喜欢
      • 2021-01-30
      • 2019-05-26
      • 1970-01-01
      • 2019-06-22
      • 1970-01-01
      • 1970-01-01
      • 2013-11-15
      • 2021-08-03
      • 2017-12-13
      相关资源
      最近更新 更多