How to count number of inner documents in mongoDB - mongodb

I am very new to mongodb concepts
outerob{
_id:111,
name:xxx,
dependents : [ {
name:a,
age:11
}
{
name:b,
age:12
}
{
name:a,
age:11
}
]
}
I have collection like this. I want to count number of dependents. please help me with this
thanks in advance

You can find the number of items in array by using Aggregation framework as follows :
db.myCollection.aggregate(
{ $unwind: "$dependents" },
{ $group: { _id: "$_id", count: { $sum: 1 }}}
);
You can find the number of items with specific name as follows :
db.myCollection.aggregate(
{ $unwind: "$dependents" },
{ $match : {"dependents.name" : "a"}},
{ $group: { _id: "$_id", count: { $sum: 1 }}}
);

try
x=db.collection.find({_id:111}).toArray()[0].dependents.length

Related

About Mongo Group by where arr.length>0

Just assume following data:
{_id:1,hotelcode:a,availdates:["2020-01-02","2020-02-03"]}
{_id:2,hotelcode:a,availdates:["2020-02-03"]}
{_id:3,hotelcode:b,availdates:[]}
{_id:4,hotelcode:b,availdates:["2020-01-02"]}
{_id:5,hotelcode:c,availdates:["2020-01-02","2020-02-03"]}
I wanna achieve:
select hotelcode,count(hotelcode) from table group by hotelcode where availdates.length>0
What should I do?
I tried:
db.getCollection('spl_rate_27').aggregate([
{$project:{
adlength:{$size:"$avail_dates"}}
},
{$match:{adlength:{$gt:1}}},
{$group:{_id:{hotelcode:"$hotel_code"},total:{$sum:1}}}
])
But I got :
{
"_id" : {
"hotelcode" : null
},
"total" : 99999,0
}
It seems something was wrong...But I can't find it out....
You can do something like following, first get the objects whose availdates is greater than 0
[
{
$match: {
$expr: {
$gt: [
{
$size: "$availdates"
},
0
]
}
}
},
{
$group: {
_id: "$hotelcode",
total: {
$sum: 1
}
}
},
{
$project: {
_id: 0,
hotelcode: "$_id",
total: 1
}
}
]
Working Mongo playground
There are two things you can change.
Instead of $project use $addFields - project restricts fields, addFields adds field to the document
Then use $gte in the query as you need >0.
play
db.collection.aggregate([
{
$addFields: {
adlength: {
$size: "$availdates" //misspelled
}
}
},
{
$match: {
adlength: {
$gte: 1
}
}
},
{
$group: {
_id: {
hotelcode: "$hotelcode" //misspelled
},
total: {
$sum: 1
}
}
}
])
Well , I got inspiration from #Gibbs' answer. And I changed a bit my script:
db.getCollection('table').aggregate([
{$project:{
hotelcode:1, ##I omit this!!!
adlength:{$size:"$availdates"}}
},
{$match:{"adlength":{$gt:0}}},
{$group:{_id:{hotelcode:"$hotelcode"},total:{$sum:1}}}
])
And it works perfectly!
I hope this is what you are expecting.
db.collection.aggregate({
$match: {
"availdates": {
"$gt": "1"
}
}
},
{
$group: {
_id: "$hotelcode",
"records": {
$push: "$$ROOT"
},
"dataCount": {
$sum: 1
}
}
})
Working demo url : Mongo Playground URL

Mongo aggregation pipeline, finding out the total number of entries in an array per user

I have a collection, lets call it 'user'. In this collection there is a property entries, which holds a variably sized array of strings,
I want to find out the total number of these strings across my collection.
db.users.find()
> [{ entries: [] }, { entries: ['entry1','entry2']}, {entries: ['entry1']}]
So far I have have made many attempts here are some of my closest.
db.users.aggregate([
{ $project:
{ numberOfEntries:
{ $size: "$entries" } }
},
{ $group:
{_id: { total_entries: { $sum: "$entries"}
}
}
}
])
What this gives me is a list of the users with the total number of entries, now what I want is each of the total_entries figures added up to get my total. Any ideas of what I am doing wrong. Or if there is a better way to start this?
A possible solution could be:
db.users.aggregate([{
$group: {
_id: 'some text here',
count: {$sum: {$size: '$entries'}}
}
}]);
This will give you the total count of all entries across all users and look like
[
{
_id: 'some text here',
count: 3
}
]
I would use $unwind in the case that you want individual entry counts.
That would look like
db.users.aggregate([
{ $unwind: '$entries' },
{$group: {
_id: '$entries',
count: {$sum: 1}
}
])
and this will give you something along the lines of:
[
{
_id: 'entry1',
count: 2
},
{
_id: 'entry2',
count: 1
}
]
In case you want the overall distinct nbr of entries:
> db.users.aggregate([
{ $unwind: "$entries" },
{ $group: { _id: "$entries" } },
{ $count: "total" }
])
{ "total" : 2 }
In case you want the overall nbr of entries:
> db.users.aggregate( [ { $unwind: "$entries" }, { $count: "total" } ] )
{ "total" : 3 }
This makes use of the "unwind" operator which flattens elements of an array from records:
> db.users.aggregate( [ { $unwind: "$entries" } ] )
{ "_id" : ObjectId("5a81a7a1318e1cfc10250430"), "entries" : "entry1" }
{ "_id" : ObjectId("5a81a7a1318e1cfc10250430"), "entries" : "entry2" }
{ "_id" : ObjectId("5a81a7a1318e1cfc10250431"), "entries" : "entry1" }
You were in the right direction though you just needed to specify an _id value of null in the $group stage to calculate accumulated values for all the input documents as a whole i.e.
db.users.aggregate([
{
"$project": {
"numberOfEntries": {
"$size": {
"$ifNull": ["$entries", []]
}
}
}
},
{
"$group": {
"_id": null, /* _id of null to get the accumulated values for all the docs */
"totalEntries": { "$sum": "$numberOfEntries" }
}
}
])
Or with just a single pipeline as:
db.users.aggregate([
{
"$group": {
"_id": null, /* _id of null to get the accumulated values for all the docs */
"totalEntries": {
"$sum": {
"$size": {
"$ifNull": ["$entries", []]
}
}
}
}
}
])

MongoDB aggregate and count

A document in collection called 'myCollection' looks like this:
{
_id : 57b4b4e028108d801738a472,
updatedAt : 2016-08-17T19:03:01.831+0000,
createdAt : 2016-08-17T19:02:56.887+0000,
from : 57b1c2fc4bf55ba009b36c84,
to : 57b1c75e4bf55ba009b36c85,
}
I need to count the occurrences of 'from' and 'to' and end up with collection of documents like this:
{
"_id" : 7b1c2fc4bf55ba009b36c84,
"occurredInFrom" : 12,
"occurredInTo" : 16
}
where _id comes from either '$from' or '$to'.
The incorrect aggregate query I've written is this:
{
$group: {
_id: "$from",
occurredInFrom: { $sum: 1 },
occurredInTo: { $sum: 1}
}
}
I can definitely see that _id: "$from" is not sufficient. Can you please show me the correct way?
Note: The structure of 'myCollection' is not final, if you think there is a better structure, please suggest it.
Try this
db.myCollection.aggregate([
{ $project:
{ _id: 0,
dir: [
{id:"$from", from:{"$sum":1}, to:{"$sum":0}},
{id:"$to", from:{"$sum":0}, to:{"$sum":1}}
]
}
},
{ $unwind : "$dir" },
{ $group:
{
_id: "$dir.id",
occurredInFrom: { $sum: "$dir.from" },
occurredInTo: { $sum: "$dir.to" }
}
}
])

Convert to lowercase in group aggregation

I want to return an aggregate of blog post tags and their total count. My blog posts are stored like so:
{
"_id" : ObjectId("532c323bb07ab5aace243c8e"),
"title" : "Fitframe.js - Responsive iframes made easy",
"tags" : [
"JavaScript",
"jQuery",
"RWD"
]
}
I'm then executing the following pipeline:
printjson(db.posts.aggregate(
{
$project: {
tags: 1,
count: { $add: 1 }
}
},
{
$unwind: '$tags'
},
{
$group: {
_id: '$tags',
count: {
$sum: '$count'
},
tags_lower: { $toLower: '$tags' }
}
},
{
$sort: {
_id: 1
}
}
));
So that the results are sorted correctly I need to sort on a lowercase version of each tag. However, when executing the above code I get the following error:
aggregate failed: {
"errmsg" : "exception: unknown group operator '$toLower'",
"code" : 15952,
"ok" : 0
}
Do I need to do another projection to add the lowercase tag?
Yes, you must add it to the projection. It will not work in the group, only specific operators like $sum ( http://docs.mongodb.org/manual/reference/operator/aggregation-group/ ) are counted as $group operators and capable of being used on that level of the group
You don't need to add another projection ... you could fix it when you do the $group:
db.posts.aggregate(
{
$project: {
tags: 1,
count: { $add: 1 }
}
},
{
$unwind: '$tags'
},
{
$group: {
_id: { tag: '$tags', lower: { $toLower : '$tags' } },
count: {
$sum: '$count'
}
}
},
{
$sort: {
"_id.lower": 1
}
}
)
In the above example, I've preserved the original name and added the lower case version to the _id.
Add another projection step between $unwind and $grop:
...
{$project: {
tags: {$toLower: '$tags'},
count: 1
}}
...
And remove tags_lower from $group

Sum in nested document MongoDB

I'm trying to sum some values in an array of documents, with no luck.
This is the Document
db.Cuentas.find().pretty()
{
"Agno": "2013",
"Egresos": [
{
"Fecha": "28-01-2013",
"Monto": 150000,
"Detalle": "Pago Nokia Lumia a #josellop"
},
{
"Fecha": "29-01-2013",
"Monto": 4000,
"Detalle": "Cine, Pelicula fome"
}
],
"Ingresos": [],
"Mes": "Enero",
"Monto": 450000,
"Usuario": "MarioCares"
"_id": ObjectId(....)
}
So, i need the sum of all the "Monto" in "Egresos" for the "Usuario": "MarioCares". In this example 154000
Using aggregation i use this:
db.Cuentas.aggregate(
[
{ $match: {"Usuario": "MarioCares"} },
{ $group:
{
_id: null,
"suma": { $sum: "$Egresos.Monto" }
}
}
]
)
But i always get
{ "result" : [{ "_id" : null, "suma" : 0 }], "ok" : 1 }
What am i doing wrong ?
P.D. already see this and this
As Sammaye indicated, you need to $unwind the Egresos array to duplicate the matched doc per array element so you can $sum over each element:
db.Cuentas.aggregate([
{$match: {"Usuario": "MarioCares"} },
{$unwind: '$Egresos'},
{$group: {
_id: null,
"suma": {$sum: "$Egresos.Monto" }
}}
])
You can do also by this way. don't need to group just project your fields.
db.Cuentas.aggregate([
{ $match: { "Usuario": "MarioCares" } },
{
$project: {
'MontoSum': { $sum: "$Egresos.Monto" }
}
}
])
Since mongoDB version 3.4 you can use $reduce to sum array items:
db.collection.aggregate([
{
$match: {Usuario: "MarioCares"}
},
{
$project: {
suma: {
$reduce: {
input: "$Egresos",
initialValue: 0,
in: {$add: ["$$value", "$$this.Monto"]}
}
}
}
}
])
Playground example