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

Problemas con el marco de agregación de SailsJS y MongoDB con consultas personalizadas

Su primera consulta estaba en el camino correcto cuando estaba usando el operador de canalización incorrecto.

Artist.native(function(err,collection) {

    collection.aggregate(
        [
            { "$project": {
                "_id": 1,
                "name": 1,
                "total": { "$size": "$dubs" }
            }}
        ],
        function(err,result) {
          if (err) return res.serverError(err);
          console.log(result);
        }
})

Por supuesto, el $size El operador allí requiere que necesite una versión MongoDB 2.6 o superior, lo que probablemente ya debería hacer, pero aún puede hacer lo mismo sin el operador para medir la longitud de la matriz:

Artist.native(function(err,collection) {

    collection.aggregate(
        [
            { "$project": {
                "_id": 1,
                "name": 1,
                "dubs": {
                    "$cond": [
                       { "$eq": [ "$dubs", [] ] },
                       [0],
                       "$dubs"
                    ]
                }
            }},
            { "$unwind": "$dubs" },
            { "$group": {
                "_id": "$_id",
                "name": { "$first": "$name" },
                "total": { 
                    "$sum": {
                        "$cond": [
                            { "$eq": [ "$dubs", 0 ] },
                            0,
                            1
                        ]
                    }
                }
            }}
        ],
        function(err,result) {
          if (err) return res.serverError(err);
          console.log(result);
        }
})

Eso hace lo mismo al contar los miembros de la matriz, pero en su lugar necesitaría $unwind los elementos de la matriz para contarlos. Por lo tanto, todavía se puede hacer, pero no es tan eficiente.

Además, debe manejar los casos en los que la matriz está realmente en blanco pero presente debido a cómo $unwind trata una matriz vacía [] . Si no hubiera contenido, el documento que contenía dicho elemento se eliminaría de los resultados. De manera similar, necesitaría usar $ifNull para establecer una matriz donde el documento ni siquiera contenía un elemento para $unwind para no resultar en un error.

Realmente, si tiene la intención de realizar este tipo de consulta de forma regular, debe mantener un campo "total" en el documento en lugar de intentar calcularlo primero. Use el $inc operador junto con operaciones como $push y $pull para llevar la cuenta de la longitud actual de la matriz.

Eso se aleja un poco de la filosofía general de Waterline, pero ya ha introducido operaciones de agregación nativas y no es mucho más difícil darse cuenta de que está obteniendo un mejor rendimiento al usar operaciones nativas también en otras áreas.

Así que con documentos como estos:

{
  "dubs": [{},{},{}],
  "name": "The Doors",
  "createdAt": "2014-12-15T15:24:26.216Z",
  "updatedAt": "2014-12-15T15:24:26.216Z",
  "id": "548efd2a436c850000353f4f"
},
{
  "dubs": [],
  "name": "The Beatles",
  "createdAt": "2014-12-15T20:30:33.922Z",
  "updatedAt": "2014-12-15T20:30:33.922Z",
  "id": "548f44e90630d50000e2d61d"
}

Obtiene exactamente los resultados que desea en cada caso:

{
    "_id" : ObjectId("5494b79d7e22da84d53c8760"),
    "name" : "The Doors",
    "total" : 3
},
{
    "_id" : ObjectId("5494b79d7e22da84d53c8761"),
    "name" : "The Beatles",
    "total" : 0
}