Как вернуть результаты Mongoose из метода find? - PullRequest
55 голосов
/ 31 мая 2011

Все, что я могу найти для перерисовки страницы с результатами 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 ]

67 голосов
/ 31 мая 2011

Вы пытаетесь навязать синхронную парадигму.Просто не работает.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
});
20 голосов
/ 26 апреля 2015

Я сыграю здесь некроманта, так как я все еще вижу другой, лучший способ сделать это.

Использование замечательной библиотеки обещаний 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 (и их модели) доступными как функции, возвращающие обещания, с суффиксом Async (.exec() становится .execAsync() и т. Д.). .promisifyAll() метод является почти универсальным в мире Node.JS - вы можете использовать его для всего, что обеспечивает асинхронные функции, принимающие обратный вызов в качестве последнего аргумента.

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

.props() Метод bluebird принимает объект с обещаниями в качестве его свойств и возвращает коллективное обещание, которое разрешается, когда оба запроса базы данных (здесь - обещания) возвращают свои результаты. Разрешенное значение - это наш results объект в конечной функции:

  • results.users - пользователи, найденные в базе данных пользователем mongoose
  • results.articles - статьи, найденные в базе данных mongoose (d'uh)

Как видите, мы даже не приближаемся к аду обратного вызова отступа. Оба запроса к базе данных выполняются параллельно - нет необходимости, чтобы один из них ждал другого. Код короткий и читаемый - практически соответствующий по длине и сложности (или, скорее, его отсутствия) желаемому «нерабочему примеру», опубликованному в самом вопросе.

Обещания классные. Используйте их.

16 голосов
/ 31 мая 2011

Простой способ:

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.

Но в вашем случае я думаю, что самый простой способ - это вложить обратные вызовы (это позволяет запрашивать статьи для выбранных ранее пользователей) или делать это полностью параллельно с помощью асинхронных библиотек (см. Управление потоком данных / Асинхронные вкусности ).

1 голос
/ 24 июня 2018

Вы достигнете желаемого результата с помощью следующего кода. Надеюсь, это поможет вам.

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);
});
1 голос
/ 23 апреля 2013

Я имел дело с очень похожей вещью, но использовал socket.io и доступ к БД с клиента. Моя находка возвращала содержимое моей БД клиенту до того, как у базы была возможность получить данные ... Итак, для чего это стоит, я поделюсь своими выводами здесь:

Моя функция для извлечения БД:

// Чтение Доски - полная БД

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, а затем, как только мы получаем данные из БД, мой сокет отправляет их обратно клиенту ...

Для чего это стоит ...

1 голос
/ 28 января 2013

У меня есть функция, которую я немного использую в качестве возврата к функциям Node.

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

Тогда у меня есть необязательный параметр обратного вызова во всех сигнатурах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...