54 votes

Comment renvoyer les résultats de Mongoose à partir de la méthode find ?

Tout ce que j'ai pu trouver pour rendre une page avec les résultats de la mangouste dit de le faire comme ceci :

users.find({}, function(err, docs){
    res.render('profile/profile', {
        users:     docs
    });
});

Comment pourrais-je retourner les résultats de la requête, plutôt comme ceci ?

var a_users = users.find({}); //non-working example

Pour que je puisse obtenir 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 ?

67voto

Josh Points 8217

Vous essayez de forcer un paradigme synchrone. Cela ne fonctionne pas. node.js est mono-threaded, pour la plupart -- quand io est fait, le contexte d'exécution est cédé. La signalisation est gérée par un callback. Cela signifie que vous avez soit des callbacks imbriqués, soit des fonctions nommées, soit une bibliothèque de contrôle de flux pour rendre les choses plus agréables à regarder.

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

19voto

bardzusny Points 3460

Je vais jouer le rôle du nécromancien ici, car je vois encore un autre moyen, meilleur, de le faire.

Utilisation de la bibliothèque des promesses merveilleuses Oiseau bleu et son promisifyAll() méthode :

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 principaux éléments sont les suivants :

Promise.promisifyAll(mongoose);

Rend toutes les méthodes de mongoose (et de ses modèles) disponibles en tant que fonctions retournant des promesses, avec Async suffixe ( .exec() devient .execAsync() et ainsi de suite). .promisifyAll() est presque universelle dans le monde Node.JS - vous pouvez l'utiliser sur tout ce qui fournit des fonctions asynchrones prenant un callback comme dernier argument.

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

.props() La méthode bluebird prend un objet avec des promesses comme propriétés, et renvoie une promesse collective qui est résolue lorsque les deux requêtes de base de données (ici - promesses) renvoient leurs résultats. La valeur résolue est notre results dans la fonction finale :

  • results.users - utilisateurs trouvés dans la base de données par la mangouste
  • results.articles - articles trouvés dans la base de données par la mangouste (d'uh)

Comme vous pouvez le constater, nous ne nous approchons même pas de l'enfer du rappel de l'indentation. Les deux requêtes de la base de données sont exécutées en parallèle - pas besoin pour l'une d'entre elles d'attendre l'autre. Le code est court et lisible - il correspond pratiquement en longueur et en complexité (ou plutôt en absence de complexité) à l'"exemple non fonctionnel" affiché dans la question elle-même.

Les promesses sont cool. Utilisez-les.

16voto

Oleg Shparber Points 1540

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. Tout comme la recherche de Mongoose. Et si vous voulez l'appeler en série, vous devez utiliser quelque chose comme Diapositive bibliothèque.

Mais dans votre cas, je pense que le plus simple est d'imbriquer des callbacks (ce qui permet par exemple de demander des articles pour des utilisateurs sélectionnés au préalable) ou de le faire de manière totalement parallèle à l'aide de bibliothèques asynchrones (cf. Contrôle de flux / Async goodies ).

1voto

Sten Muchow Points 1815

J'étais confronté à une situation très similaire, mais en utilisant socket.io et l'accès à la base de données depuis un client. Ma découverte était de renvoyer le contenu de ma base de données au client avant que la base de données n'ait eu la chance de recevoir les données... Donc, pour ce que ça vaut, je vais partager mes découvertes ici :

Ma fonction pour récupérer la BD :

//Lectures des planches - DB 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énements 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 la mangouste nous donne et 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...

1voto

Surender Singh Points 21

Vous obtenez le résultat souhaité avec le code suivant. J'espère que cela 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);
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X