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

¿Cómo encontrar en mongodb el último elemento de una matriz?

Sé que esta pregunta es antigua, pero la encontré en Google después de responder una nueva pregunta similar . Así que pensé que esto merecía el mismo tratamiento.

Puede evitar el impacto en el rendimiento de $where mediante el uso de agregar en cambio:

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

])

Y eso debería dar vueltas alrededor de $where ya que pudimos acotar los documentos que tenían un comentario de "Abe" en primer lugar. Como se advirtió, $where va a probar todos los documentos de la colección y nunca usará un índice, incluso si hay uno para usarlo.

Por supuesto, también puede mantener el documento original usando la técnica descrita aquí también, por lo que todo funcionaría como un find() .

Solo algo de reflexión para cualquiera que encuentre esto.

Actualización para versiones modernas de MongoDB

Las versiones modernas han agregado el $redact expresión de canalización, así como $arrayElemAt (este último a partir de 3.2, por lo que sería la versión mínima aquí) que en combinación permitiría una expresión lógica para inspeccionar el último elemento de una matriz sin procesar un $unwind etapa:

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

La lógica aquí se hace en comparación donde $arrayElemAt está obteniendo el último índice de la matriz -1 , que se transforma en solo una matriz de los valores en "by" propiedad a través de $map . Esto permite la comparación del valor único con el parámetro requerido, "Abe" .

O incluso un poco más moderno usando $expr para MongoDB 3.6 y superior:

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

Esta sería, con mucho, la solución de mayor rendimiento para hacer coincidir el último elemento dentro de una matriz, y en realidad se espera que reemplace el uso de $where en la mayoría de los casos y especialmente aquí.