MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Come trovare in mongodb l'ultimo elemento di un array?

So che questa domanda è vecchia, ma l'ho trovata su Google dopo aver risposto a una nuova domanda simile . Quindi ho pensato che questo meritasse lo stesso trattamento.

Puoi evitare il calo delle prestazioni di $where utilizzando aggregato invece:

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

])

E questo dovrebbe girare intorno a $dove dal momento che siamo stati in grado di restringere i documenti che aveva un commento di "Abe" in primo luogo. Come avvertito, $dove testerà tutti i documenti della raccolta e non utilizzerà mai un indice anche se è lì per essere utilizzato.

Naturalmente, puoi anche mantenere il documento originale utilizzando la tecnica descritta qui inoltre, quindi tutto funzionerebbe proprio come un find() .

Solo spunto di riflessione per chiunque lo trovi.

Aggiornamento per le versioni Modern MongoDB

Le versioni moderne hanno aggiunto $redact espressione della pipeline nonché $arrayElemAt (quest'ultimo a partire dalla 3.2, quindi sarebbe la versione minima qui) che in combinazione consentirebbe a un'espressione logica di ispezionare l'ultimo elemento di un array senza elaborare un $unwind fase:

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

La logica qui viene eseguita rispetto a $arrayElemAt sta ottenendo l'ultimo indice dell'array -1 , che viene trasformato in un semplice array di valori nel "by" proprietà tramite $map . Ciò consente il confronto del singolo valore con il parametro richiesto, "Abe" .

O anche un po' più moderno usando $expr per MongoDB 3.6 e versioni successive:

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

Questa sarebbe di gran lunga la soluzione più efficace per abbinare l'ultimo elemento all'interno di un array e in realtà dovrebbe sostituire l'uso di $where nella maggior parte dei casi e soprattutto qui.