I have the below code snippet which will retrieve Date and count from a MongoDb collection from a specific date. Example: Retrieve date, count from 05-05-2020.
||Date||Count||
|05-06-2020|4|
|05-07-2020|25| and so on.
i want to add another logic to retrieve aggregate sum of 7 days instead of individual dates. Appreciate any help.
mongoClient.db().collection(COLLECTION.AUDIT).aggregate([
{
$match: { created_at: { $gt: date } }
},
{
$group: {
_id: {
$dateToString: { format: "%Y-%m-%d", date: "$created_at" }
},
count: { $sum: 1 }
}
},
{
$sort: { "_id": -1 }
}
])
The simplest way to do what I think you're asking would be to transform your group operator to $week instead of $dateToString. Since a week is 7 days, this will group all the documents from the same week, and return a count of the documents, along with the number of the week. To get both results from 1 query, combine them into a facet. So:
mongoClient.db().collection(COLLECTION.AUDIT).aggregate([
{
$match: { created_at: { $gt: date } }
},
{
$facet: {
by_week: {
$group: {
_id: { $week: $created_at},
count: { $sum: 1 }
},
{ $sort: { "_id": -1 }}
},
by_day: {
$group: {
_id: {
$dateToString: { format: "%Y-%m-%d", date: "$created_at" }
},
count: { $sum: 1 }
}
},
{ $sort: { "_id": -1 }}
}
},
])
Related
I am trying to show results where the sum of records is greater or equal to 4 and the status matches a string. If I leave off the status field it works fine but adding it in always gives me an empty array even when there should be data.
const bookings = await Booking.aggregate([
{
$group: {
_id: {
$dateToString: {
format: "%Y/%m/%d",
date: "$bookingDate",
},
},
totalBookings: {
$sum: 1,
},
},
},
{
$match: {
totalBookings: {
$gte: 4,
},
status: "Accepted",
},
},
]);
Each booking will have it's own status. So you need to add that as part of $group
{
$group: {
_id: {
status: "$status",
"d": {
$dateToString: {
format: "%Y/%m/%d",
date: "$bookingDate",
}
},
},
totalBookings: {
$sum: 1,
},
}
}
Then you need to change your match as below
$match: {
totalBookings: {
$gte: 4,
},
"_id.status": "Accepted",
}
It will give you all the Accepted Booking on the given BookinDate which is >= 4.
I'm trying to group Orders array within the time interval and group them by date, sort them, and have all orders split into days. However, I'd like to sort the orders array on each day sorted within each day as well.
Orders.aggregate([{
$match: {
'created_at': {
$gte: timeInterval, //match last 3 days
}
}
}, {
"$group": {
_id: {
$dateToString: { format: "%d/%m/%Y", date: "$created_at", timezone: "Australia/Melbourne" } // group by date
},
orders: { $push: '$$ROOT' }
}
}, {
$sort: { '_id': -1 } // sort by date
}])
const OrderSchema = new Schema({
...,
created_at: {
type: Date,
default: Date.now
},
})
exData=[{_id: 26/12/2021, orders:[...]},{_id: 25/12/2021, orders:[...]}, ]
// need to sort orders array
I've tried:
{
$sort: { '_id': -1, "orders.created_at": -1 }
}
I would appreciate any help. Thanks.
Your aggregation pipeline should be looked as below:
$match - Filter documents by condition.
$sort - Sort documents by created_at.
$group - Group by created_at and add orders for the accumulated field.
Orders.aggregate([
{
$match: {
'created_at': {
$gte: timeInterval, //match last 3 days
}
}
},
{
$sort: { "created_at": -1 }
},
{
$group: {
_id: {
$dateToString: { format: "%d/%m/%Y", date: "$created_at", timezone: "Australia/Melbourne" } // group by date
},
orders: { $push: '$$ROOT' }
}
}
])
I collect data off my database table. I'd like to manipulate one of the fields I'm getting back from the aggregate() method.
Currently, this is how I use aggregate() method:
const weeklyLogs = await Log.aggregate([
{ $match: { timestamp: { $gte: moment.tz('Asia/Jerusalem').subtract(6, 'days').startOf('day').toDate() } } },
{
$group: {
_id: {
$dateFromParts: {
year: { $year: { date: "$timestamp", timezone: "Asia/Jerusalem" } },
month: { $month: { date: "$timestamp", timezone: "Asia/Jerusalem" } },
day: { $dayOfMonth: { date: "$timestamp", timezone: "Asia/Jerusalem" } },
timezone: "Asia/Jerusalem"
}
},
start: {
$sum: {
$cond: [{ $eq: ['$eventName', 'connect'] }, 1, 0]
}
},
end: {
$sum: {
$cond: [{ $ne: ['$eventName', 'connect'] }, 1, 0]
}
}
}
}
]);
This is how timestamp field (which is of type Data) looks in my DB (example): 2020-09-24T05:25:42.608+00:00. So basically, When I get back the data from the method, it typically looks like:
end: 0
start: 9
_id: "2020-10-09T21:00:00.000Z"
But I'd like get back in the _id field the format of dd/mm/yyyy instead of 2020-10-09T21:00:00.000Z. How could I manipulate it in the aggregate() method?
You could use the built-in $dateToString utility:
{
$group: {
_id: {
$dateToString: {
format: "%d/%m/%Y",
date: "$timestamp"
}
},
start: {
$sum: {
$cond: [{
$eq: ['$eventName', 'connect']
}, 1, 0]
}
},
end: {
$sum: {
$cond: [{
$ne: ['$eventName', 'connect']
}, 1, 0]
}
}
}
}
I have a collection which contains half million data, and i want an average for all months between the date i enter. Right now i am getting the data for whole year, but i want it seperated by single month i.e 12 data range for every single month.
Below is the aggregation pipeline i am using.
let filter = 'y';
const date = new Date();
let checkDate = moment().subtract(1.5, 'years')._d;
MeterData.aggregate([
{
$group: {
_id: "$meter_id",
// total: { $sum: 1 },
totalEnergy: filter !== 'a' ? {
$sum: {
$toDouble: {
$cond: {
if: {
$gte: [
"$date", checkDate
]
},
then: "$energy.Energy",
else: 0
}
}
}
} : { $sum: { $toDouble:
"$energy.Energy"
} }
},
}
]);
Here i am getting totalEnergy for all year, in totalEnergy field, but now i want totalEnergy plus monthly calculations for the year i enter.
Any idea on how to do that. ?
Below is a sample document from the collection.
{"_id":{"$oid":"5e557779ed588826d84cef11"},
"meter_id":"1001",
"date":{"$date":{"$numberLong":"1509474600000"}},
"parameter_name":"hvac","voltage":{"unit":"V"},
"current":{"unit":"AMP"},
"powerFactor":{"unit":"phi"},
"angle":{"unit":"degree"},
"activePower":{"unit":"kwh"},
"reactivePower":{"unit":"kwh"},
"apparentPower":{"unit":"kwh"},
"frequency":{"unit":"hz"},
"thd":{"unit":"percentage"},
"energy":{"Energy":"5.7"},
"power":{"unit":"watt"},
As per suggested by Ryan Gunner, i got my answer which i am pasting below, i just have one more problem.
[
{
meter_id: '1001',
month: '2017-10',
totalEnergy: 0,
averageEnergy: 0
} + 11 more months......
]
Now what i need is the total of the energy for 12 months. For example total of totalEnergy field for all 12 months in a single variable.
how about something like this?
var startDate = new ISODate('2020-04-01');
var endDate = new ISODate('2019-04-01');
db.collection.aggregate(
{
$match: {
$expr: {
$and: [
{ $gt: ['$date', endDate] },
{ $lt: ['$date', startDate] }]
}
}
},
{
$group: {
_id: {
meter: '$meter_id',
month: { $dateToString: { format: '%Y-%m', date: '$date' } }
},
totalEnergy: { $sum: { $toDouble: '$energy.Energy' } },
averageEnergy: { $avg: { $toDouble: '$energy.Energy' } }
}
},
{
$project: {
meter_id: '$_id.meter',
month: '$_id.month',
totalEnergy: '$totalEnergy',
averageEnergy: '$averageEnergy',
_id: 0
}
},
{
$sort: { meter_id: 1 }
}
{
$group: {
_id: null,
grandTotalEnergy: { $sum: '$totalEnergy' },
monthlyData: { $push: '$$ROOT' }
}
},
{ $project: { _id: 0 } }
)
update: added grandTotalEnergy field and pushed monthlyData to an array.
Here is a sample document.
{"_id":{"$oid":"5e557779ed588826d84cef11"},
"meter_id":"1001",
"date":{"$date":{"$numberLong":"1509474600000"}},
"parameter_name":"hvac","voltage":{"unit":"V"},
"current":{"unit":"AMP"},
"powerFactor":{"unit":"phi"},
"angle":{"unit":"degree"},
"activePower":{"unit":"kwh"},
"reactivePower":{"unit":"kwh"},
"apparentPower":{"unit":"kwh"},
"frequency":{"unit":"hz"},
"thd":{"unit":"percentage"},
"energy":{"Energy":"5.7"},
"power":{"unit":"watt"},
And there are around 100 000 documents. I want to filter out the documents whose date is greater than the date i specify and calculate the total energy i.e energy.Energy
I used the below aggregation, but it doesn't seem to be working
const endDate = new Date(12-12-2018)
MeterData.aggregate([
{
$group: {
_id: "$meter_id",
total: { $sum: 1 },
totalEnergy: { $sum: { $toDouble: "$energy.Energy"
} },
dateSum: {
$sum: {
$toDouble: {
$not: [{
$cond: {
if: {
$gte: [
"$date", endDate
]
},
then: "$energy.Energy",
else: 0
}
}
]
}
}
}
}
}
])
Would be this:
db.collection.aggregate([
{ $match: { date: { $gte: ISODate("2016-12-12") } } },
{
$group: {
_id: "$meter_id",
total: { $sum: 1 },
totalEnergy: { $sum: "$energy.Energy" }
}
}
])
See Mongo playground