MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Utilisation de l'opérateur $slice pour obtenir le dernier élément du tableau

Comme vous le savez maintenant, $slice n'est utilisé dans la projection que pour limiter les éléments de tableau renvoyés dans les résultats. Vous seriez donc obligé de traiter la liste par programmation avec les résultats d'un find().

Une meilleure approche consiste à utiliser des agrégats. Mais voyons d'abord comment $slice est utilisé :

> 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" ] }

Donc, vous obtenez le dernier élément du tableau, mais vous êtes coincé avec la boucle des résultats car vous ne pouvez pas faire correspondre la dernière valeur de l'élément. Vous auriez aussi bien pu le faire dans le code.

Regardons maintenant agrégé :

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 } }
])

Même s'il s'agit de votre première utilisation d'aggregate(), je vous encourage à l'apprendre . C'est peut-être votre outil de résolution de problèmes le plus utile. a certainement été pour moi. Mettez chaque étape une fois à la fois si vous apprenez.

Pas sûr non plus sur votre formulaire de document, tous les 1: { ... } la notation du sous-document semble être une erreur, mais vous devez clarifier cela ou ajuster le code ci-dessus pour référencer "1.relevancy" Au lieu. J'espère que vos documents ressembleront davantage à ceci :

{ "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 et versions ultérieures

Bien entendu MongoDB 3.2 introduit un opérateur "d'agrégation" pour $slice et un $arrayElemAt encore meilleur opérateur qui supprime le besoin de tout $unwind et $group En traitement. Après le $match initial requête vous venez de faire une "correspondance logique" avec $redact :

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

Cela va faire l'inspection sur le dernier élément du tableau lors de la décision de $$KEEP ou $$PRUNE les documents des résultats retournés.

Si vous vouliez toujours la "projection", vous pouvez en fait ajouter le $slice :

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

Ou l'approche alternative de :

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

Mais est probablement moins coûteux de faire le $redact d'abord et "ensuite" faire tout remodelage dans `$project.