I have this query to display people in certain age groups.
db.people.aggregate([
{
$bucket: {
groupBy: "$age",
boundaries: [ 0, 10, 20, 30, Number.POSITIVE_INFINITY ],
default: Number.NEGATIVE_INFINITY,
output: {
"count": { $sum: 1 }
}
}
}
])
enter code here
which produces following output:
{ "_id" : 0, "count" : 5 }
{ "_id" : 10, "count" : 10 }
{ "_id" : 20, "count" : 6 }
{ "_id" : 30, "count" : 9 }
I want to display it as
{ "_id" : 0, "count" : 5 }
{ "_id" : 10, "count" : 10 }
{ "_id" : 20, "count" : 6 }
{ "_id" : ">30", "count" : 9 }
How can I make it? Thanks.
There's no hacky way this make this happen, you'll have to add a $project
stage and specify the logic you want, like so:
db.people.aggregate([
{
$bucket: {
groupBy: "$age",
boundaries: [ 0, 10, 20, 30, Number.POSITIVE_INFINITY ],
default: Number.NEGATIVE_INFINITY,
output: {
"count": { $sum: 1 }
}
}
},
{
$project: {
_id: {
$cond: [{$eq: ['$_id', 30]}, '>30', '$_id']
},
count: 1
}
}
])
Related
I have a simple table with ranked users...
User:
{
"_id" : "aaa",
"rank" : 10
},
{
"_id" : "bbb",
"rank" : 30
},
{
"_id" : "ccc",
"rank" : 20
},
{
"_id" : "ddd",
"rank" : 30
},
{
"_id" : "eee",
"rank" : 30
},
{
"_id" : "fff",
"rank" : 10
}
And I would like to count how many have each rank, and then sort them with highest to lowest count
So I can get this result:
Result:
{
"rank" : 30,
"count": 3
},
{
"rank" : 10,
"count": 2
},
{
"rank" : 20,
"count": 1
}
I tried different things but cant seem to get the correct output
db.getCollection("user").aggregate([
{
"$group": {
"_id": {
"rank": "$rank"
},
"count": { "$sum": 1 }
},
"$sort": {
"count" : -1
}
])
I hope this is possible to do.
You can count and then sort them by aggregation in mongodb
db.getCollection('users').aggregate(
[
{
$group:
{
_id: "$rank",
count: { $sum: 1 }
}
},
{ $sort : { count : -1} }
]
)
Working example
https://mongoplayground.net/p/aM3Ci3GACjp
You don't need to add additional group or count stages when you can do it in one go -
db.getCollection("user").aggregate([
{
$sortByCount: "$rank"
}
])
I'm trying to figure out what I'm doing wrong, I have collected the following, "Subset of data", "Desired output"
This is how my data objects look
[{
"survey_answers": [
{
"id": "9ca01568e8dbb247", // As they are, this is the key to groupBy
"option_answer": 5, // Represent the index of the choosen option
"type": "OPINION_SCALE" // Opinion scales are 0-10 (meaning elleven options)
},
{
"id": "ba37125ec32b2a99",
"option_answer": 3,
"type": "LABELED_QUESTIONS" // Labeled questions are 0-x (they can change it from survey to survey)
}
],
"survey_id": "test"
},
{
"survey_answers": [
{
"id": "9ca01568e8dbb247",
"option_answer": 0,
"type": "OPINION_SCALE"
},
{
"id": "ba37125ec32b2a99",
"option_answer": 3,
"type": "LABELED_QUESTIONS"
}
],
"survey_id": "test"
}]
My desired output is:
[
{
id: '9ca01568e8dbb247'
results: [
{ _id: 5, count: 1 },
{ _id: 0, count: 1 }
]
},
{
id: 'ba37125ec32b2a99'
results: [
{ _id: 3, count: 2 }
]
}
]
Active query
Model.aggregate([
{
$match: {
'survey_id': survey_id
}
},
{
$unwind: "$survey_answers"
},
{
$group: {
_id: "$survey_answers.option_answer",
count: {
$sum: 1
}
}
}
])
Current output
[
{
"_id": 0,
"count": 1
},
{
"_id": 3,
"count": 2
},
{
"_id": 5,
"count": 1
}
]
I added your records to my db. Post that I tried your commands one by one.
$unwind results you similar to -
> db.survey.aggregate({$unwind: "$survey_answers"})
{ "_id" : ObjectId("5c3859e459875873b5e6ee3c"), "survey_answers" : { "id" : "9ca01568e8dbb247", "option_answer" : 5, "type" : "OPINION_SCALE" }, "survey_id" : "test" }
{ "_id" : ObjectId("5c3859e459875873b5e6ee3c"), "survey_answers" : { "id" : "ba37125ec32b2a99", "option_answer" : 3, "type" : "LABELED_QUESTIONS" }, "survey_id" : "test" }
{ "_id" : ObjectId("5c3859e459875873b5e6ee3d"), "survey_answers" : { "id" : "9ca01568e8dbb247", "option_answer" : 0, "type" : "OPINION_SCALE" }, "survey_id" : "test" }
{ "_id" : ObjectId("5c3859e459875873b5e6ee3d"), "survey_answers" : { "id" : "ba37125ec32b2a99", "option_answer" : 3, "type" : "LABELED_QUESTIONS" }, "survey_id" : "test" }
I am not adding code for match since that is okay in your query as well
The grouping would be -
> db.survey.aggregate({$unwind: "$survey_answers"},{$group: { _id: { 'optionAnswer': "$survey_answers.option_answer", 'id':"$survey_answers.id"}, count: { $sum: 1}}})
{ "_id" : { "optionAnswer" : 0, "id" : "9ca01568e8dbb247" }, "count" : 1 }
{ "_id" : { "optionAnswer" : 3, "id" : "ba37125ec32b2a99" }, "count" : 2 }
{ "_id" : { "optionAnswer" : 5, "id" : "9ca01568e8dbb247" }, "count" : 1 }
You can group on $survey_answers.id to bring it into projection.
The projection is what you're missing in your query -
> db.survey.aggregate({$unwind: "$survey_answers"},{$group: { _id: { 'optionAnswer': "$survey_answers.option_answer", 'id':'$survey_answers.id'}, count: { $sum: 1}}}, {$project : {answer: '$_id.optionAnswer', id: '$_id.id', count: '$count', _id:0}})
{ "answer" : 0, "id" : "9ca01568e8dbb247", "count" : 1 }
{ "answer" : 3, "id" : "ba37125ec32b2a99", "count" : 2 }
{ "answer" : 5, "id" : "9ca01568e8dbb247", "count" : 1 }
Further you can add a group on id and add results to a set. And your final query would be -
db.survey.aggregate(
{$unwind: "$survey_answers"},
{$group: {
_id: { 'optionAnswer': "$survey_answers.option_answer", 'id':'$survey_answers.id'},
count: { $sum: 1}
}},
{$project : {
answer: '$_id.optionAnswer',
id: '$_id.id',
count: '$count',
_id:0
}},
{$group: {
_id:{id:"$id"},
results: { $addToSet: {answer: "$answer", count: '$count'} }
}},
{$project : {
id: '$_id.id',
answer: '$results',
_id:0
}})
Hope this helps.
I have a document to Mongodb update array of objects like this:
{
"_id" : 5,
"quizzes" : [
{ "wk" : 1, "score" : 10 },
{ "wk" : 2, "score" : 8 },
{ "wk" : 5, "score" : 8 }
]
}
And I want to add new field in each object of quizzes array.
The expected result should be
{
"_id" : 5,
"quizzes" : [
{ "wk" : 1, "score" : 10, "day": 1 },
{ "wk" : 2, "score" : 8, "day": 2 },
{ "wk" : 5, "score" : 8, "day": 3 }
]
}
Any solution for this.
You can use Aggregation Framework:
db.col.aggregate([
{
$unwind: {
path: "$quizzes",
includeArrayIndex: "quizzes.day"
}
},
{
$group: {
_id: "$_id",
quizzes: {
$push: {
"score" : "$quizzes.score",
"wk" : "$quizzes.wk",
"day" : { $add: [ "$quizzes.day", 1 ] }
}
}
}
},
{
$out: "col"
}
])
To assign indexes to each element you can use $unwind with includeArrayIndex option. Those indexes start with 0 so we have to use $add to start with 1. Then you can group back by your _id property and use $out to save aggregation results to your collection.
I have the following records:
{ "_id" : 1, "c" : 120, "b" : [ { "f1" : 10 }, { "f1" : 10 } ] }
{ "_id" :2, "c" : 5, "b" : [ { "f1" : 10 }, { "f1" : 10 } ] }
I need the output this way:
{ "_id" : 1, 'total':140}
{ "_id" :2, 'total':25 }
where total = sum of value in 'c' with sum of values in f1 for same record.
When i unwind the field 'b' it creates two documents with same id and hence data is duplicated and when i sum it up, i get:
db.test2.aggregate([
{'$unwind':'$b'},
{'$project':{'total':{'$add':['$c','$b.f1']}}},
{'$group':{'_id':'$_id', 'total':{'$sum':'$total'}}}
])
outputs:
{ "_id" : 1, 'total':260}
{ "_id" :2, 'total':30 }
(not what i wanted, as it has added 120 and 5 again to total due to duplication during unwinding)
So i tried:
db.test2.aggregate([
{'$unwind':'$b'},
{'$group':{'_id':'$_id', 'c':{'$push': '$c'},'f1':{'$sum':'$b.f1'}}},
{'$project':{'total':{'$add':[{'$arrayElemAt':['$c',0]},'$f1']}}}
])
outputs:
{ "_id" : 1, 'total':140}
{ "_id" :2, 'total':25 }
( what i wanted)
Is there any other way to achieve this?
You can try below query. Sum operator to first calculate sum in array followed by add to calculate total with other field.
db.test2.aggregate([{
$project: {
total: {"$add":["$c", {"$sum":"$b.f1"}]}
}
}]
An alternative:
db.test2.aggregate([{
$project: {
_id: 0,
c: "$c",
b: {
$reduce: {
input: "$b.f1",
initialValue: 0,
in: {
$add: ["$$value", "$$this"]
}
}
}
}
},
{
$project: {
_id: 0,
total: {
$sum: ["$c", "$b"]
}
}
}
])
That would create result:
{
"total" : 140
}
{
"total" : 25
}
If you need the field _id then replace the _id: 0 in both $project to _id: 1
That would create this result:
{
"_id" : 1,
"total" : 140
}
{
"_id" : 2,
"total" : 25
}
This question already has answers here:
Sum in nested document MongoDB
(3 answers)
Closed 7 years ago.
db.logdata.findOne()
{
"_id" : ObjectId("552cfc949258ff1fa8686f1a"),
"ldl_date" : "2015-04-09",
"ldl_mmo_id" : 5,
"ldl_master_info_id" : 11,
"ldl_publication_info_id" : 41616,
"detail" : [
{
"ldl_id" : 54261629,
"ldl_xml_info_id" : 37437691,
"ldl_distribution_id" : 3289,
"ldl_local_flag" : 1,
"ldl_ftp_flag" : 0,
"ldl_time" : "2015-04-09 06:36:46"
}
]
}
I need to access the ldl_local_flag and count of the ldl_local_flag I tried following query but not get the exact result.
The query is
db.logdata.aggregate([
{
$group: {
_id: "$ldl_mmo_id",
total: {
$sum: "$detail.ldl_local_flag"
}
}
},
{
$limit: 10
}
])
And output is
{ "_id" : 1, "total" : 0 }
{ "_id" : 2, "total" : 0 }
{ "_id" : 3, "total" : 0 }
{ "_id" : 4, "total" : 0 }
{ "_id" : 5, "total" : 0 }
please help me..........
This might be helpful to you:
db.collection.aggregate({
$unwind: '$detail'
},
{
$group: {
"_id": "$detail.ldl_local_flag",
"sum": {
"$sum": "$detail.ldl_local_flag"
}
}
},
{
$project: {
"local_flags": "$_id",
"count": "$sum"
}
})