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

Usando el operador $slice para obtener el último elemento de la matriz

Como ya sabrá, $slice solo se usa en la proyección para limitar los elementos de la matriz devueltos en los resultados. Por lo tanto, tendría que procesar la lista mediante programación con los resultados de un find().

Un mejor enfoque es usar agregados. Pero primero consideremos cómo $slice se usa:

> db.collection.find({},{ relevancy: {$slice: -1} })
{ "_id" : ObjectId("530824b95f44eac1068b45c0"), "relevancy" : [  "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c2"), "relevancy" : [  "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c3"), "relevancy" : [  "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c4"), "relevancy" : [  "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c6"), "relevancy" : [  "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c7"), "relevancy" : [  "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c8"), "relevancy" : [  "N" ] }

Así que obtienes el último elemento de la matriz, pero te quedas atascado con el bucle de resultados ya que no puedes coincidir el último valor del elemento. También podría haber hecho esto en código.

Ahora echemos un vistazo a agregado :

db.collection.aggregate([
    // Match things so we get rid of the documents that will never match, but it will
    // still keep some of course since they are arrays, that *may* contain "N"
    { "$match": { "relevancy": "Y" } },

    // De-normalizes the array
    { "$unwind": "$relevancy" },

    // The order of the array is retained, so just look for the $last by _id
    { "$group": { "_id": "$_id", "relevancy": { "$last": "$relevancy" } }},

    // Match only the records with the results you want
    { "$match": { "relevancy": "Y" }},

    // Oh, and maintain the original _id order [ funny thing about $last ]
    { "$sort": { "_id": 1 } }
])

Incluso si este fuera su primer uso de added(), lo animo a aprenderlo. . Es quizás su herramienta de resolución de problemas más útil. Sin duda lo ha sido para mí. Ponga cada paso en una vez a la vez si estás aprendiendo.

Tampoco estoy seguro en el formulario de su documento, todos los 1: { ... } la notación del subdocumento parece ser un error, pero debe aclararlo o ajustar el código anterior para hacer referencia a "1.relevancy" en cambio. Sin embargo, espero que sus documentos se parezcan más a esto:

{ "relevancy" : [  "Y" ] , "_id" : ObjectId("530824b95f44eac1068b45c0") }
{ "relevancy" : [  "Y",  "Y" ] , "_id" : ObjectId("530824b95f44eac1068b45c2") }
{ "relevancy" : [  "N" ], "_id" : ObjectId("530824b95f44eac1068b45c3") }
{ "relevancy" : [  "Y",  "Y" ], "_id" : ObjectId("530824b95f44eac1068b45c4") }
{ "relevancy" : [  "Y",  "N" ], "_id" : ObjectId("530824b95f44eac1068b45c6") }
{ "relevancy" : [  "N" ], "_id" : ObjectId("530824b95f44eac1068b45c7") }
{ "relevancy" : [  "Y",  "N" ], "_id" : ObjectId("530824b95f44eac1068b45c8") }

MongoDB 3.2.x y superior

Por supuesto, MongoDB 3.2 introduce un operador de "agregación" para $slice y un $arrayElemAt aún mejor operador que elimina la necesidad de cualquier $unwind y $group Procesando. Después del $match inicial consulta, simplemente haga una "coincidencia lógica" con $redact :

db.collection.aggregate([
    { "$match": { "relevancy": "Y" } },
    { "$redact": {
        "$cond": {
            "if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }}   
])

Eso hará la inspección en el último elemento de la matriz al decidir si $$KEEP o $$PRUNE los documentos de los resultados devueltos.

Si aún desea la "proyección", puede agregar el $slice :

db.collection.aggregate([
    { "$match": { "relevancy": "Y" } },
    { "$redact": {
        "$cond": {
            "if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }},
    { "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } }
])

O el enfoque alternativo de:

db.collection.aggregate([
    { "$match": { "relevancy": "Y" } },
    { "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } },
    { "$match": { "relevancy": "Y" } }
])

Pero probablemente sea menos costoso hacer el $redact primero y "luego" hacen cualquier cambio de forma en `$project.