How Do I get saperated counts while grouping on multiple fields mongodb aggregation? - mongodb

I have the following documents in my candidate collection.
candidates = [
{
name: "amit",
age: 21,
city: 'pune'
}
{
name: "rahul",
age: 23,
city: 'pune'
},
{
name: "arjun",
age: 21,
city: 'pune'
},
{
name: "rakesh",
age: 23,
city: 'pune'
},
{
name: "amit",
age: 22,
city: 'nashik'
}
]
I want to group by age and city fields and count the documents based on its sum independent of each other
I tried following query
candidate.aggregate([
{$group: {_id: {age: '$age', city: '$city'}, count: {$sum: -1}}}
{$sort: {count: -1}},
{$limit: 10}
])
which gives me count of combine results of age and city.
what I want instead
{
ages: [
{
age: 21,
count: 2
},
{
age: 23,
count: 2
},
{
age: 21,
count: 1
}
],
cities: [
{
city: 'pune',
count: 4
},
{
city: 'nashik',
count: 1
}
]
}
thanks for any help.

You need to use $facet stage, with a $group stage per age, and another per city.
Here's the query :
db.collection.aggregate([
{
$facet: {
byCity: [
{
$group: {
_id: {
city: "$city"
},
count: {
$sum: 1
}
}
},
{
$sort: {
count: -1
}
},
{
$limit: 10
}
],
byAge: [
{
$group: {
_id: {
age: "$age",
},
count: {
$sum: 1
}
}
},
{
$sort: {
count: -1
}
},
{
$limit: 10
}
]
}
},
])
Mongo playground

Related

how to Increment optional sub-fields using $inc operator?

this are sample documents of the collection,
{
_id: ObjectId("637f1128d8298d42bae0d4fc"),
name: 'Iska Paphat',
age: 8,
cat: { name: 'Malone Poppelhoffen', age: 7 }
},
{
_id: ObjectId("637f1128d8298d42bae0d4fd"),
name: 'Elbow Frank',
age: 67
},
{
_id: ObjectId("637f1128d8298d42bae0d4fe"),
name: 'Frank Frank',
age: 49,
cat: { name: 'Pirate Yolanda', age: 4 }
},
{
_id: ObjectId("637f1128d8298d42bae0d4ff"),
name: 'Fluffy Yolanda',
age: 66
},
I'm trying to increment age and cat.age by 1, using
db.people.updateMany({},{$inc:{age:1,'cat.age':1}}),
this command adds{cats:{age:1}} in fields which has no cat subfields.
{
_id: ObjectId("637f03bcd8298d42bae0d110"),
name: 'Elbow Pirate',
age: 5,
cat: { age: 1 }
},
{
_id: ObjectId("637f03bcd8298d42bae0d111"),
name: 'Malone Foxton',
age: 45,
cat: { age: 1 }
},
{
_id: ObjectId("637f03bcd8298d42bae0d112"),
name: 'Fluffy Poppelhoffen',
age: 1,
cat: { age: 1 }
},
how to $inc both cat's age and person age without adding cat field in single query?
You want to be using pipelined updates for this. this allows us to incorporate some more complex logic, in this case only increment the age field if the cat exists.
db.people.updateMany({},
[
{
$set: {
age: {
$sum: [
"$age",
1
]
},
cat: {
$cond: [
{
$eq: [
"$cat",
undefined
]
},
"$$REMOVE",
{
$mergeObjects: [
"$cat",
{
age: {
$sum: [
"$cat.age",
1
]
}
}
]
}
]
}
}
}
])
Mongo Playground

Projection and group on nested object mongodb aggregation query

How to get the nested object in projection and group in mongodb aggregate query.
[
{
city: "Mumbai",
meta: {
luggage: 2,
scanLuggage: 1,
upiLuggage: 1
},
cash: 10
},
{
city: "Mumbai",
meta: {
luggage: 4,
scanLuggage: 3,
upiLuggage: 1
},
cash: 24
},
]
I want to $match the above on the basis of city, and return the sum of each luggage type.
My code is as follows but $project is not working -
City.aggregate([
{
$match: { city: 'Mumbai' }
},
{
$project: {
city: 1,
mata.luggage: 1,
meta.scanLuggage: 1,
meta.upiLuggage: 1
}
},
{
$group: {
id: city,
luggage: {$sum: '$meta.luggage'},
scanLuggage: {$sum: '$meta.scanLuggage'},
upiLuggage: {$sum: '$meta.upiLuggage'}
}
}
])
But the $project is throwing error. I want my output to look like -
{
city: 'Mumbai',
luggage: 6,
scanLuggage: 4,
upiLuggage: 2
}
You should specify nested fields in quotes when using in $project, and also for grouping key should be _id.
db.collection.aggregate([
{
$match: {
city: "Mumbai"
}
},
{
$project: {
city: 1,
"meta.luggage": 1,
"meta.scanLuggage": 1,
"meta.upiLuggage": 1
}
},
{
$group: {
_id: "$city",
luggage: {
$sum: "$meta.luggage"
},
scanLuggage: {
$sum: "$meta.scanLuggage"
},
upiLuggage: {
$sum: "$meta.upiLuggage"
}
}
}
])
This is the playground link.

MongoDB Aggregation - $sum nested groups

This is my Mongo event data in the events collection:
[
{ country: "USA", Region: "CA", City: "Los Angeles" },
{ country: "USA", Region: "NY", City: "New York" },
{ country: "USA", Region: "NY", City: "White Plains" },
{ country: "France", Region: "Ile-de-France", City: "Paris" },
{ country: "France", Region: "Bretagne", City: "Brest" },
{ country: "Germany", Region: "", City: "Berlin" }
]
If possible I would like to show the event summed by country and region. The desired output format would be:
[
{
country: "USA",
count: 3,
children: [
{ Region: "NY", count: 2 },
{ Region: "CA", count: 1 }
]
},
{
country: "France",
count: 2,
children: [
{ Region: "Ile-de-France", count: 1 },
{ Region: "Bretagne", count: 1 }
]
},
{
country: "Germany",
count: 1,
children: [ // Region undefined ]
}
]
Here is what I tried:
events.aggregate([
{
$group: {
_id: '$country', count: {$sum: 1}
}
},
{
$group: {
_id: '$_id.country',
children: {
$push: {
Region: '$_id.Region',
count: {$sum: 1}
}
}
}
}
]
The first stage groups and counts the country works on its own. The issue is summing the Region parameter. I even removed the $sum function from the first stage. All I am getting is:
[
{
_id: null,
children : [
{ count: 1 },
{ count: 1 },
{ count: 1 },
{ count: 1 },
...
]
}
]
Any advice would be appreciated!
$group - Group by country and Region.
$group - Group by country.
db.collection.aggregate([
{
$group: {
_id: {
country: "$country",
Region: "$Region"
},
count: {
$sum: 1
}
}
},
{
$group: {
_id: "$_id.country",
children: {
$push: {
Region: "$_id.Region",
count: "$count"
}
}
}
}
])
Sample Mongo Playground

Group values by sub string in MongoDB

I have this documents in my collection :
{_id: "aaaaaaaa", email: "mail1#orange.fr"},
{_id: "bbbbbbbb", email: "mail2#orange.fr"},
{_id: "cccccccc", email: "mail3#orange.fr"},
{_id: "dddddddd", email: "mail4#gmail.com"},
{_id: "eeeeeeee", email: "mail5#gmail.com"},
{_id: "ffffffff", email: "mail6#yahoo.com"}
And i would like this result :
{
result: [
{domain: "orange.fr", count: 3},
{domain: "gmail.com", count: 2},
{domain: "yahoo.com", count: 1},
]
}
I'm not sure you can use the aggregator and $regex operator
Aggregation Framework
I don't believe that with the present document structure you can achieve the desired result by using the aggregation framework. If you stored the domain name in a separate field, it would have become trivial:
db.items.aggregate(
{
$group:
{
_id: "$emailDomain",
count: { $sum: 1 }
},
}
)
Map-Reduce
It's possible to implement what you want using a simple map-reduce aggregation. Naturally, the performance will not be good on large collections.
Query
db.emails.mapReduce(
function() {
if (this.email) {
var parts = this.email.split('#');
emit(parts[parts.length - 1], 1);
}
},
function(key, values) {
return Array.sum(values);
},
{
out: { inline: 1 }
}
)
Output
[
{
"_id" : "gmail.com",
"value" : 2
},
{
"_id" : "yahoo.com",
"value" : 1
},
{
"_id" : "orange.fr",
"value" : 3
}
]
Aggregation Framework
MongoDB 3.4(Released Nov 29, 2016) onwords in aggregation framework have many methods
[
{
$project: {
domain: {
$substr: ["$email", {
$indexOfBytes: ["$email", "#"]
}, {
$strLenBytes: "$email"
}]
}
},
{
$group: {
_id: '$domain',
count: {
$sum: 1
}
}
},
{
$sort: {
'count': -1
}
},
{
$group: {
_id: null,
result: {
$push: {
'domain': "$_id",
'count': '$count'
}
}
}
}
]
Results
{
_id: null,
result: [
{domain: "#orange.fr", count: 3},
{domain: "#gmail.com", count: 2},
{domain: "#yahoo.com", count: 1},
]
}

MongoDB .Need to count fileds of an array

I have a collection like below
{ _id: 1, zipcode: "63109", students: [
{ name: "john", school: 102, age: 10 },
{ name: "jess", school: 102, age: 11 },
{ name: "jeff", school: 108, age: 15 }
] }
{ _id: 2, zipcode: "63110", students: [
{ name: "ajax", school: 100, age: 7 },
{ name: "achilles", school: 100, age: 8 },
] }
{ _id: 3, zipcode: "63109", students: [
{ school: 100, age: 7 },
{ school: 100, age: 8 },
] }
{ _id: 4, zipcode: "63109", students: [
{ name: "barney", school: 102, age: 7 },
{ name: "ruth", school: 102, age: 16 },
] }
Note:Some document doesnot have name field.
I want to findout the count of name field.
Kindly suggest query to find count in mongo
You can do this with aggregation framework with $unwind. Let say your collection name is test:
db.test.aggregate(
{$unwind: '$students'},
{$match:{'students.name':{$exists:1}}},
{$group:{_id: '$students.name', count:{$sum:1}}},
{$project:{tmp:{name:'$_id', count:'$count'}}},
{$group:{_id:'Total Names', total:{$sum:1}, data:{$addToSet:'$tmp'}}}
)
Hope this is what you want!
You need to use the aggregation framework in this case.
The first aggregation step would be to use $unwind to turn the arrays into streams of documents.
Then you can use $group as a second aggregation step with $sum:1 to get the count of every name.
db.collection.aggregate([
{
$unwind: "$students"
},
{
$group: {
_id:"$students.name",
count: { $sum:1 }
}
}
]
This is doable through the aggregation framework
I'll assume your collection is called mycoll:
db.mycoll.aggregate([
{$unwind:'$students'},
{$group:{_id:'$name', 'count':{$sum:1}},
{$match:{'students.name':{$exists:1}}}
]);
References:
Aggregations http://docs.mongodb.org/manual/tutorial/aggregation-zip-code-data-set/
Exists: http://docs.mongodb.org/manual/reference/operator/query/exists/
Summing '1' essentially turns it into a count.