Display results according to calendar weeks in Mongodb - mongodb

I have a MongoDB collection named Bookings
{
"_id" : ObjectId("5fca982d219fee6f00e631a0"),
"price" : 45.9,
"createdAt" : ISODate("2020-12-04T20:12:29.117Z")
}
{
"_id" : ObjectId("5fca990b219fee6f00e631a1"),
"price" : 45.9,
"createdAt" : ISODate("2020-12-04T20:16:11.925Z")
}
{
"_id" : ObjectId("5fcab925a912a2064fe7b916"),
"price" : 45.9,
"createdAt" : ISODate("2020-12-04T22:33:09.958Z")
}
{
"_id" : ObjectId("5fcab938a912a2064fe7b917"),
"price" : 45.9,
"createdAt" : ISODate("2020-12-04T22:33:28.641Z")
}
{
"_id" : ObjectId("5fcab94aa912a2064fe7b918"),
"createdAt" : ISODate("2020-12-04T22:33:46.118Z")
}
{
"_id" : ObjectId("5fcb73e0e396cf18e6141dc6"),
"price" : 45.9,
"createdAt" : ISODate("2020-12-05T11:49:52.544Z")
}
{
"_id" : ObjectId("5fcb73eee396cf18e6141dc7"),
"price" : 45.9,
"createdAt" : ISODate("2020-12-05T11:50:06.914Z")
}
{
"_id" : ObjectId("5fcbee785ef206248fa9513e"),
"price" : 35.7,
"createdAt" : ISODate("2020-12-05T20:32:56.508Z")
}
{
"_id" : ObjectId("5fcbf0045ef206248fa9513f"),
"price" : 2047.66,
"createdAt" : ISODate("2020-12-05T20:39:32.369Z")
}
I need to display the data according to a week and collective price for that week. If I use aggregation pipeline, It would only give me the range of dates on which booking is made.
{$group: {
_id: {
$week: "$createdAt"
},
start_date: {$min: "$createdAt"},
end_date: {$max: "$createdAt"}
}}
Suppose the previous week started from 14-06-21 and ended on 20-06-21
Instead, I want a result which would actually include start_date as 14-06-21 and end_date as 20-06-21, and if no earning is made it would be 0 otherwise the total price in a given week and so on for other group of weeks for whole year or month accordingly.

You can categorize total price by week number using $week operator, but it is hard to get the week's start date and end date in MongoDB, I would suggest you to get start date and end date from the week number in your client-side language.
$group by createdAt's week using $week operator and get total price by $sum
db.collection.aggregate([
{
$group: {
_id: { $week: "$createdAt" },
totalPrice: { $sum: "$price" }
}
}
])
Playground

For fetching the start day of a week, you can make use of the $dateToString operator and pass the %g and %v in format which represents ISO Year and Week of the year respectively.
Similarly, add 518400000 (6 days in milliseconds) to the start date of the week to get the end date.
Also, these two operations will only work inside the _id field of the $group stage, so parse the sub-object of the _id key to get the required data values. The weekNo key is useless for the $group stage, but keep it if it's required.
db.collection.aggregate([
{
$group: {
_id: {
"weekNo": {
$week: "$createdAt"
},
"start_date": {
"$dateFromString": {
"dateString": {
"$dateToString": {
"date": "$createdAt",
"format": "%G/%V",
},
},
"format": "%G/%V"
}
},
"end_date": {
"$add": [
{
"$dateFromString": {
"dateString": {
"$dateToString": {
"date": "$createdAt",
"format": "%G/%V",
},
},
"format": "%G/%V"
}
},
518400000,
],
},
},
totalPrice: {
$sum: "$price"
}
}
}
])
Mongo Playground Sample Execution

Related

Get sum of a column from mongodb along with the list of another column

I have a collection "employees" with sample entries as below-
{
"_id" : ObjectId("62ccaa238a322322211"),
"employeeId" : "1234",
"date" : ISODate("2022-07-11T12:00:00.000+0000"),
"hours" : 15.0,
"createdBy" : "user1",
"createdDate" : ISODate("2023-02-19T21:54:27.213+0000"),
"updatedBy" : "user1",
"updatedDate" : ISODate("2023-02-19T21:54:27.213+0000"),
},
{
"_id" : ObjectId("62ccaa238a322388821"),
"employeeId" : "1234",
"date" : ISODate("2022-07-10T12:00:00.000+0000"),
"hours" : 25.0,
"createdBy" : "user1",
"createdDate" : ISODate("2023-02-19T22:54:27.213+0000"),
"updatedBy" : "user1",
"updatedDate" : ISODate("2023-02-19T22:54:27.213+0000"),
}
I am trying to get sum of hours for each employee along with the list of dates for those entries
{
employeeId :"1234"
hours : 40 // sum of the hours from both entries
dates : [2022-07-11, 2022-07-10] // list of `date` column
}
I tried below one but dont know how to adapt to get employeeId and sum
db.getCollection("employees").aggregate( [
{ $match : {
$and :[
{"employeeId" : "1234"},
{"date" : { $lte: new ISODate("2023-02-19") }}
]}},
{
$group:
{
"_id": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$date"
}
},
totalAmount: { $sum: "$hours" }
}
}
] )
You should group by employeeId instead of date.
db.collection.aggregate([
{
$group: {
_id: "$employeeId",
hours: {
$sum: "$hours"
},
dates: {
$push: {
$dateTrunc: {
date: "$date",
unit: "day"
}
}
}
}
}
])
Mongo Playground

Average interval time in Hrs, Minutes, seconds Mongodb

I am trying to get the average time interval for all the documents in a collection.
The output I am trying to figure out is in this format Average: HH:MM:SS
It will compute the time interval for each document and then aggregate it to get the average time interval for the whole data set.
This is sample data.
{
"_id" : ObjectId("60dc1e7d72296329347b2bbe"),
"name": "firstupdate",
"starttime" : ISODate("2021-06-30T07:38:06.926Z"),
"endtime" : ISODate("2021-06-30T12:35:08.265Z"),
},
{
"_id" : ObjectId("60dc1e7d72296329347b2bce"),
"name": "secondupdate",
"starttime" : ISODate("2021-07-29T07:41:06.926Z"),
"endtime" : ISODate("2021-07-30T01:52:07.937Z"),
},
{
"_id" : ObjectId("60dc1ff472d9f809d6d2f23e"),
"name": "thirdupdate",
"starttime" : ISODate("2021-07-15T07:43:06.926Z"),
"endtime" : ISODate("2021-07-14T10:34:13.269Z"),
},
{
"_id" : ObjectId("60dc204e03362e293a5f5014"),
"name": "fourthupdate",
"starttime" : ISODate("2021-07-21T05:11:23.654Z"),
"endtime" : ISODate("2021-07-21T09:46:33.000Z"),
},
{
"_id" : ObjectId("60dc21436a9e0e09f9a551ae"),
"name": "fifthupdate",
"starttime" : ISODate("2021-07-07T02:34:06.926Z"),
"endtime" : ISODate("2021-07-07T08:11:06.926Z"),
},
Thank you in advance
You can use this one:
db.collection.aggregate([
{
$group: {
_id: null,
diff: {
$avg: {
$dateDiff: {
startDate: "$starttime",
endDate: "$endtime",
unit: "millisecond"
}
}
}
}
},
{
$set: {
diff: {
$dateToString: {
date: { $toDate: "$diff" },
format: "%H:%M:%S"
}
}
}
}
])
Optionally use format: "%j %H:%M:%S",
%j is day of year, i.e. this would return valid output up to one year. Otherwise you would need some Date math.
Mongo Playground

I have an array of objects and i want to get the latest createdAt and then apply a filter of date range if it falls in that date and then count it

{
"_id" : ObjectId("61a765e6f664eb8f6b12c"),
"details" : [
{
"_id" : ObjectId("60c84d9968c2d100154f3391"),
"expiryDate" : ISODate("2021-06-12T05:30:00.000Z"),
"updatedAt" : ISODate("2021-06-15T06:50:01.046Z"),
"createdAt" : ISODate("2021-06-10T06:50:01.046Z")
},
{
"_id" : ObjectId("60c84d99c2d100154f3391"),
"expiryDate" : ISODate("2021-06-25T05:30:00.000Z"),
"updatedAt" : ISODate("2021-06-15T06:50:01.046Z"),
"createdAt" : ISODate("2021-06-16T06:50:01.046Z")
},
{
"_id" : ObjectId("60c84d9968c20154f3391"),
"expiryDate" : ISODate("2021-06-25T05:30:00.000Z"),
"updatedAt" : ISODate("2021-06-15T06:50:01.046Z"),
"createdAt" : ISODate("2021-06-15T06:50:01.046Z")
}
]
}
How can i write mongo query to sort and get the latest date and then apply date range filter on that
You can $addFields an auxilary field lastCreatedAt by using $max. Then $match on the field in an aggregation pipeline.
db.collection.aggregate([
{
"$addFields": {
"lastCreatedAt": {
$max: "$details.createdAt"
}
}
},
{
"$match": {
lastCreatedAt: {
// input your date range here
$gte: ISODate("2012-06-16T06:50:01.000Z"),
$lt: ISODate("2021-12-30T06:50:01.100Z")
}
}
},
{
$group: {
_id: null,
docs: {
$push: "$$ROOT"
},
numOfLastCreatedAt: {
$sum: 1
}
}
}
])
Here is the Mongo playground for your reference.

how correctly use toDate in group query

I'm working on a query which is grouping records per day and counting them on MongoDB
here is my query
db.getCollection('CustomerApplications').aggregate(
[
{
$group:
{
_id: { day: { $dayOfYear: { $toDate: "$data.submittedAt" }}, year: { $year: { $toDate: "$data.submittedAt" } } },
count: { $sum: 1 }
}
}
]
)
$data.submittedAt is a double so I need to convert it to date then pull $dayOfYear from it
but I get
Unrecognized expression '$toDate'
my data structure is like
{
"_id" : ObjectId("5c942f50dae240feb1942b00"),
"data" : {
"id" : "624c0d17-b683-4c89-9d7c-011577d4e3b8",
"email" : "i8888#eee.com",
"name" : "ianh",
"phoneNumber" : "+1222222",
"score" : 12,
"status" : "PENDING",
"submittedAt" : 1553215312006.0,
"surveyVersion" : "1"
},
"updatedAt" : ISODate("2019-03-21T00:41:52.192Z")
}
any Idea is this doable in MongoDB if yes how to correctly do it?
$toDate New in version 4.0. Please check your version
Can you try with this.
db.getCollection('CustomerApplications').aggregate(
[
{
$group:
{
_id : { $substr: ["$data.submittedAt", 0, 10] },
count: { $sum: 1 }
}
}
])
May this will help you
$toDate - Converts a value to a date (New in version 4.0)
$dayOfMonth - Returns the day of the month for a date as a number between 1 and 31
$dayOfYear - Returns the day of the year for a date as a number between 1 and 366

Aggregation query which returns other fields

I have data which looks like this.
{
"badgeId" : "ventura",
"date" : ISODate("2016-12-22T21:26:40.382+0000"),
"mistakes" : NumberInt(10)
}
{
"_id" : "a4usNGibIu",
"badgeId" : "dog",
"date" : ISODate("2016-12-21T21:26:40.382+0000"),
"mistakes" : NumberInt(10)
}
{
"_id" : ObjectId("580c77801d7723f3f7fe0e77"),
"badgeId" : "dog",
"date" : ISODate("2016-11-24T21:26:41.382+0000"),
"mistakes" : NumberInt(5)
}
I need documents grouped by badgeId where the mistakes is smallest and the corresponding date
I cannot use $min, $max, $first, $last on for the date in $group because I need the date from the row where mistakes is lowest.
I tried the following query where I am using $min, but it won't give the intended result as it will pick $min of the date
db.Badges.aggregate([
{
$match: otherMatchConditions
},
{
$group: {
_id: '$badgeId',
date: {
$min: '$date'
},
mistakes: {
$min: '$mistakes'
}
}
}
])
You may sort the results by mistakes and then take the corresponding $first of mistakes and date
[
{$sort: {mistakes: 1}},
{
$group: {
_id: '$badgeId',
date: {
$first: '$date'
},
mistakes: {
$first: '$mistakes'
}
}
}
]
I think your query is right but as you see dates are invalid here.
ISODate("2016-14-22T21:26:41.382+0000") and ISODate("2016-13-22T21:26:40.382+0000"),
in both dates you can see months is 13 and 14 , which is not valid month. Below are right data after putting in mongodb.
{
"_id" : ObjectId("580ca86c9a43fad551ba801f"),
"badgeId" : "ventura",
"date" : ISODate("2016-12-22T21:26:40.382Z"),
"mistakes" : 10
}
{
"_id" : "a4usNGibIu",
"badgeId" : "dog",
"date" : ISODate("2016-12-23T21:26:40.382Z"),
"mistakes" : 10
}
{
"_id" : ObjectId("580c77801d7723f3f7fe0e77"),
"badgeId" : "dog",
"date" : ISODate("2016-12-24T21:26:40.382Z"),
"mistakes" : 5
}
When applied your query
db.getCollection('COLLECTION_NAME').aggregate([
{
$group: {
_id: '$badgeId',
date: {
$min: '$date'
},
mistakes: {
$min: '$mistakes'
}
}
}
])
I got the below result.
{
"_id" : "dog",
"date" : ISODate("2016-12-23T21:26:40.382Z"),
"mistakes" : 5
}
{
"_id" : "ventura",
"date" : ISODate("2016-12-22T21:26:40.382Z"),
"mistakes" : 10
}