MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Puis-je utiliser le peuplement avant l'agrégation dans la mangouste ?

Non, vous ne pouvez pas appeler .populate() avant .aggregate() , et il y a une très bonne raison pour laquelle vous ne pouvez pas. Mais vous pouvez adopter différentes approches.

Le .populate() la méthode fonctionne "côté client" où le code sous-jacent effectue réellement des requêtes supplémentaires (ou plus précisément un $in query ) pour "rechercher" le ou les éléments spécifiés dans la collection référencée.

En revanche .aggregate() est une opération "côté serveur", vous ne pouvez donc pas manipuler le contenu "côté client", puis mettre ces données à la disposition des étapes du pipeline d'agrégation ultérieurement. Tout doit être présent dans la collection sur laquelle vous travaillez.

Une meilleure approche ici est disponible avec MongoDB 3.2 et versions ultérieures, via le $lookup fonctionnement du pipeline d'agrégation. Également probablement préférable de gérer à partir de l'User collection dans ce cas afin d'affiner la sélection :

User.aggregate(
    [
        // Filter first
        { "$match": {
            "age": { "$gt": 20 } 
        }},
        // Then join
        { "$lookup": {
            "from": "scores",
            "localField": "userID",
            "foriegnField": "userID",
            "as": "score"
        }},
        // More stages
    ],
    function(err,results) {

    }
)

Cela va essentiellement inclure un nouveau champ "score" dans le User objet sous la forme d'un "tableau" d'éléments qui correspondent lors de la "recherche" à l'autre collection :

{
    "userID": "abc",
    "age": 21,
    "score": [{
        "userID": "abc",
        "score": 42,
        // other fields
    }]
}

Le résultat est toujours un tableau, car l'utilisation générale attendue est une "jointure gauche" d'une possible relation "un à plusieurs". Si aucun résultat ne correspond, il s'agit simplement d'un tableau vide.

Pour utiliser le contenu, travaillez simplement avec un tableau de quelque manière que ce soit. Par exemple, vous pouvez utiliser le $arrayElemAt afin d'obtenir uniquement le premier élément unique du tableau dans toutes les opérations futures. Et ensuite, vous pouvez simplement utiliser le contenu comme n'importe quel champ intégré normal :

        { "$project": {
            "userID": 1,
            "age": 1,
            "score": { "$arrayElemAt": [ "$score", 0 ] }
        }}

Si vous ne disposez pas de MongoDB 3.2, votre autre option pour traiter une requête limitée par les relations d'une autre collection consiste à obtenir d'abord les résultats de cette collection, puis à utiliser $in pour filtrer sur la seconde :

// Match the user collection
User.find({ "age": { "$gt": 20 } },function(err,users) {

    // Get id list      
    userList = users.map(function(user) {
       return user.userID;
    });

    Score.aggregate(
        [ 
            // use the id list to select items
            { "$match": {
                "userId": { "$in": userList }
            }},
            // more stages
        ],
        function(err,results) {

        }
    );

});

Ainsi, en obtenant la liste des utilisateurs valides de l'autre collection au client, puis en la transmettant à l'autre collection dans une requête, c'est le seul moyen d'obtenir cela dans les versions antérieures.