MongoDB max in group results - mongodb

I grouped results by mvid and the counted number of occurrences in each group.
db.some_details.aggregate([
{$group: {_id: "$mvid", count: {$sum: 1}}}
])
Now, I would like to select group with max count. Here is my naive guess:
db.some_details.aggregate([
{$group: {_id: "$mvid", count: {$sum: 1}}},
{$max: "count"}
])
It, obviously, generates an error. I need to use max with group, but I don't have anything to group on.

What also would work is sorting the result and then using only the first element:
db.some_details.aggregate([
{$group: {_id: "$mvid", count: {$sum: 1}}},
{$sort: {"count": -1}},
{$limit: 1 }
])
The advantage that I see compared to chridam's solution is that you also get the id of the group with the maximum count, but I expect it to be slower (not tested).

The aggregation pipeline allows you to could include another $group operator pipeline that would give you the maximum count of all the groups:
db.some_details.aggregate([
{
$group: {
_id: "$mvid",
count: { $sum: 1 }
}
},
{
$group: {
_id: 0,
maxCount: { $max: "$count" }
}
}
])

Related

How to slice and mondify a mongodb aggregation

I am new to MongoDB and I am trying to project the amount field from a decimal to a double when queried. Right now I add $$ROOT to an array and then slice that array to just get a subset of transactions. I figure I can probably convert it when I push to the array ($group stage) or after slicing ($project stage) but I can't figure out how. Any tips? End goal is to present the sum, count, and most recent transactions (I need to add sorting logic later).
db.transactions.aggregate([
{$match:{}},
{$group:{
_id:null,
transactions:{
$push:"$$ROOT"
},
count:{$sum: 1},
sum: {$sum: "$amount"}
}},
{$project:{
_id:0,
summary:{ count: "$count", sum: {$convert:{input:"$sum",to:"double"}}},
transactions: {$slice:["$transactions", 2]}
}}
])
I figured out that $facet allow me to do this:
db.transactions.aggregate([{
$facet:{
summary: [
{$match:{}},
{$group:{
_id:null,
count:{$sum: 1},
sum: {$sum: "$amount"}
}},
{$project:{
_id:0,
count: "$count",
sum: {$convert:{input:"$sum",to:"double"}}}
}
],
transactions: [
{$match:{}},
{$sort:{date:-1,timestamp:-1}},
{$limit:1},
{$addFields:{amount: {$convert:{input:"$amount",to:"double"}}}}
]
}
}]);

MongoDB $group + $project + weekly average

I'm trying to get the average of a puntations for some stores weekly in Mongo but it don't work. Could u help me?
db.collection.aggregate(
[
{$match:{storeId:{$in:[
ObjectId("e069d1b76557685b9e235v"),ObjectId("e069d1b76557685b9t7j8n"),
ObjectId("e069d1b76557685b9e2fg6"),ObjectId("e069d1b76557685b9p56r2")
]}}},
{$group:{_id:"$storeId", week: { date: new Date("$createdAt") }, totalPoints: {$sum: "$points"}, averagePoints: {$avg: "$points"}} },
{$sort: {totalPoints:-1}}
])
It doesn't work. But if I delete the part of the week, the code work it but make a wrong average
db.collection.aggregate(
[
{$match:{storeId:{$in:[
ObjectId("e069d1b76557685b9e235v"),ObjectId("e069d1b76557685b9t7j8n"),
ObjectId("e069d1b76557685b9e2fg6"),ObjectId("e069d1b76557685b9p56r2")
]}}},
{$group:{_id:"$storeId", totalPoints: {$sum: "$points"}, averagePoints: {$avg: "$points"}} },
{$sort: {totalPoints:-1}}
])
For groupBy week you can use $week function from mongo and add start Date in $match operation.
db.collection.aggregate(
[
{$match:{storeId:{$in:[
ObjectId("e069d1b76557685b9e235v"),ObjectId("e069d1b76557685b9t7j8n"),
ObjectId("e069d1b76557685b9e2fg6"),ObjectId("e069d1b76557685b9p56r2")
]},
timeStamp: {$gt: ISODate(createdAt)},
}},
{$group:{_id:"$storeId", week: { $week: '$timeStamp'}, totalPoints: {$sum: "$points"}, averagePoints: {$avg: "$points"}} },
{$sort: {totalPoints:-1}}
])

how to getting the count with all records

I am trying this mongodb aggregation. I got the output but how can I get the count value with all records.
db.STREETLIGHTS.aggregate(
[
{$match : {"CreateDate":{$gt:new Date(ISODate("2018-04-09T23:54:16.064Z") - 24*60*60 * 1000)}}},
{ $project: {_id:1, SLC_ID:1,LONGITUDE:1,LATITUDE:1,DCUID:1,CUMILITIVE_KWH:1,LAMPSTATUS:1,CreateDate:1 } },
]
)
Please try this.
db.STREETLIGHTS.aggregate([
{$match : {"CreateDate":{$gt:new Date(ISODate("2018-04-09T23:54:16.064Z") - 24*60*60 * 1000)}}},
{$project: {_id:1, SLC_ID:1,LONGITUDE:1,LATITUDE:1,DCUID:1,CUMILITIVE_KWH:1,LAMPSTATUS:1,CreateDate:1 } },
{$group: {_id: null, count: {$sum: 1}}}
])
You need to use the $sum operator in the $project stage :
{$project: {
// Your others projections
total: {$sum: 1}
}

mongoDB, sum many values query

I have a list of items, and I want mongoDB return the result of the sum of their price.
Schema = {
_id: ObjectId,
price: Integer,
}
I'm trying using the aggregation framework, but I can't figure out how correctly use it.
Here an example
db.items.aggregate([
{$match: {_id: {$in: [103070,103069]}}},
{$unwind: "$items"},
{$group: {_id: "$items", count: {$sum: "$items.price"}}},
{$project: {_id: 1}}
])
you are not correctly using the $in operator... $in is used to find elements inside an array, in this case you should use $gte (greater than equal), $lte (less then equal)... Your schema simply don't have "nodeId"... $unwind is used when you have an array inside the document what I presume is not the case... If i understand the query should be something like:
db.items.aggregate([
{$match : {_id : { $gte : 103069, $lte : 103070 } } },
{$group: {_id: null, count: {$sum: "$price"}}},
{$project: {_id: 0, count : 1}}
])

MongoDB Aggregation Framework $Project additional ObjectId reference field

Say I have the following:
this.aggregate(
{$unwind: "$tags"},
{$match: {tags: {$in: pip.activity.tags}}},
{$group : {_id : '$_id',matches:{$sum:1}}},
{$project: { _id: 0,matches:1}},
{$sort: {matches:-1 }},
callback
);
how would I go about including an additional 'external' objectId field in the results? e.g if I have the following:
var otherField = new ObjectId('xxxxxxx');
this.aggregate(
{$unwind: "$tags"},
{$match: {tags: {$in: pip.activity.tags}}},
{$group : {_id : '$_id',matches:{$sum:1}}},
{$project: { _id: 0,matches:1,otherField:otherField}}, <-- include otherField
{$sort: {matches:-1 }},
callback
);
Is this possible or should I be using a forLoop or MapReduce for this particular step? I'm looking for something really efficient.
The $project pipeline operator would not let you inject the object, but you can probably insert the object id earlier in the $group operator. If you have a collection:
db.foo.save({_id:1,tags:['a','b']})
db.foo.save({_id:2,tags:['b','c']})
db.foo.save({_id:3,tags:['c','d']})
You can then write:
db.foo.aggregate({
$unwind: "$tags"},{
$match: { tags: {$in: ['b','c'] } }},{
$group: { _id: "$_id", matches: {$sum: 1 }, otherField: {$min: new ObjectId()} }},{
$project: { _id: 0, matches: 1, otherField: 1 }},{
$sort: { matches: -1 }})
The $min or $max can be used here, but it expects an operator or reference to a field so you have to give it one..