MongoDB aggregates (time & avg) - mongodb

I wonder if it's possible to do an average over a MongoDb time series aggregate. For instance, an aggregate that gives the average temp for every minute.
My data looks like this:
[
{
"_id": "57fbebf99929a71d305e2bb2",
"temp": 23.77,
"dateTime": "2016-10-10T19:28:57.923Z",
"_dateTime": 1476127737000
},
{
"_id": "57fbebfa9929a71d305e2bb3",
"temp": 27.16,
"dateTime": "2016-10-10T19:28:58.838Z",
"_dateTime": 1476127738000
},
{
"_id": "57fbebff9929a71d305e2bb4",
"temp": 31.93,
"dateTime": "2016-10-10T19:29:03.848Z",
"_dateTime": 1476127743000
}
]
The code (javascript) looks like this so far..
var results = temperatures.aggregate(
[
{ $project : { "timeSpan" : {$add : [new Date(0),"$_dateTime"] } } },
{ $project : { "minuteRead" : { $minute : "$timeSpan" }} },
{
$group : {
_id : {minuteRead : "$minuteRead" },
count : { $sum : 1 }
}
}
],
function(err, result) {
console.log(result);
}
);
With the output of:
[ { _id: { minuteRead: 30 }, count: 7 },
{ _id: { minuteRead: 29 }, count: 12 },
{ _id: { minuteRead: 28 }, count: 2 } ]
But what I'd like to have is:
[ { _id: { minuteRead: 30 }, avgTemp: 17.6 },
{ _id: { minuteRead: 29 }, avgTemp: 18.3 },
{ _id: { minuteRead: 28 }, avgTemp: 20.1 } ]
Is this possible?
Thank you!

The "$avg" would do the trick
$group : {
_id : {minuteRead : "$minuteRead" },
avgTemp : { $avg :"$temp" }
}

Got it!
temperatures.aggregate(
[
{ $project: { temp:'$temp', "timeSpan": { $add: [new Date(0), "$_dateTime"] } }},
{ $project: { "timestamp": { $minute: "$timeSpan" }, temp:'$temp' } },
{
$group: {
_id: { minuteRead: "$timestamp" },
avgTemp : { $avg :"$temp" }
}
}
],
function (err, result) {
if (err)
console.log("ERROR " + err);
else
console.log(result);
}
);

Related

Grouping and summing after using $addToSet in MongoDB

Assume I have the following data:
[{
"type" : "DIVIDEND_OR_INTEREST",
"netAmount" : 2.43,
"transactionDate" : "2019-01-01T17:02:36+0000",
"transactionId" : 1,
"transactionItem" : {
"instrument" : {
"symbol" : "SPHD"
}
}
},
{
"type" : "DIVIDEND_OR_INTEREST",
"netAmount" : 5.00,
"transactionDate" : "2019-01-01T17:02:36+0000",
"transactionId" : 2,
"transactionItem" : {
"instrument" : {
"symbol" : "ATT"
}
}
},
{
"type" : "DIVIDEND_OR_INTEREST",
"netAmount" : 2.43,
"transactionDate" : "2019-02-01T17:02:36+0000",
"transactionId" : 3,
"transactionItem" : {
"instrument" : {
"symbol" : "SPHD"
}
}
},
{
"type" : "DIVIDEND_OR_INTEREST",
"netAmount" : 5.00,
"transactionDate" : "2019-02-01T17:02:36+0000",
"transactionId" : 4,
"transactionItem" : {
"instrument" : {
"symbol" : "ATT"
}
}
}]
I want to group the data by year and get a total sum for that year. I also want an array of the items used during the group, grouped by a field and summed, if that makes sense. This is ultimately what I want to end up with:
{
"year": [
{
"year": "2019",
"totalYear": 14.86,
"dividends": [
{
"symbol": "T",
"amount": 10.00
},
{
"symbol": "SPHD",
"amount": 4.86
}
]
}
]
}
Below is the code I have written so far using Mongoose. The problem is that I can't figure out how to group and sum the items that I added to the set. I could always do that in the application layer but I was hoping to accomplish this entirely inside of a query.:
const [transactions] = await Transaction.aggregate([
{ $match: { type: TransactionType.DIVIDEND_OR_INTEREST, netAmount: { $gte: 0 } } },
{
$facet: {
year: [
{
$group: {
_id: { $dateToString: { format: '%Y', date: '$transactionDate' } },
totalYear: { $sum: '$netAmount' },
dividends: {
$addToSet: {
symbol: '$transactionItem.instrument.symbol',
amount: '$netAmount',
},
},
},
},
{ $sort: { _id: 1 } },
{
$project: {
year: '$_id',
totalYear: { $round: ['$totalYear', 2] },
dividends: '$dividends',
_id: false,
},
},
],
},
},
]).exec();
It requires to do two group stages,
First group by year and symbol
Second group by only year
If the transactionDate field has date type value then just use $year operator to get the year
I would suggest you do $sort after the immediate $match stage to use an index if you have created or planning for future
const [transactions] = await Transaction.aggregate([
{
$match: {
type: TransactionType.DIVIDEND_OR_INTEREST,
netAmount: { $gte: 0 }
}
},
{ $sort: { transactionDate: 1 } },
{
$facet: {
year: [
{
$group: {
_id: {
year: { $year: "$transactionDate" },
symbol: "$transactionItem.instrument.symbol"
},
netAmount: { $sum: "$netAmount" }
}
},
{
$group: {
_id: "$_id.year",
totalYear: { $sum: "$netAmount" },
dividends: {
$push: {
symbol: "$_id.symbol",
amount: "$netAmount"
}
}
}
},
{
$project: {
_id: 0,
year: "$_id",
totalYear: 1,
dividends: 1
}
}
]
}
}
]).exec();
Playground

MongoDB group with project

I am trying to select maximum value of a field along with the time it occured.
db.temperaterdata.aggregate([
{
$match: {
$and: [
{ "organization_id": 37 },
{
"resulttime":{
$gte:'2020-05-01 00:00',
$lte:'2020-05-29 23:59'
}
}
]
}
},
{
"$group": {
"_id": "$userid",
maxTemperature: { $max: "$temperature"},
minTemperature: { $min: "$temperature"}
}
},
{
"$project": {
"resulttime":1,
maxTemperature:1,
minTemperature:1
}
}
]);
However, the time for which the maximum/minimum temperature has occurred it's not showing up. The result coming is like this:
{ "_id" : 233, "maxTemperature" : 100.67, "minTemperature" : 98.56 }
{ "_id" : 256, "maxTemperature" : 100.67, "minTemperature" : 98.56 }
{ "_id" : 263, "maxTemperature" : 100.67, "minTemperature" : 98.56 }
Any help will be much appreciated.
You need to order by userId + temperature and take max / min documents with $first / $last operators.
Try the query below:
db.temperaterdata.aggregate([
{
"$match": {
"organization_id": 37,
"resulttime": {
"$gte": "2020-05-01 00:00",
"$lte": "2020-05-29 23:59"
}
}
},
{
"$sort": {
"userid": 1,
"temperature": 1
}
},
{
"$group": {
"_id": "$userid",
"maxTemperature": {
"$last": "$$ROOT"
},
"minTemperature": {
"$first": "$$ROOT"
}
}
},
{
"$project": {
"maxresulttime": "$maxTemperature.resulttime",
"minresulttime": "$minTemperature.resulttime",
"maxTemperature": "$maxTemperature.temperature",
"minTemperature": "$minTemperature.temperature"
}
}
])
MongoPlayground

How to get grand total of columns in mongodb aggregate

I am using mongodb aggregate to show reports. my query is below :
db.campaigns_report.aggregate([
{ '$match' : { } },
{ '$group' : {
'_id': '$campaignId',
'campaignName' : { '$first': '$campaignName' },
'impressions' : { '$sum': '$impressions' }
}
},
{ '$project' : {'campaignName': '$campaignName', 'impressions': '$impressions'} },
{ '$facet' : {
'metadata': [ { '$count': "total"} ],
'data': [ { '$skip': 0 },{ '$limit': 10 } ]
}
}
]);
In the above query I want total sum of impressions in $facet along with total document count.
Thanks in advance.
To get total sum of impressions along with total document count you need to run $group specifying null as grouping _id and use $sum operator twice:
db.campaigns_report.aggregate([
{ '$match' : { } },
{ '$group' : {
'_id': '$campaignId',
'campaignName' : { '$first': '$campaignName' },
'impressions' : { '$sum': '$impressions' }
}
},
{ '$project' : {'campaignName': '$campaignName', 'impressions': '$impressions'} },
{ '$facet' : {
'metadata': [ { '$group': { _id: null, total: { $sum: 1 }, totalImpressions: { $sum: '$impressions' } } } ],
'data': [ { '$skip': 0 },{ '$limit': 10 } ]
}
}
])
Mongo Playground

I can nt make a sum in a nested mongo query

I tried all weekend to write this query, but it is not working. The nested field worked, but the other field does not show the $sum.
This is a example of the collections:
{
"_id": ObjectId("5dc28a3fd89a4d7bb82a75b4"),
"bedrijf": ObjectId("5c7ee51d2478a30fa4357b4c"),
"doelgroep": "Kinderen 12-",
"recreatieleider": 1,
"__v": 0
}
I like to group the key "bedrijf" and make a subgroup "doelgroep" The code I use is:
{
$group: {
_id: {
bedrijf: "$bedrijf",
doelgroep: "$doelgroep",
},
"totaal": {
$sum: 1
}
}
},
{
$group : {
_id : '$_id.bedrijf',
doelgroep : {
"$push": {
doelgroep:"$_id.doelgroep",
total:"$totaal"
}
},
"recreatieleider": {
$sum: "$recreatieleider"
}
}
}
But when I see the results the key "recreatieleder" does not make the sum of the entries.
{
"results": [
{
"_id": "5c69c5d939fbb38a1fcf3146",
"doelgroep": [
{
"doelgroep": "Gezinnen",
"total": 1
},
{
"doelgroep": "Kinderen 9-11",
"total": 9
}
],
"recreatieleider": 0
}
]
}
So how can I count the "recreatieleider" value?
My final expected output must be:
{
"results": [
{
"_id": "5c69c5d939fbb38a1fcf3146",
"doelgroep": [
{
"doelgroep": "Gezinnen",
"total": 1
},
{
"doelgroep": "Kinderen 9-11",
"total": 9
}
],
"recreatieleider": 20
}
]
}
added question
I ran to a other problem. You make me fixed the first problem. When a mak a other sub group it will not show me
I use this code
{
$group: {
_id: {
bedrijf: "$bedrijf",
doelgroep: "$doelgroep",
},
"totaal": {
$sum: 1
},
"hulpkrachten": {
$sum: "$hulpkrachten"
},
"recreatieleider": {
$sum: "$recreatieleider"
},
"stagiaires": {
$sum: "$stagiaires"
},
}
},
{
$group : {
_id : '$_id.bedrijf',
doelgroep : {
"$push": {
doelgroep:"$_id.doelgroep",
total:"$totaal"
}
},
soortactiviteit : {
"$push": {
soortactiviteit:"$_id.soortactiviteit",
total:"$totaal"
}
}
}
}
You can see I add "soortactiviteit" to it, but it wil not add u subgroup
The expeditor outcome must be
{
"results": [
{
"_id": "5c69c5d939fbb38a1fcf3146",
"doelgroep": [
{
"doelgroep": "Gezinnen",
"total": 1
},
{
"doelgroep": "Kinderen 9-11",
"total": 9
}
],
"soortactivieit": [
{
"doelgroep": "creativiteit",
"total": 20
},
{
"doelgroep": "sports,
"total": 9
}
],
"recreatieleider": 20
}
]
}
Maybe you can help with my last question of the subject.. Thank
Not sure, what you are trying to achieve with this query. However, below query works for your scenario.
{
$group:{
_id:{
bedrijf:"$bedrijf",
doelgroep:"$doelgroep",
},
"totaal":{
$sum:1
},
"recreatieleider":{
$sum:"$recreatieleider"
}
}
},
{
$group:{
_id:'$_id.bedrijf',
doelgroep:{
"$push":{
doelgroep:"$_id.doelgroep",
total:"$totaal"
}
},
"recreatieleider":{
$sum:"$recreatieleider"
}
}
}
When first $group runs the key recreatieleider is lost in
{
$group: {
_id: {
bedrijf: "$bedrijf",
doelgroep: "$doelgroep",
},
"totaal": {
$sum: 1
}
}
},
change it to and try then:
{
$group: {
_id: {
bedrijf: "$bedrijf",
doelgroep: "$doelgroep",
},
"totaal": {
$sum: 1
},
"recreatieleider": {
$sum: "$recreatieleider"
}
}
},

mongoDB aggregate with two percent by $group

My dataset :
{
"codepostal": 84000,
"siren": 520010234,
"type": "home"
},
{
"codepostal": 84000,
"siren": 0,
"type": "home"
},
{
"codepostal": 84000,
"siren": 450123003,
"type": "appt"
} ...
My pipeline (total is an integer) :
var pipeline = [
{
$match: { codepostal: 84000 }
},
{
$group: {
_id: { type: "$type" },
count: { $sum: 1 }
}
},
{
$project: {
percentage: { $multiply: ["$count", 100 / total] }
}
},
{
$sort: { _id: 1 }
}
];
Results :
[ { _id: { type: 'appt' }, percentage: 66 },
{ _id: { type: 'home' }, percentage: 34 } ]
Expected results is to count when "siren" is set to 0 or another number.
Count siren=0 => part
Count siren!=0 => pro
[ { _id: { type: 'appt' }, totalPercent: 66, proPercent: 20, partPercent: 80},
{ _id: { type: 'home' }, totalPercent: 34, proPercent: 45, partPercent: 55 } ]
Thanks a lot for your help !!
You can use $cond to get 0 or 1 for pro/part documents depending o value of siren field. Then it's easy to calculate totals for each type of document:
[
{
$match: { codepostal: 84000 }
},
{
$group: {
_id: { type: "$type" },
count: { $sum: 1 },
countPro: { $sum: {$cond: [{$eq:["$siren",0]}, 0, 1]} },
countPart: {$sum: {$cond: [{$eq:["$siren",0]}, 1, 0]} }
}
},
{
$project: {
totalPercent: { $multiply: ["$count", 100 / total] },
proPercent: { $multiply: ["$countPro", {$divide: [100, "$count"]}] },
partPercent: { $multiply: ["$countPart", {$divide: [100, "$count"]}] }
}
},
{
$sort: { _id: 1 }
}
]
Note that I used $divide to calculate pro/part percentage relative to the count of document within type group.
For your sample documents (total = 3) output will be:
[
{
"_id" : { "type" : "appt" },
"totalPercent" : 33.3333333333333,
"proPercent" : 100,
"partPercent" : 0
},
{
"_id" : { "type" : "home" },
"totalPercent" : 66.6666666666667,
"proPercent" : 50,
"partPercent" : 50
}
]