Getting the count of documents within a document in mongodb - mongodb

I have a structure of...
{ _id = object_id,
user: name,
days: { "4/1/2010": {"checked": true},
"4/2/2011": {"checked": false)}
}
I want to get the total number of days across users. If days was an array, I would do something like...
db.collection.aggregate([{"$group": {"_id": null, {"$sum": {"$size": "$days"}}}}])
but that won't work since I can't use size. Anyone have suggestions?
Note: There may be a different number of days missing in the data structure for each user which is why I want to check the count within each user's days

You can use aggregation pipeline with $objectToArray stage to convert days pair into arrays followed by $sum and $size in a $group stage in 3.4.
db.collection.aggregate([
{"$group":{
"_id":null,
"count":{
"$sum":{
"$size":{"$objectToArray":"$days"}
}
}
}}
])

Related

Specific Field Wont Display In Mongo DB Aggregation Pipeline

I have a collection of Book Reviews where I am trying to find users who have created multiple reviews (lets say 5), I also want to return the number of reviews, their unique ID and their Name.
So far I have managed to find a way of doing this through aggregation, however for the life of me I cant seem to return the name field, I assumed a simple $project would be fine but instead I can only see the ID and the Number of reviews someone has made, what am i missing to fix this?
Current Code:
db.bookreviews.aggregate([
{"$group": {"_id": "$reviewerID","NumberOfReviews": { "$sum": 1 }}},
{"$match": {NumberOfReviews: {"$gte": 5}}},
{"$project":{_id:1,NumberOfReviews:1, reviewerName:1}},
])
Returned Values:
{IDXYZ, NumberofReviews 5},
{IDABC, NumberofReviews 5},
{ID123, NumberofReviews 5}
you can use $first to keep the first document of that group and keep the value of reviewerName in your $group stage and you can remove the $project.
db.bookreviews.aggregate([
{"$group": {"_id": "$reviewerID","NumberOfReviews": { "$sum": 1 }, "reviewerName": { "$first": "$reviewerName" } } },
{"$match": {"NumberOfReviews": {"$gte": 5}}},
])

Get count of a value of a subdocument inside an array with mongoose

I have Collection of documents with id and contact. Contact is an array which contains subdocuments.
I am trying to get the count of contact where isActive = Y. Also need to query the collection based on the id. The entire query can be something like
Select Count(contact.isActive=Y) where _id = '601ad0227b25254647823713'
I am using mongo and mongoose for the first time. Please edit the question if I was not able to explain it properly.
You can use an aggregation pipeline like this:
First $match to get only documents with desired _id.
Then $unwind to get different values inside array.
Match again to get the values which isActive value is Y.
And $group adding one for each document that exists (i.e. counting documents with isActive= Y). The count is stores in field total.
db.collection.aggregate([
{
"$match": {"id": 1}
},
{
"$unwind": "$contact"
},
{
"$match": {"contact.isActive": "Y"}
},
{
"$group": {
"_id": "$id",
"total": {"$sum": 1}
}
}
])
Example here

How to write group by query for embedded array of document in mongodb

I have a collection in below format
{customerID:1,acctDetails:[{accType:"Saving",balance:100},{accType:"checking",balance:500}]}
{customerID:2,acctDetails:[{accType:"Saving",balance:500}]}
I want to find total balance by acctType. I tried below query.
db.<collectionName>.aggregate([{$group:{_id:"$acctDetails.accType",totalBalance:{$sum:"$accDetails.balace"}}}])
But it is not giving right result.
I think that this might solve your problem. You first need to use $unwind to transform each array element in a document, then use $group to sum the total balance by account type.
db.collection.aggregate([
{"$unwind": "$acctDetails"},
{
"$group": {
"_id": "$acctDetails.accType",
"totalBalance": {"$sum": "$acctDetails.balance"}
}
}
])
Working Mongo playground

MongoDB Aggregate - Count objects of a specific matching field

I want to know how to use aggregate() to take all of the objects of a specific field (i.e. "user") and count them.
This what I am doing:
I want to return a list of users with the sum of how many tweets that have made?
So I want output that looks like
Etc..
Also I don't want repeating users like
Etc..
which is what the above aggregate does.
So basically, how can I modify this aggregate to ensure the objects are unique?
I believe you will want to group by the user.id field instead of the user object. You can try doing that directly
$group: {_id: "$user.id", totalTweets: {$sum: 1} }
Or you might want to try projecting that field onto the document before grouping
$addFields: {userId: "$user.id"}
$group: {_id: "$userId", totalTweets: {$sum: 1} }
If you want whole inner user object in each documents after aggregation then you have to use $push operator in aggregation
and also you need to do the aggregation on unique id of users e.g: id or id_str instead of $user object as in your question.
db.tweets.aggregate([{ $group: {_id: "$user.id", totalTweets: { $sum: 1 }, user : { $push: "$user" } } }])
This will solved your problem. For details about $push operator, have a look at official documents $push

Meteor + Mongo (2.6.7) Pushing Document to Array in Sorted Order

I have a document with an array (which should be denormalised, but can't be because the reactive events will fire "add" too many times at client startup).
I need to be able to push a document to that array, and keep it in sorted (or roughly sorted) order. I've tried this query:
{ $push: {
'events': {
$each: [{'id': new Mongo.ObjectID, 'start':startDate,...}],
$sort: {'start': 1},
$slice: -1
}
}
But it requires the $slice operator to be present... I don't want to delete all my old data, I just want to be able to insert data into an array, and then have that array be sorted so that I can query the array later and say "slice greater than or equal to time X".
Is this possible?
Edit:
This mongo aggregate query nearly works, except for one level of document in the result array, but aggregating is not reactive (probably because they're expensive computations). Here is the aggregate query if anyone can see how to translate it to a find, or why it can't be translated:
Coll.aggregate({$unwind: '$events'},
{$sort: {'events.start':1}},
{$match: {'events.start': {$gte: new Date()}}},
{$group: {_id: '$_id', 'events': {$push: '$events'} }})