Как вернуть результаты Мангуста из метода find?
все, что я могу найти для рендинга страницы с результатами мангуста говорит, чтобы сделать это так:
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
- пользователи, найденные в базе данных Мангуст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; };
тогда у меня есть дополнительный параметр обратного вызова во всех подписей.
Я имел дело с очень похожей вещью, но используя socket.io и доступ к БД от клиента. Моя находка отбрасывала содержимое моей БД обратно клиенту, прежде чем база данных имела возможность получить данные... Так что для чего это стоит я поделюсь своими выводами здесь:
моя функция для извлечения ДБ:
/ / Read Boards-complete 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); });