Как вернуть результаты Мангуста из метода find?

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


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

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

используя замечательную библиотеку обещаний птица и 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);

делает все методы мангуста (и его модели) доступными в качестве функций, возвращающих обещания, с Async суффикс (.exec() становится .execAsync() и так далее). .promisifyAll() метод почти универсален в узле.JS world - вы можете использовать его на всем, что предоставляет асинхронные функции, принимающие обратный вызов в качестве последнего аргумента.

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

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

  • results.users - пользователи, найденные в базе данных Мангуст!--30-->
  • results.articles - статьи, найденные в базе данных мангустом (d'UH)

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

обещания-это круто. Использовать их.


самый простой способ:

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

практически каждая функция асинхронна в узле.js. Как и находка Мангуста. И если вы хотите назвать его последовательно, вы должны использовать что-то вроде скольжения библиотека.

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


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

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

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


Я имел дело с очень похожей вещью, но с использованием сокета.доступ к 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);
        });
    });

Так для того чтобы разрешить проблему мы используем обещание этот Мангуст дает нам, а затем, как только мы получили данные из БД, мой сокет отправляет их обратно клиенту...

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


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

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