sql >> Database >  >> NoSQL >> MongoDB

Kan ik populate before aggregaat gebruiken in mangoest?

Nee, u kunt .populate() niet aanroepen voor .aggregate() , en er is een heel goede reden waarom u dat niet kunt. Maar er zijn verschillende benaderingen die u kunt volgen.

De .populate() methode werkt "client side" waar de onderliggende code daadwerkelijk aanvullende zoekopdrachten uitvoert (of beter gezegd een $in query ) om de gespecificeerde elementen uit de verzameling waarnaar wordt verwezen te "zoeken".

In tegenstelling .aggregate() is een bewerking aan de "serverzijde", dus u kunt in principe de inhoud "clientzijde" niet manipuleren en die gegevens later beschikbaar hebben voor de aggregatiepijplijnfasen. Het moet allemaal aanwezig zijn in de collectie waarop u werkt.

Een betere benadering is hier beschikbaar met MongoDB 3.2 en hoger, via de $lookup aggregatie pijplijn operatie. Waarschijnlijk ook het beste af te handelen vanaf de User collectie in dit geval om de selectie te verfijnen:

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

    }
)

Dit zal in feite een nieuw veld "score" bevatten binnen de User object als een "array" van items die bij "lookup" overeenkwamen met de andere collectie:

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

Het resultaat is altijd een array, aangezien het algemeen verwachte gebruik een "left join" is van een mogelijke "one to many"-relatie. Als er geen resultaat wordt gevonden, is het gewoon een lege array.

Om de inhoud te gebruiken, werkt u gewoon op welke manier dan ook met een array. U kunt bijvoorbeeld de $arrayElemAt gebruiken operator om het enige eerste element van de array in toekomstige bewerkingen te krijgen. En dan kun je de inhoud gewoon gebruiken zoals elk normaal ingesloten veld:

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

Als je MongoDB 3.2 niet beschikbaar hebt, is je andere optie om een ​​zoekopdracht te verwerken die wordt beperkt door de relaties van een andere collectie, eerst de resultaten van die collectie te krijgen en vervolgens $in om op de tweede te filteren:

// 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) {

        }
    );

});

Dus door de lijst met geldige gebruikers van de andere collectie naar de client te halen en die vervolgens in een query aan de andere collectie te geven, is dit de enige manier om dit in eerdere releases te laten gebeuren.




  1. Hoe maak je een afgetopte collectie met Spring Data? - MongoDB

  2. Verbinding geweigerd - connect(2) met rake db:seed op Mongodb

  3. Vreemde reactie bij het vinden van documenten in MongoDB met Mongoose in Node.js

  4. Kan redis.service niet starten:Eenheid redis-server.service is gemaskeerd