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

marco de agregación mongodb coincide con documentos anidados

Consultar esta estructura para obtener los resultados que desea no es posible sin conocer todos los forms posibles nombres de antemano y usarlos en la consulta. Sería muy desordenado en cualquier caso. Dicho esto, sigue leyendo mientras explico cómo se puede hacer.

Hay un problema con la estructura de estos documentos que le impedirá realizar un análisis de consulta razonable. Tal como está, tendría que conocer todos los campos de nombre de formulario posibles para filtrar cualquier cosa.

Su estructura actual tiene formularios que contienen un subdocumento, de los cuales cada clave contiene otro subdocumento con una sola propiedad, status . Esto es difícil de atravesar ya que sus forms El elemento tiene una estructura arbitraria para cada documento que crea. Eso significa que el patrón para descender al status información que desea comparar cambios para cada documento en su colección.

Esto es lo que quiero decir con camino. Para obtener el estado en cualquier elemento, debe hacer lo siguiente

Con el segundo elemento cambiando todo el tiempo. No hay de ninguna manera a comodín algo como esto ya que el nombre se considera explícito.

Esto puede haber sido considerado una manera fácil de implementar la serialización de los datos de sus formularios pero veo un más flexible alternativa. Lo que necesita es una estructura de documento que pueda recorrer en un patrón estándar. Esto siempre es algo que vale la pena considerar en el diseño. Toma lo siguiente:

{
    "_id" : "Tvq444454j",
    "name": "Jim",
    "forms": [
        {
             "name": "Jorney",
             "status":"closed"          
        },
        {
            "name": "Women",
            "status":"void"            
        },
        {
            "name": "Child",
            "status":"closed"           
        },
        {
            "name": "Farm",
            "status":"closed"            
        }  
    ]
}

Entonces la estructura del documento se cambia para hacer los forms elemento una matriz, y en lugar de colocar el campo de estado debajo de una clave que nombra el "campo de formulario", tenemos cada miembro de la matriz como un subdocumento que contiene el "campo de formulario" name y el status . Entonces, tanto el identificador como el estado todavía están emparejados, pero ahora solo se representan como un subdocumento. Lo que es más importante, cambia la ruta de acceso a estas claves, ya que ahora para ambas el nombre del campo y su estado que podemos hacer

¿Qué esto significa que puede consultar para encontrar los nombres de todos los campos en el form o todo el status campos en el form , o incluso todos los documentos con un determinado name campo y cierto status . Eso es mucho mejor que lo que se podría hacer con la estructura original.

Ahora, en su caso particular, desea obtener solo los documentos donde todos los campos no son void . Ahora no hay forma de hacer esto en una sola consulta, ya que no hay un operador para comparar todos los elementos en una matriz de esta manera y ver si son iguales. Pero hay dos enfoques que puede tomar:

La primera, y probablemente no tan eficiente, es consultar todos documentos que contienen un elemento en forms que tiene un status de "vacío". Con los ID de documentos resultantes, puede emitir otra consulta que devuelva los documentos que no tener las identificaciones que se especificaron.

db.forms.find({ "forms.status": "void" },{ _id: 1})

db.forms.find({ _id: $not: { $in: [<Object1>,<Object2>,<Object3>,... ] } })

Dado el tamaño del resultado, esto puede no ser posible y generalmente no es una buena idea ya que el operador de exclusión $not básicamente está forzando un análisis completo de la colección, por lo que no podría usar un índice.

Otro enfoque es usar la canalización de agregación de la siguiente manera:

db.forms.aggregate([
    { "$unwind": "$forms" },
    { "$group": { "_id": "$_id", "status": { "$addToSet": "$forms.status" }}},
    { "$unwind": "$status" },
    { "$sort": { "_id": 1, "status": -1 }},
    { "$group": { "_id": "$_id", "status": { "$first": "$status"}}},
    { "$match":{ "status": "closed" }}
])

Por supuesto, eso solo devolverá el _id de los documentos que coincidan, pero puede emitir una consulta con $in y devolver todos los documentos coincidentes. Esto es mejor que el operador de exclusión que se usaba antes, y ahora podemos usar un índice para evitar escaneos completos de la colección.

Como enfoque final y para el mejor considerando el rendimiento, puede cambiar el documento nuevamente para que en el nivel superior mantenga el "estado" de si algún campo en los formularios está "vacío" o "cerrado". Entonces, en el nivel superior, el valor se cerraría solo si todos los elementos estuvieran "cerrados" y "anulados" si algo estuviera vacío, y así sucesivamente.

Ese último significaría un cambio programático adicional, y todos los cambios en los forms los elementos también tendrían que actualizar este campo para mantener el "estado". Sin embargo, es la forma más eficiente de encontrar los documentos que necesita y puede valer la pena considerarlo.

EDITAR :

Además de cambiar el documento para que tenga un estado maestro, el formulario de consulta más rápido en la estructura revisada es en realidad:

db.forms.find({ "forms": { "$not": { "$elemMatch": { "status": "void" } } } })