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

Uso de agregación para ordenar en condicional complejo en Mongodb

Primero, tenga en cuenta que su ejemplo de clasificación tiene un formato incorrecto:el método agregado toma una matriz como entrada, donde cada elemento de la matriz especifica una etapa en una canalización de agregación. Además, tenga en cuenta que $elemMatch El operador no se puede usar como parte de una etapa $sort.

Una forma de lograr lo que está tratando de hacer con su ejemplo de clasificación es usar el marco de agregación $relajarse operador de tubería Al desenrollar una matriz, se despegarán los elementos de la matriz uno por uno en documentos separados. Por ejemplo, la siguiente consulta

db.my_collection.aggregate([ {$unwind: "$answers"} ]);

devuelve algo como lo siguiente:

[
    {
        "_id" : ObjectId("5237157f3fac8e36fdb0b96e"),
        "user" : "bruno",
        "answers" : {
            "id" : 0,
            "value" : 3.5
        }
    },
    {
        "_id" : ObjectId("5237157f3fac8e36fdb0b96e"),
        "user" : "bruno",
        "answers" : {
            "id" : 1,
            "value" : "hello"
        }
    },
    {
        "_id" : ObjectId("523715813fac8e36fdb0b96f"),
        "user" : "bruno2",
        "answers" : {
            "id" : 0,
            "value" : 0.5
        }
    },
    {
        "_id" : ObjectId("523715813fac8e36fdb0b96f"),
        "user" : "bruno2",
        "answers" : {
            "id" : 1,
            "value" : "world"
        }
    }
]

Agregar una fase de coincidencia de $ le permitirá tomar solo los documentos donde answers.id es cero. Finalmente, una fase $sort le permite ordenar por respuestas.valor. En total, la consulta de agregación es:

db.my_collection.aggregate([
    {$unwind: "$answers"},
    {$match: {"answers.id": 0}},
    {$sort: {"answers.value": -1}}
]);

Y la salida:

[
    {
        "_id" : ObjectId("5237157f3fac8e36fdb0b96e"),
        "user" : "bruno",
        "answers" : {
            "id" : 0,
            "value" : 3.5
        }
    },
    {
        "_id" : ObjectId("523715813fac8e36fdb0b96f"),
        "user" : "bruno2",
        "answers" : {
            "id" : 0,
            "value" : 0.5
        }
    }
]

Según lo que está preguntando, no parece que siempre necesite $ unwind o incluso el marco de agregación. Si, en cambio, quisiera encontrar el documento con respuestas.id igual a 0 y respuestas.valor igual a 3.5, y luego cambiar respuestas.valor a 4, podría usar find con $elemMatch seguido de db.collection.save():

doc = db.my_collection.findOne({"answers": {$elemMatch: {"id": 0, "value": 3.5}}});
for (i=0; i<doc.answers.length; i++) {
  if (doc.answers[i].id === 0) {
    doc.answers[i].value = 4;
    db.my_collection.save(doc);
    break;
  }
}