如何从find方法返回Mongoose结果?

时间:2011-05-30 21:27:13

标签: mongodb node.js express mongoose

我能找到的用于渲染具有猫鼬结果的页面的所有内容都说是这样做的:

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

可以这样做吗?

6 个答案:

答案 0 :(得分:66)

您正在尝试强制使用同步范例。只是不工作。 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
});

答案 1 :(得分:20)

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

使用精彩的承诺库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方法接受带有promises作为其属性的对象,并返回在两个数据库查询(此处为promises)返回结果时解析的集合promise。已解析的值是最终函数中的results对象:

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

正如你所看到的,我们甚至没有接近缩进回调地狱。两个数据库查询都是并行执行的 - 不需要其中一个等待另一个。代码简短易读 - 在问题本身中张贴了如意的“非工作示例”,其长度和复杂性(或者说相当缺乏)几乎相应。

承诺很酷。使用它们。

答案 2 :(得分:16)

简单方法:

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中都是异步的。 Mongoose的发现也是如此。如果你想连续调用它,你应该使用类似Slide库的东西。

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

答案 3 :(得分:1)

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

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

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

答案 4 :(得分:1)

我正在处理一个非常类似的事情,但是使用来自客户端的socket.io和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);
        });
    });

所以为了解决这个问题,我们使用了mongoose给我们的承诺,然后一旦我们收到了来自DB的数据,我的套接字将它发回客户端......

它的价值......

答案 5 :(得分:1)

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

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