Reputation: 469
I have a document schema in a test
collection like this:
{
"_id" : NumberLong("A unique number"),
"text" : {
"characters_map" : {
"a" : 4,
"f" : 3,
"b" : 6,
...
"o" : 3
}
...
}
...
}
I want to count the sum of each character in the whole collection. I tried using the aggregation framework
, but it doesn't seem I do it correct.
I began by calculating each character separately ( i.e the 'a'), but with no luck. My best approach is:
> db.test.aggregate([
{ "$group" : {
_id : { a_count : "$text.characters_map.a" },
counter : { "$sum" : "$text.characters_map.a" }
}
}
])
with a_count
representing the name of the id.
which results to:
{ "_id" : { "a_map" : 8 }, "counter" : 8 }
{ "_id" : { "a_map" : 5 }, "counter" : 5 }
{ "_id" : { "a_map" : 7 }, "counter" : 21 }
...
Not false entirely, but not what I want. These results mean I have 1 document with a field of: { "a" : 8, ... }
, another 1 document with: { "a" : 5, ... }
and 3 documents with: { "a" : 7, ... }
.
Is there any way to group these fields together at "a" level? Is my approach completely wrong?
Upvotes: 0
Views: 762
Reputation: 75914
You have to change your structure to something like below.(Preferred)
[{
"text" : { "characters_map" : [{"k":"a", "v":4}, {"k":"b", "v":8}, {"k":"c", "v":5}, {"k":"d", "v":4 }] }
}]
You can use aggregation the way you tried in your post.
db.test.aggregate([
{$unwind:"$text.characters_map"},
{$group:{_id:"$text.characters_map.k", counter:{$sum:"$text.characters_map.v"}}}
])
This is the solution if you can't change your structure.
You can use 3.4.4
version and use $objectToArray
& $arrayToObject
to switch between dynamic keys and label value pair.
Stage 1: Convert the dynamic characters_map
keys into label value pair.
Stage 2 & 3: $unwind
& $group
on the characters and sum their counts.
Stage 4 & 5: Group back the output from last grouping into array of key value pairs followed by $arrayToObject
to convert the key value pairs into dynamic keys.
db.test.aggregate([
{$addFields: {"text.characters_map": {$objectToArray: "$text.characters_map"}}},
{$unwind:"$text.characters_map"},
{$group:{_id:"$text.characters_map.k", counter:{$sum:"$text.characters_map.v"}}},
{$group:{_id:null, arraykeyval:{$push:{k:"$_id", v:"$counter"}}}},
{$project:{result: {$arrayToObject:"$arraykeyval"}}}
])
Upvotes: 2