How to write group by query for embedded array of document in mongodb - 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

Related

Mongo aggregator query: get list of documents depending on condition

I am working with 1.000 documets in a collection in MongoDb. Each document can be made of many topics, and a topic can be made of many keywords.
The mongo structure for each document is the following:
_id:ObjectId(6d5fc0922982bb550e08502d),
id_doc:"1234-678-436-42"
topic:Array
keywords:Array
The key topic is an array of objects o this type
type:"topic"
label:"work"
While, the keywords key is an array of objects, very similar to "topic":
type:"keyword"
value:"programmer"
label:"work"
Label represents in both cases the topic of the doc!
What I want is to list all the documents (id_doc) where a topic appears in the "topic" array, but never in the "keyword" array.
Query
takes the intersection of topic.label with keywords.label
if empty then no common members, so document passes the filter
*not sure if you want this, if not if you can give 1-2 documents in json text, and the expected output
Playmongo
aggregate(
[{"$match":
{"$expr":
{"$eq":
[{"$setIntersection": ["$topic.label", "$keywords.label"]}, []]}}}])
One option is using $filter:
count the number of items in topic which their label is not present in as a value of an item on keywords. Save this count as condMatch
$match only document with condMatch greater than 0
db.collection.aggregate([
{$set: {condMatch: {
$size: {
$filter: {
input: "$topic",
cond: {$not: {$in: ["$$this.label", "$keywords.value"]}}
}
}
}
}
},
{$match: {condMatch: {$gt: 0}}},
{$unset: "condMatch"}
])
See how it works on the playground example

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

Getting the count of documents within a document in 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"}
}
}
}}
])

Aggregate method in MongoDB Compass?

as stated in the title i'm having some problems querying from MongoDB Compass using the aggregate methhod. I have a collection of documents in this form:
{"Array":[{"field":"val","field2":"val2"},{"field":"val","field2":"val2"},{"field":"val","field2":"val2"},{"field":"val","field2":"val2"},{"field":"val","field2":"val2"},...]}
using mongo shell or Studio 3T software I query it with aggregate method, follows an example:
db.collection.aggregate([
{ $match: {"Array.field": "val"}},
{ $unwind: "$Array"},
{ $match: {"Array.field": "val"}},
{ $group: {_id: null, count: {$sum:NumberInt(1)}, Array: {$push: "$Array"}}},
{ $project: {"N. Hits": "$count", Array:1}}
])
where I look for elements of Array who has field's value = "val" and count them. This works perfectly, but I don't know how to do the same in MongoDB Compass
in the query bar I have 'filter', 'project' and 'sort' and I can do usual queries, but i don't know how to use aggregate method.
Thanks
You are looking at the Documents tab which is restricted for querying documents.
Take a look in the second tab called Aggregations where you can do your aggregation pipelines, as usual.
For further information please visit the Aggregation Pipeline Builder documentation.

Mongodb aggregation sort on array primative

Given documents like
{
...
name:'whatever',
games: [122, 199, 201, 222]
}
db.col.aggregate({$match:{}},
{$sort:{'games.0': -1}})
doesn't sort ... no errors ... it just doesn't sort on the first array element of the games array.
Although a query with the same syntac .. works fine
col.find({}).sort({'games.0':-1})
if I change the collection so games is an array of objects like
[ {game1:198}, {game2:201} ...]
then the aggregation works using
{$sort:{'games.game1': -1}})
what am I missing to get this to work with an array of numbers?
Try unwinding the array first by applying the $unwind operator on the array, then use $sort on the deconstructed array and finally use $group to get the original documents structure:
db.coll.aggregate([
{"$unwind": "$games"},
{"$sort": {"games": 1}},
{
"$group": {
"_id": "$_id",
"name": {"$first": "$name"},
"games": {"$push": "$games"}
}
}
])
Try this:
db.coll.aggregate([
{"$unwind": "$games"},
{"$sort": {"games": -1}}
]}
I hope this will work for you as you expected.
In mongo 3.4 find sort i.e. db.col.find({}).sort({'games.0':-1}) works as expected whereas aggregation sort doesn't.
In mongo 3.6 both find and aggregation sort works as expected.
Jira issue for that: https://jira.mongodb.org/browse/SERVER-19402
I would recommend you to update your mongo version and your aggregation query will work fine.