sql >> Database >  >> NoSQL >> MongoDB

Hoe vind je in mongodb naar het laatste item van een array?

Ik weet dat deze vraag oud is, maar ik vond hem op Google na het beantwoorden van een vergelijkbare nieuwe vraag . Dus ik dacht dat dit dezelfde behandeling verdiende.

U kunt de prestatiehit van $where vermijden door gebruik te maken van aggregaat in plaats daarvan:

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

])

En dat zou moeten draaien rond $where omdat we de documenten konden beperken die had een opmerking van "Abe" in de eerste plaats. Zoals gewaarschuwd, $where gaat elk document in de collectie testen en nooit een index gebruiken, ook al is er een om te gebruiken.

Natuurlijk kunt u het originele document ook behouden met behulp van de techniek die hier wordt beschreven ook, dus alles zou werken als een find() .

Gewoon stof tot nadenken voor iedereen die dit vindt.

Update voor moderne MongoDB-releases

Moderne releases hebben de $redact toegevoegd pijplijnexpressie evenals $arrayElemAt ( de laatste vanaf 3.2, dus dat zou hier de minimale versie zijn ) die in combinatie een logische expressie in staat zou stellen om het laatste element van een array te inspecteren zonder een $unwind stadium:

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

De logica hier wordt gedaan in vergelijking waar $arrayElemAt krijgt de laatste index van de array -1 , die wordt omgezet in slechts een array van de waarden in de "by" eigendom via $map . Hierdoor kan de enkele waarde worden vergeleken met de vereiste parameter, "Abe" .

Of zelfs een beetje moderner met $expr voor MongoDB 3.6 en hoger:

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

Dit zou verreweg de meest performante oplossing zijn voor het matchen van het laatste element binnen een array, en zou eigenlijk het gebruik van $where in de meeste gevallen en vooral hier.



  1. MongoDB 4.0-transacties:ACID lezen + schrijven?

  2. Zijn redis-bewerkingen op threads van datastructuren veilig?

  3. Hoe MongoDB op Heroku . te implementeren

  4. Array-object bijwerken op basis van id?