【问题标题】:How to return Mongoose results from the find method?如何从 find 方法返回 Mongoose 结果?
【发布时间】:2011-09-05 01:42:57
【问题描述】:

我能找到的所有内容都可以用来渲染带有猫鼬结果的页面:

users.find({}, function(err, docs){
    res.render('profile/profile', {
        users:     docs
    });
});

我怎样才能从查询中返回结果,更像这样?

var a_users = users.find({}); //non-working example

这样我就可以在页面上发布多个结果?

喜欢:

/* non working example */
var a_users    = users.find({});
var a_articles = articles.find({});

res.render('profile/profile', {
      users:    a_users
    , articles: a_articles
});

这个可以吗?

【问题讨论】:

标签: mongodb node.js express mongoose


【解决方案1】:

简单的方法:

var userModel = mongoose.model('users');
var articleModel = mongoose.model('articles');
userModel.find({}, function (err, db_users) {
  if(err) {/*error!!!*/}
  articleModel.find({}, function (err, db_articles) {
    if(err) {/*error!!!*/}
    res.render('profile/profile', {
       users: db_users,
       articles: db_articles
    });
  });
});

实际上,Node.js 中的每个函数都是异步的。猫鼬的发现也是如此。如果你想连续调用它,你应该使用Slide library 之类的东西。

但在您的情况下,我认为最简单的方法是嵌套回调(这允许 f.e. 为选定的先前用户查询文章)或在异步库的帮助下完全并行(参见 Flow control / Async goodies)。

【讨论】:

  • 我想我可以这样做,但没有解决我更大的底层问题。我的例子可能不是最好的。我理解保持异步,但最大的问题是我试图让代码更有条理地以更真实的 MVC 方式组织,并且很难做到这一点。我讨厌在每个页面的控制器中我必须进行所有这些查询的想法——在我看来应该在模型中处理。因此,我试图找出一种将模型保存在一个地方并请求信息并将其返回给控制器的方法。
  • @user776796 在我的项目中,我将模型放在单独的文件中,这些文件在控制器之前加载。 Mongoose 的模型在我的模型中,我为常用查询添加了快捷功能。
  • 这听起来像是我的设置方式。您如何从快捷功能返回查询结果?
  • @user776796 我不返回结果而是传递给回调传递给快捷函数。
【解决方案2】:

您正在尝试强制使用同步范式。就是行不通。 node.js 在大多数情况下是单线程的——当 io 完成时,会产生执行上下文。信令通过回调进行管理。这意味着您要么拥有嵌套回调、命名函数或流控制库,以使事情看起来更漂亮。

https://github.com/caolan/async#parallel

async.parallel([
   function(cb){
      users.find({}, cb);
   },
   function(cb){
      articles.find({}, cb);
   }
], function(results){
   // results contains both users and articles
});

【讨论】:

  • @josh 有没有办法在第二个函数中访问第一个函数的结果?还是它们仅在回调中可用?
  • @pkyeck 如果您使用瀑布或其他连续执行操作的方法之一,则可以。在这个例子中,这两种方法都可以使用 process.nextTick 并行运行,这意味着函数 1 的结果不可用于函数 2
  • Async NPM 似乎很强大,有时我们需要一些同步任务。
  • 这行得通,而且是非常好的答案(赞成!:)),但是这些天 - 我会说使用 async 进行并行任务有点过时了。这是完全可以理解的,考虑到这个解决方案是在 2011 年编写的。Promises 在处理异步任务时提供了更大的灵活性,我建议任何人在使用不同的解决方案之前考虑使用它们(免责声明: 我在这个线程中发布了答案,展示了它们在这种情况下的用途)。
  • 有没有办法访问“结果”上的属性,例如 results.users 或 results.articles ?
【解决方案3】:

我有一个函数,我经常使用它作为对 Node 函数的返回。

function freturn (value, callback){
    if(callback){
        return callback(value); 
    }
    return value; 
}; 

然后我在所有签名中都有一个可选的回调参数。

【讨论】:

    【解决方案4】:

    我正在处理一个非常相似的事情,但使用来自客户端的 socket.io 和 DB 访问。我的发现是在数据库有机会获取数据之前将我的数据库内容扔回客户端......所以我将在这里分享我的发现:

    我检索数据库的函数:

    //读板-完整的DB

    var readBoards = function() {
            var callback = function() {
                return function(error, data) {
                    if(error) {
                        console.log("Error: " + error);
                    }
                    console.log("Boards from Server (fct): " + data);
    
                }
            };
    
            return boards.find({}, callback());
        };
    

    我的套接字事件监听器:

    socket.on('getBoards', function() {
            var query = dbConnection.readBoards();
            var promise = query.exec();
            promise.addBack(function (err, boards) {
                if(err)
                    console.log("Error: " + err);
                socket.emit('onGetBoards', boards);
            });
        });
    

    所以为了解决这个问题,我们使用猫鼬给我们的承诺,然后一旦我们从数据库接收到数据,我的套接字就会将它发送回客户端......

    为了它的价值......

    【讨论】:

      【解决方案5】:

      我将在这里扮演死灵法师,因为我仍然看到另一种更好的方法。

      使用美妙的 promise 库 Bluebird 及其 promisifyAll() 方法:

      var Promise = require('bluebird');
      var mongoose = require('mongoose');
      
      Promise.promisifyAll(mongoose); // key part - promisification
      
      var users, articles; // load mongoose models "users" and "articles" here
      
      Promise.props({
          users: users.find().execAsync(),
          articles: articles.find().execAsync()
        })
        .then(function(results) {
          res.render('profile/profile', results);
        })
        .catch(function(err) {
          res.send(500); // oops - we're even handling errors!
        });
      

      关键部分如下:

      Promise.promisifyAll(mongoose);
      

      使所有 mongoose(及其模型)方法可用作返回 Promise 的函数,带有 Async 后缀(.exec() 变为 .execAsync(),等等)。 .promisifyAll() 方法在 Node.JS 世界中几乎是通用的——你可以在任何提供异步函数的东西上使用它,将回调作为最后一个参数。

      Promise.props({
          users: users.find().execAsync(),
          articles: articles.find().execAsync()
        })
      

      .props() bluebird 方法接收带有 Promise 作为其属性的对象,并返回集体 Promise,当两个数据库查询(此处为 Promise)返回其结果时,该 Promise 将得到解决。解析出来的值就是我们在最终函数中的results对象:

      • results.users - 由猫鼬在数据库中找到的用户
      • results.articles - mongoose (d'uh) 在数据库中找到的文章

      如您所见,我们甚至还没有接近缩进回调地狱。两个数据库查询是并行执行的——其中一个不需要等待另一个。代码简短易读 - 实际上在长度和复杂性(或者说缺乏它)上与问题本身中发布的一厢情愿的“非工作示例”相对应。

      承诺很酷。使用它们。

      【讨论】:

        【解决方案6】:

        您可以通过以下代码获得所需的结果。希望这会对你有所帮助。

        var async = require('async');
        
        // custom imports
        var User = require('../models/user');
        var Article = require('../models/article');
        
        var List1Objects = User.find({});
        var List2Objects = Article.find({});
        var resourcesStack = {
            usersList: List1Objects.exec.bind(List1Objects),
            articlesList: List2Objects.exec.bind(List2Objects),
        };
        
        async.parallel(resourcesStack, function (error, resultSet){
            if (error) {
                res.status(500).send(error);
                return;
            }
            res.render('home', resultSet);
        });
        

        【讨论】:

          猜你喜欢
          • 2019-01-14
          • 1970-01-01
          • 2016-11-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-26
          • 1970-01-01
          相关资源
          最近更新 更多