Как вернуть результаты Мангуста из метода 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);
});