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

corrispondenza del framework di aggregazione mongodb per documenti nidificati

Non è possibile interrogare questa struttura per i risultati desiderati senza conoscere tutti i possibili forms nomi in anticipo e utilizzarli nella query. Sarebbe comunque molto disordinato. Detto questo, continua a leggere mentre spiego come si può fare.

C'è un problema con la struttura di questi documenti che ti impedirà di eseguire qualsiasi ragionevole analisi delle query. Allo stato attuale dovresti conoscere tutti i possibili campi del nome del modulo per filtrare qualsiasi cosa.

La tua struttura attuale ha moduli contenenti un sottodocumento, di cui ogni chiave contiene un altro sottodocumento con una singola proprietà, status . Questo è difficile da attraversare come i tuoi forms element ha una struttura arbitraria per ogni documento che crei. Ciò significa che il modello per discendere allo status informazioni che desideri confrontare le modifiche per ogni documento nella tua raccolta.

Ecco cosa intendo per percorso. Per ottenere lo stato in qualsiasi elemento devi fare quanto segue

Con il secondo elemento che cambia continuamente. Non c'è nessun modo a carattere jolly qualcosa del genere poiché la denominazione è considerata esplicita.

Questo potrebbe essere stato considerato un modo semplice per implementare la serializzazione dei dati dai tuoi moduli ma ne vedo una più flessibile alternativa. Ciò di cui hai bisogno è una struttura del documento che puoi attraversare secondo uno schema standard. Questo è sempre qualcosa che vale la pena considerare nel design. Prendi quanto segue:

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

Quindi la struttura del documento viene modificata per creare i forms elemento un Array, e invece di posizionare il campo di stato sotto una chiave che denomina il "campo modulo", abbiamo ogni membro dell'Array come sottodocumento contenente il "campo modulo" name e lo status . Quindi sia l'identificatore che lo stato sono ancora accoppiati ma ora rappresentati solo come un documento secondario. Questo cambia soprattutto il percorso di accesso a queste chiavi, come ora per entrambe il nome del campo e il suo stato possiamo fare

Cosa questo significa che puoi interrogare per trovare i nomi di tutti i campi nel form o tutto lo status campi nel form , o anche tutti i documenti con un certo name campo e un determinato status . Questo è molto meglio di quanto si potrebbe fare con la struttura originale.

Ora, nel tuo caso particolare, vuoi ottenere solo i documenti dove tutti i campi non sono void . Ora non c'è modo in una singola query per farlo poiché non esiste un operatore per confrontare tutti gli elementi in un array in questo modo e vedere se sono gli stessi. Ma ci sono due approcci che puoi adottare:

Il primo e probabilmente non altrettanto efficiente è eseguire una query per tutti documenti che contengono un elemento in forms che ha uno status di "vuoto". Con gli ID del documento risultanti puoi emettere un'altra query che restituisce i documenti che non avere gli ID specificati.

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

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

Data la dimensione del risultato, ciò potrebbe non essere possibile e generalmente non è una buona idea poiché l'operatore di esclusione $not fondamentalmente sta forzando una scansione completa della raccolta, quindi non puoi utilizzare un indice.

Un altro approccio consiste nell'utilizzare la pipeline di aggregazione come segue:

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" }}
])

Ovviamente ciò restituirà solo _id per i documenti che corrispondono, ma puoi inviare una query con $in e restituire tutti i documenti corrispondenti. Questo è migliore dell'operatore di esclusione utilizzato in precedenza e ora possiamo utilizzare un indice per evitare scansioni complete della raccolta.

Come approccio finale e per il meglio considerazione delle prestazioni, è possibile modificare nuovamente il documento in modo che al livello più alto si mantenga lo "stato" se un qualsiasi campo nei moduli è "vuoto" o "chiuso". Quindi al livello più alto il valore sarebbe chiuso solo se tutti gli elementi fossero "chiusi" e "nullo" se qualcosa fosse vuoto, e così via.

Quella finale significherebbe un'ulteriore modifica programmatica e tutte le modifiche ai forms gli articoli dovrebbero aggiornare anche questo campo per mantenere lo "stato". È tuttavia il modo più efficiente per trovare i documenti di cui hai bisogno e potrebbe valere la pena prendere in considerazione.

MODIFICA :

Oltre a modificare il documento per avere uno stato principale, il modulo di query più veloce sulla struttura rivista è in realtà:

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