Tout ce que je peux trouver pour rendre une page avec des résultats de mangouste dit de le faire comme ceci:
users.find({}, function(err, docs){
res.render('profile/profile', {
users: docs
});
});
Comment pourrais-je renvoyer les résultats de la requête, plutôt comme ceci?
var a_users = users.find({}); //non-working example
Pour que je puisse avoir plusieurs résultats à publier sur la page?
comme:
/* non working example */
var a_users = users.find({});
var a_articles = articles.find({});
res.render('profile/profile', {
users: a_users
, articles: a_articles
});
Cela peut-il être fait?
Vous essayez de forcer un paradigme synchrone. Ça ne marche pas. node.js est, pour la plupart, à un seul thread: lorsque io est terminé, le contexte d'exécution est généré. La signalisation est gérée avec un rappel. Cela signifie que vous avez des rappels imbriqués, des fonctions nommées ou une bibliothèque de contrôle de flux pour rendre les choses plus agréables.
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
});
Je vais jouer le nécromancien ici, car je vois encore une autre meilleure façon de le faire.
Utilisation de la merveilleuse bibliothèque de promesses Bluebird et de sa méthode 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!
});
Les parties clés sont les suivantes:
Promise.promisifyAll(mongoose);
Rend toutes les méthodes mangouste (et ses modèles) disponibles sous forme de fonctions renvoyant des promesses, avec le suffixe Async
(.exec()
devient .execAsync()
, etc.). La méthode .promisifyAll()
est presque universelle dans le monde Node.JS - vous pouvez l'utiliser sur tout ce qui fournit des fonctions asynchrones prenant le rappel comme dernier argument.
Promise.props({
users: users.find().execAsync(),
articles: articles.find().execAsync()
})
.props()
La méthode bluebird prend les propriétés d'un objet avec des promesses et renvoie une promesse collective qui est résolue lorsque les deux requêtes de base de données (ici - les promesses) renvoient leurs résultats. La valeur résolue est notre objet results
dans la fonction finale:
results.users
- utilisateurs trouvés dans la base de données par mangousteresults.articles
- articles trouvés dans la base de données par mangouste (d'uh)Comme vous pouvez le constater, nous ne nous approchons même pas de l'enfer de rappel d'indentation. Les deux requêtes de base de données sont exécutées en parallèle. Inutile d'attendre l'une d'elles pour l'autre. Le code est court et lisible - correspondant pratiquement en longueur et en complexité (ou plutôt en son absence) à un "exemple non exploitant" affiché dans la question elle-même.
Les promesses sont cool. Utilise les.
Le moyen le plus simple:
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
});
});
});
Pratiquement toutes les fonctions sont asynchrones dans Node.js. Ainsi est la découverte de Mongoose. Et si vous voulez l'appeler en série, vous devriez utiliser quelque chose comme Slide library.
Mais dans votre cas, je pense que le moyen le plus simple consiste à imbriquer des rappels (cela permet, par exemple, de rechercher des articles pour certains utilisateurs précédemment sélectionnés) ou de le faire complètement en parallèle avec l’aide de bibliothèques asynchrones (voir Contrôle de flux/Goodies Async ).
J'ai une fonction que j'utilise un peu comme retour à Node fonctions.
function freturn (value, callback){
if(callback){
return callback(value);
}
return value;
};
Ensuite, j'ai un paramètre de rappel facultatif dans toutes les signatures.
J'avais affaire à une chose très similaire mais en utilisant socket.io et l'accès à la base de données depuis un client. Ma découverte renvoyait le contenu de ma base de données au client avant que la base de données ne puisse obtenir les données ... Donc, pour ce que cela vaut, je vais partager mes conclusions ici:
Ma fonction pour récupérer la base de données:
// Lire les tableaux - Base de données complète
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());
};
Mon écouteur d'événement de socket:
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);
});
});
Donc, pour résoudre le problème, nous utilisons la promesse que nous a donnée Mangouste, puis une fois que nous avons reçu les données de la base de données, mon socket les renvoie au client ...
Pour ce que ça vaut ...
Vous obtenez le résultat souhaité avec le code suivant. J'espère que ceci vous aidera.
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);
});