sql >> Base de Datos >  >> NoSQL >> MongoDB

¿Puedo usar poblar antes de agregar en mangosta?

No, no puedes llamar a .populate() antes de .aggregate() , y hay una muy buena razón por la que no puedes. Pero hay diferentes enfoques que puede tomar.

El .populate() El método funciona en el "lado del cliente", donde el código subyacente en realidad realiza consultas adicionales (o más exactamente, un $in query ) para "buscar" los elementos especificados de la colección a la que se hace referencia.

Por el contrario, .aggregate() es una operación del "lado del servidor", por lo que básicamente no puede manipular el contenido del "lado del cliente" y luego tener esos datos disponibles para las etapas de canalización de agregación más adelante. Todo debe estar presente en la colección en la que está operando.

Un mejor enfoque aquí está disponible con MongoDB 3.2 y versiones posteriores, a través del $lookup operación de tubería de agregación. Probablemente también sea mejor manejarlo desde el User colección en este caso para acotar la selección:

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

    }
)

Básicamente, esto incluirá un nuevo campo "puntuación" dentro del User objeto como una "matriz" de elementos que coincidieron en la "búsqueda" con la otra colección:

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

El resultado siempre es una matriz, ya que el uso general esperado es una "unión izquierda" de una posible relación "uno a muchos". Si no coincide ningún resultado, es solo una matriz vacía.

Para usar el contenido, simplemente trabaje con una matriz de cualquier manera. Por ejemplo, puede usar $arrayElemAt operador para obtener solo el primer elemento de la matriz en cualquier operación futura. Y luego puede usar el contenido como cualquier campo incrustado normal:

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

Si no tiene MongoDB 3.2 disponible, entonces su otra opción para procesar una consulta limitada por las relaciones de otra colección es obtener primero los resultados de esa colección y luego usar $in para filtrar en el segundo:

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

        }
    );

});

Por lo tanto, obtener la lista de usuarios válidos de la otra colección para el cliente y luego enviarla a la otra colección en una consulta es la única forma de lograr que esto suceda en versiones anteriores.