sql >> Databáze >  >> NoSQL >> MongoDB

MongoDB agregovaný součet každého klíče na dílčím dokumentu

Jak bylo uvedeno, zpracování dokumentů, jako je tento, není s agregačním rámcem možné, pokud skutečně nezadáte všechny klíče, jako například:

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

Musíte však samozřejmě výslovně uvést každý klíč, se kterým chcete pracovat. To platí jak pro agregační rámec, tak pro operace obecných dotazů v MongoDB, protože pro přístup k prvkům uvedeným v tomto formuláři „sub-document“ musíte zadat „přesnou cestu“ k prvku, abyste s ním mohli cokoli dělat.

Agregační rámec a obecné dotazy nemají pojem „procházení“, což znamená, že nemohou zpracovat „každý klíč“ dokumentu. To vyžaduje jazykovou konstrukci, která není v těchto rozhraních k dispozici.

Obecně řečeno, použití „jména klíče“ jako datového bodu, kde jeho název ve skutečnosti představuje „hodnotu“, je trochu „anti-vzor“. Lepším způsobem, jak to modelovat, by bylo použít pole a reprezentovat váš „typ“ jako hodnotu samotnou:

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

Také je třeba poznamenat, že „datum“ je nyní spíše objektem správného data než řetězcem, což je také dobrá praxe. Tento druh dat je však snadno zpracovatelný pomocí agregačního rámce:

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

To ukazuje dvoufázové seskupení, které nejprve získá součty za "typ" bez uvedení každého "klíče", protože již nemusíte, a poté se vrátí jako jeden dokument pro "app_id" s výsledky v poli, jak byly původně uloženy. Tento datový formulář je obecně mnohem flexibilnější pro prohlížení určitých „typů“ nebo dokonce „hodnot“ v určitém rozsahu.

Pokud nemůžete změnit strukturu, pak je vaší jedinou možností mapReduce. To vám umožňuje „kódovat“ procházení klíčů, ale protože to vyžaduje interpretaci a provádění JavaScriptu, není to tak rychlé jako agregační rámec:

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

To v podstatě projde a zkombinuje "klíče" a sečte hodnoty pro každý nalezený.

Takže vaše možnosti jsou buď:

  1. Změňte strukturu a pracujte se standardními dotazy a agregací.
  2. Zůstaňte u struktury a vyžadujte zpracování JavaScriptu a mapReduce.

Záleží na vašich skutečných potřebách, ale ve většině případů přináší restrukturalizace výhody.




  1. Oznámení ClusterControl 1.7.1:Podpora pro PostgreSQL 11 a MongoDB 4.0, vylepšené monitorování

  2. Jaké jsou případy použití, kdy je Redis preferován před Aerospike?

  3. Jak Spark, Python a MongoDB spolupracovat

  4. StackExchange TimeoutException při pokusu o vložení 750 položek ve 2 sadách v redis