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

Cómo usar $regex dentro de $o como una expresión de agregación

Todo dentro de $expr es una expresión de agregación, y es posible que la documentación no "diga que no puede explícitamente" , pero la falta de cualquier operador con nombre y el problema de JIRA SERVER-11947 ciertamente decir eso. Entonces, si necesita una expresión regular, realmente no tiene otra opción que usar $where en cambio:

db.getCollection('permits').find({
  "$where": function() {
    var description = this.inspections
       .sort((a,b) => b.inspectionDate.valueOf() - a.inspectionDate.valueOf())
       .shift().description;

     return /^Found a .* at the property$/.test(description) ||
           description === "Health Inspection";

  }
})

Todavía puede usar $expr y expresiones de agregación para una coincidencia exacta, o simplemente mantenga la comparación dentro de $where de todos modos. Pero en este momento, las únicas expresiones regulares que entiende MongoDB son $regex dentro de una expresión "query" .

Si realmente "require" una expresión de canalización de agregación que le impide usar $where , entonces el único enfoque válido actual es primero "proyectar" el campo por separado de la matriz y luego $match con la expresión de consulta regular:

db.getCollection('permits').aggregate([
  { "$addFields": {
     "lastDescription": {
       "$arrayElemAt": [
         "$inspections.description",
         { "$indexOfArray": [
           "$inspections.inspectionDate",
           { "$max": "$inspections.inspectionDate" }
         ]}
       ]
     }
  }},
  { "$match": {
    "lastDescription": {
      "$in": [/^Found a .* at the property$/,/Health Inspection/]
    }
  }}
])

Lo que nos lleva al hecho de que parece estar buscando el elemento en la matriz con el valor de fecha máximo. La sintaxis de JavaScript debería dejar en claro que el enfoque correcto aquí es $sort la matriz en "actualizar". De esa forma, el "primer" elemento de la matriz puede ser el "más reciente". Y esto es algo que puede hacer con una consulta regular.

Para mantener el orden, asegúrese de agregar nuevos elementos a la matriz con $push y $sort así:

db.getCollection('permits').updateOne(
  { "_id": _idOfDocument },
  {
    "$push": {
      "inspections": {
        "$each": [{ /* Detail of inspection object */ }],
        "$sort": { "inspectionDate": -1 }
      }
    }
  }
)

De hecho, con un argumento de matriz vacío para $each an updateMany() actualizará todos sus documentos existentes:

db.getCollection('permits').updateMany(
  { },
  {
    "$push": {
      "inspections": {
        "$each": [],
        "$sort": { "inspectionDate": -1 }
      }
    }
  }
)

Estos realmente solo deberían ser necesarios cuando, de hecho, "altera" la fecha almacenada durante las actualizaciones, y esas actualizaciones se emiten mejor con bulkWrite() para hacer efectivamente "tanto" la actualización como la "clasificación" de la matriz:

db.getCollection('permits').bulkWrite([
  { "updateOne": {
    "filter": { "_id": _idOfDocument, "inspections._id": indentifierForArrayElement },
    "update": {
      "$set": { "inspections.$.inspectionDate": new Date() }
    }
  }},
  { "updateOne": {
    "filter": { "_id": _idOfDocument },
    "update": {
      "$push": { "inspections": { "$each": [], "$sort": { "inspectionDate": -1 } } }
    }
  }}
])

Sin embargo, si nunca "alteró" la fecha, probablemente tenga más sentido simplemente usar $position modificador y "pre-pend" a la matriz en lugar de "agregar", y evitando cualquier sobrecarga de un $sort :

db.getCollection('permits').updateOne(
  { "_id": _idOfDocument },
  { 
    "$push": { 
      "inspections": {
        "$each": [{ /* Detail of inspection object */ }],
        "$position": 0
      }
    }
  }
)

Con la matriz ordenada permanentemente o al menos construida para que la fecha "más reciente" sea siempre la "primera" entrada, entonces simplemente puede usar una expresión de consulta regular:

db.getCollection('permits').find({
  "inspections.0.description": { 
    "$in": [/^Found a .* at the property$/,/Health Inspection/]
  }
})

Entonces, la lección aquí es que no intentes forzar expresiones calculadas en tu lógica donde realmente no las necesitas. No debería haber ninguna razón convincente por la que no pueda ordenar el contenido de la matriz como "almacenado" para tener la "última fecha primera " , e incluso si pensó que necesitaba la matriz en cualquier otro orden, entonces probablemente debería sopesar qué caso de uso es más importante.

Una vez reordenado, incluso puede aprovechar un índice hasta cierto punto, siempre que las expresiones regulares estén ancladas al comienzo de la cadena o al menos algo más en la expresión de consulta haga una coincidencia exacta.

En el caso de que sienta que realmente no puede reordenar la matriz, entonces el $where query es su única opción presente hasta que se resuelva el problema de JIRA. Lo que, con suerte, es para la versión 4.1 según el objetivo actual, pero es más que probable que sea de 6 meses a un año en el mejor cálculo.