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

Comment trouver dans mongodb le dernier élément d'un tableau ?

Je sais que cette question est ancienne, mais je l'ai trouvée sur Google après avoir répondu à une nouvelle question similaire . J'ai donc pensé que cela méritait le même traitement.

Vous pouvez éviter l'impact sur les performances de $where en utilisant aggregate à la place :

db.example.aggregate([

    // Use an index, which $where cannot to narrow down
    {$match: { "comments.by": "Abe" }},

    // De-normalize the Array
    {$unwind: "$comments"},

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

    // Match only where that $last comment by `by.Abe`
    {$match: { "comments.by": "Abe" }},

    // Retain the original _id order
    {$sort: { _id: 1 }}

])

Et cela devrait tourner autour de $where puisque nous avons pu affiner les documents qui avaient un commentaire de "Abe" en premier lieu. Comme averti, $where va tester chaque document de la collection et ne jamais utiliser d'index même s'il y en a un pour être utilisé.

Bien sûr, vous pouvez également conserver le document original en utilisant la technique décrite ici ainsi, tout fonctionnerait comme un find() .

Juste matière à réflexion pour quiconque trouve cela.

Mise à jour pour les versions modernes de MongoDB

Les versions modernes ont ajouté le $redact expression de pipeline ainsi que $arrayElemAt (ce dernier à partir de 3.2, donc ce serait la version minimale ici) qui, en combinaison, permettrait à une expression logique d'inspecter le dernier élément d'un tableau sans traiter un $unwind étape :

db.example.aggregate([
  { "$match": { "comments.by": "Abe" }},
  { "$redact": {
    "$cond": {
      "if": {
        "$eq": [
          { "$arrayElemAt": [ "$comments.by", -1 ] },
          "Abe"
        ]
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

La logique ici est faite en comparaison où $arrayElemAt obtient le dernier index du tableau -1 , qui est transformé en un simple tableau des valeurs dans le "by" propriété via $map . Cela permet de comparer la valeur unique avec le paramètre requis, "Abe" .

Ou même un peu plus moderne en utilisant $expr pour MongoDB 3.6 et supérieur :

db.example.find({
  "comments.by": "Abe",
  "$expr": {
    "$eq": [
      { "$arrayElemAt": [ "$comments.by", -1 ] },
      "Abe"
    ]
  }
})

Ce serait de loin la solution la plus performante pour faire correspondre le dernier élément d'un tableau, et devrait en fait remplacer l'utilisation de $where dans la plupart des cas et surtout ici.