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ď:
- Změňte strukturu a pracujte se standardními dotazy a agregací.
- 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.