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

MongoDB Aggregate Somma ogni chiave su un documento secondario

Come affermato, l'elaborazione di documenti come questo non è possibile con il framework di aggregazione a meno che tu non fornisca effettivamente tutte le chiavi, come ad esempio:

db.events.aggregate([
   { "$group": {
       "_id": "$app_id",
       "event_count": { "$sum": "$event_count" },
       "0": { "$sum": "$event_count_per_type.0" },
       "10": { "$sum": "$event_count_per_type.10" }
       "20": { "$sum": "$event_count_per_type.20" }
       "30": { "$sum": "$event_count_per_type.30" }
   }}
])

Ma ovviamente devi specificare esplicitamente ogni chiave su cui si desidera lavorare. Questo è vero sia per il framework di aggregazione che per le operazioni di query generali in MongoDB, poiché per accedere agli elementi annotati in questo modulo di "documento secondario" è necessario specificare il "percorso esatto" dell'elemento per poter fare qualsiasi cosa con esso.

Il framework di aggregazione e le query generali non hanno il concetto di "attraversamento", il che significa che non possono elaborare "ogni chiave" di un documento. Ciò richiede un costrutto di linguaggio per fare ciò che non è fornito in queste interfacce.

In generale, tuttavia, l'utilizzo di un "nome chiave" come punto dati in cui il nome rappresenta effettivamente un "valore" è un po' un "anti-modello". Un modo migliore per modellarlo sarebbe usare un array e rappresentare il tuo "tipo" come valore da solo:

{
    "app_id": "DHJFK67JDSJjdasj909",
    "date: ISODate("2014-08-07T00:00:00.000Z"),
    "event_count": 32423,
    "events": [
        { "type": 0,  "value": 322  },
        { "type": 10, "value": 4234 },
        { "type": 20, "value": 653  },
        { "type": 30, "value": 7562 }
    ]
}

Notando anche che la "data" è ora un oggetto data corretto piuttosto che una stringa, che è anche una buona pratica da fare. Tuttavia, questo tipo di dati è facile da elaborare con il framework di aggregazione:

db.events.aggregate([
    { "$unwind": "$events" },
    { "$group": {
        "_id": { 
            "app_id": "$app_id",
            "type": "$events.type"
        },
        "event_count": { "$sum": "$event_count" },
        "value": { "$sum": "$value" }
    }},
    { "$group": {
        "_id": "$_id.app_id",
        "event_count": { "$sum": "$event_count" },
        "events": { "$push": { "type": "$_id.type", "value": "$value" } }
    }}
]) 

Ciò mostra un raggruppamento in due fasi che prima ottiene i totali per "tipo" senza specificare ogni "chiave" poiché non è più necessario, quindi restituisce come un unico documento per "app_id" con i risultati in un array come erano originariamente archiviati. Questo modulo dati è generalmente molto più flessibile per esaminare determinati "tipi" o anche "valori" all'interno di un determinato intervallo.

Laddove non è possibile modificare la struttura, l'unica opzione è mapReduce. Ciò ti consente di "codificare" l'attraversamento delle chiavi, ma poiché ciò richiede l'interpretazione e l'esecuzione di JavaScript non è veloce come il framework di aggregazione:

db.events.mapReduce(
    function() {
        emit(
            this.app_id,
            {
                "event_count": this.event_count,
                "event_count_per_type": this.event_count_per_type
            }
        );
    },
    function(key,values) {

        var reduced = { "event_count": 0, "event_count_per_type": {} };

        values.forEach(function(value) {
            for ( var k in value.event_count_per_type ) {
                if ( !redcuced.event_count_per_type.hasOwnProperty(k) )
                    reduced.event_count_per_type[k] = 0;
                reduced.event_count_per_type += value.event_count_per_type;
            }
            reduced.event_count += value.event_count;
        })
    },
    {
        "out": { "inline": 1 }
    }
)

Ciò essenzialmente attraverserà e combinerà le "chiavi" e riassumerà i valori per ciascuna trovata.

Quindi le tue opzioni sono:

  1. Cambia la struttura e lavora con query e aggregazioni standard.
  2. Rimani con la struttura e richiedi l'elaborazione JavaScript e mapReduce.

Dipende dalle tue effettive esigenze, ma nella maggior parte dei casi la ristrutturazione porta vantaggi.