node.js 如何在 forEach 循环中运行猫鼬查询

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41743924/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 17:56:18  来源:igfitidea点击:

how can run mongoose query in forEach loop

node.jsmongodbexpressmongoose

提问by lakshmankashyap

can anyone help me for how can run mongoose query in forEach loop in nodejs and suggest for inner join result need of both collections

任何人都可以帮助我了解如何在 nodejs 的 forEach 循环中运行 mongoose 查询并建议两个集合的内部连接结果需要

like below details

喜欢下面的细节

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}}));
})

采纳答案by tdog

You can use this:

你可以使用这个:

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

回答by R. Gulbrandsen

Schema.find() is an async function. So your last line of code will execute while you wait for the first job search is executed in your loop. I suggest change it to Promises and use Promise.all(array).

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

To do so, first you have to change to use Promise with mongoose. you can do this with bluebird like this:

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

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

Then you can use Promises instead of callbacks like this:

然后你可以使用 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);
});

EDITHow to list both jobs and users

编辑如何列出作业和用户

If you want to have a structure like:

如果你想要一个像这样的结构:

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

you could merge the lists together. listOfJobs is in the same order as the jobQueries list, so they are in the same order as the users. Save users to a shared scope to get access to the list in the 'then function' and then merge.

您可以将列表合并在一起。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);
});

回答by chridam

No need to use forEach()which is synchronous and being called in an asynchronous fashion, that will give you wrong results.

无需使用forEach()which 是同步的并以异步方式调用,这会给您错误的结果。

You can use the aggregation framework and use $lookupwhich performs a left outer join to another collection in the same database to filter in documents from the "joined" collection for processing.

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

So the same query can be done using a single aggregation pipeline as:

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

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
        })
    );
})

回答by pengz

A nice elegant solution is to use the cursor.eachAsync()function. Credit to https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js.

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

The eachAsync() function executes a (potentially async) function for each document that the cursor returns. If that function returns a promise, it will wait for that promise to resolve before getting the next document. This is the easiest way to exhaust a cursor in mongoose.

eachAsync() 函数为游标返回的每个文档执行一个(可能是异步的)函数。如果该函数返回一个承诺,它将在获取下一个文档之前等待该承诺解决。这是在 mongoose 中耗尽游标的最简单方法。

  // 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);
  });