Get Days Between 2 MongoDB ISODates [duplicate] - mongodb

This question already has answers here:
Find the total time spent by an user in mongoDB
(1 answer)
How to find the hours difference between two dates in mongodb
(2 answers)
Closed 3 years ago.
I am trying to get the days difference between 2 ISODates and put it in days field. I have these documents below:
{
created_at: ISODate("2019-06-06TT00:00:00Z"),
completed_at: "2019-06-08"
},
{
created_at: ISODate("2019-06-06TT00:00:00Z"),
completed_at: null
},
{
created_at: ISODate("2019-06-06TT00:00:00Z"),
completed_at: "2019-06-04"
}
What I have tried so far is to get the milliseconds. But I don't want that. I just want to substract the dates and get the difference in days.
db.collection.aggregate([
{
$addFields: {
completed_at: {
$ifNull: [
{
"$dateFromString": {
"dateString": "$completed_at"
}
},
new ISODate()
]
}
}
},
{
$addFields: {
days: {
$cond: [
{"$lte": ["$completed_at", "$created_at"]},
0,
{
$divide: [
{
$subtract: [
"$completed_at",
"$created_at"
]
},
86400000
]
}
]
}
}
},
{
$project: {
_id: 0,
created_at: 1,
completed_at: 1,
days: 1
}
}
])
If completed_at field is null, then the value for this should be the current date. If completed_at is lesser than created_at, then days is 0. Let's say current date is June 6, 2019, desired result should be:
{
days: 2
},
{
days: 0
},
{
days: 0
}

I think I was able to get it. I removed the time in the date fields and the results that I wanted is showing correctly. Please let me know if I got it correctly or there are some adjustments that I need to make in order to make it faster. Thank you!
db.collection.aggregate([
{
$addFields: {
created_at: {
$dateFromParts: {
"year": {
$year: "$created_at"
},
"month": {
$month: "$created_at"
},
"day": {
$dayOfMonth: "$created_at"
}
}
},
completed_at: {
$ifNull: [
{
"$dateFromString": {
"dateString": "$completed_at"
}
},
{
$dateFromParts: {
"year": {
$year: new Date()
},
"month": {
$month: new Date()
},
"day": {
$dayOfMonth: new Date()
}
}
}
]
}
}
},
{
$addFields: {
days: {
$cond: [
{
"$lte": [
"$completed_at",
"$created_at"
]
},
0,
{
$divide: [
{
$subtract: [
"$completed_at",
"$created_at"
]
},
86400000
]
}
]
}
}
},
{
$project: {
_id: 0,
created_at: 1,
completed_at: 1,
days: 1
}
}
])

Related

How do I get the full hour before the latest in MongoDB?

I'm trying to get the second latest full hour. So if the time is 15:30 now, I'm trying to get 14:00, so I basically need to truncate the current minutes and then furthermore truncate an hour..
I'm trying to project the date like this:
// Let's say the current time is 15:46
"period": {
"start": 2022-11-03T14:00:00.000,
"end": 2022-11-03T15:00:00.000
}
It's gonna be something like this:
{
$project: {
period: {
start: {
"$subtract": [ {
$hour: {
"$toDate": "$$NOW"
}
}, 1 ]
},
end: {
"$subtract": [ {
$hour: {
"$toDate": "$$NOW"
}
}, 1 ]
},
}
}
How do I do that?
Do you mean this one?
db.collection.aggregate([
{
"$project": {
start: {
$dateSubtract: {
startDate: { $dateTrunc: { date: "$$NOW", unit: "hour" } },
unit: "hour",
amount: 1
}
},
end: { $dateTrunc: { date: "$$NOW", unit: "hour" } }
}
])
I'm not sure i understood well... But, in case, maybe something like this?
https://mongoplayground.net/p/9xALfPpdSdS
db.collection.aggregate([
{
"$project": {
hour: {
"$subtract": [
{
$hour: {
"$toDate": "$period.start"
}
},
1
]
}
}
},
])

How to get reading of collection for previous day, i.e., yesterday using aggregate in mongodb

I have data of various timestamps and I want to create an aggregate pipeline to get sum of a column having yesterdays date. And I don't want to hardcode current date to get yesterday date.
Please suggest how to do it as I am new to Mongodb
Edit :
collection name - consumption_data
documents -
1. id :101, timestamp : 2022-09-10T22:00:00.000+00:00, consumption: 199
2. id :106, timestamp : 2022-09-10T07:00:00.000+00:00, consumption: 201
3. id :108, timestamp : 2022-09-11T12:00:00.000+00:00, consumption: 77
4. id :109, timestamp : 2022-09-11T08:00:00.000+00:00, consumption: 773
If today is 2022-09-11 the I want consumption of yesterday(2022-09-10) without hardcoding the dates
Try this one:
db.consumption_data.aggregate([
{
$match: {
$expr: {
$gt: ["$timestamp", {
$dateSubtract: {
startDate: "$$NOW",
unit: "day",
amount: 1
}
}]
}
}
},
{ $group: { _id: null, consumption: { $sum: "$consumption" } } }
])
Consider the use of $dateTrunc, (i.e. { $dateTrunc: { date: "$$NOW", unit: "day" } }) otherwise it will go back exactly 24 hours from the current time
db.consumption_data.aggregate([
{
$match: {
$expr: {
$and: [
{
$gte: ["$timestamp",
{
$dateSubtract: {
startDate: { $dateTrunc: { date: "$$NOW", unit: "day" } },
unit: "day",
amount: 1
}
}
]
},
{
$lt: ["$timestamp",
{ $dateTrunc: { date: "$$NOW", unit: "day" } }
]
}
]
}
}
},
{ $group: { _id: null, consumption: { $sum: "$consumption" } } }
])
Here is a working solution:
db.totalConsumption_data.aggregate([
{
'$project': {
'month': {
'$month': '$timestamp'
},
'year': {
'$year': '$timestamp'
},
'day': {
'$dayOfMonth': '$timestamp'
},
'timestamp': 1,
'consumption': 1
}
}, {
'$match': {
'month': new Date().getMonth() +1,
'day': new Date().getDate()-1,
'year': new Date().getFullYear()
}
}, {
'$group': {
'_id': null,
'total': {
'$sum': '$consumption'
}
}
}
]

MongoDB: Search by field with date and update it by condition

Please tell me how can I fulfill the following condition - if the time in the info.startDate field is not equal to 00 hours, increase the date (2021-05-27) by 1 day ahead, set the time to 00:00:00.000Z. I tried to do it clumsily, through Mongock, getting all the elements of the collection and doing a check through LocalDateTime, but my heap overflowed, which is logical because the collection is large. How can I do this through Mongock or at least a manual request to MongoDB. So far I've only written this:
db.getSiblingDB("ervk_core").getCollection("supervision").updateMany(
{},
[
{
"$set": {
"info.startDate": {
"$cond": {
if: {
$eq: [
"$info.startDate",
(there should be a condition at midnight)
]
},
then: (here the day should be added to full and the time should be set to midnight)
}
}
}
}
])
I would like to use dateToString to do a partial search by hour, but as I understand it, this function can only be used in an aggregation.
I would be grateful for your help :)
If you're using Mongo version 5.0+ then you can use $dateTrunc and $dateAdd to achieve this quite easily, like so:
db.collection.updateMany(
{},
[
{
$set: {
"info.startDate": {
$cond: [
{
$ne: [
{
$hour: "$info.startDate"
},
0
]
},
{
$dateTrunc: {
date: {
$dateAdd: {
startDate: "$info.startDate",
unit: "day",
amount: 1
}
},
unit: "day",
}
},
"$info.startDate"
]
}
}
}
])
For older Mongo versions this is slightly messier, you should use $dateFromParts to create the new date object, like so:
db.collection.updateMany(
{},
[
{
$set: {
"info.startDate": {
$cond: [
{
$ne: [
{
$hour: "$info.startDate"
},
0
]
},
{
$dateFromParts: {
"year": {
$year: {
$add: [
"$info.startDate",
86400000
]
}
},
"month": {
$month: {
$add: [
"$info.startDate",
86400000
]
}
},
"day": {
$dayOfMonth: {
$add: [
"$info.startDate",
86400000
]
}
},
"hour": 0,
"minute": 0,
"second": 0,
"millisecond": 0,
}
},
"$info.startDate"
]
}
}
}
])
Mongo Playground

MongoDB group results by time interval

I have a collection like below.
{
"field1":"value1",
"created_at":"2022-01-01T11:42:01Z"
},
{
"field1":"value2",
"created_at":"2022-01-01T11:22:15Z"
}
I need to group the results by 15 minute time interval and project the results like below from this collection.
[{
"from":"2022-01-01T11:15:00Z",
"to":"2022-01-01T11:30:00Z",
"count":1
},
{
"from":"2022-01-01T11:30:00Z",
"to":"2022-01-01T11:45:00Z",
"count":1
}]
I am able to get the count by 15 minute time interval using the below query. But I want to project from and to dates as well.
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$created_at" },
"dayOfYear": { "$dayOfYear": "$created_at" },
"hour": { "$hour": "$created_at" },
"interval": {
"$subtract": [
{ "$minute": "$created_at" },
{ "$mod": [{ "$minute": "$created_at"}, 15] }
]
}
}},
"count": { "$sum": 1 }
}}
])
You can try an approach,
$dateToParts get parts of the created_at date
$group by year, month, day, hour, and interval as per mod and subtraction calculation and get the total count
to get from and to date from interval you can use $dateFromParts operator, just to add 15 minutes into the date.
db.collection.aggregate([
{
$addFields: {
created_at: { $dateToParts: { date: "$created_at" } }
}
},
{
$group: {
_id: {
year: "$created_at.year",
month: "$created_at.month",
day: "$created_at.day",
hour: "$created_at.hour",
interval: {
$subtract: [
"$created_at.minute",
{ $mod: ["$created_at.minute", 15] }
]
}
},
count: { $sum: 1 }
}
},
{
$project: {
_id: 0,
count: 1,
from: {
$dateFromParts: {
year: "$_id.year",
month: "$_id.month",
day: "$_id.day",
hour: "$_id.hour",
minute: "$_id.interval"
}
},
to: {
$dateFromParts: {
year: "$_id.year",
month: "$_id.month",
day: "$_id.day",
hour: "$_id.hour",
minute: { $add: ["$_id.interval", 15] }
}
}
}
}
])
Playground

MongoDB aggregation add months or years to a Date

We can use $add to add Dates in the aggregation pipe. Is there a way to add a specific number of time units (ie days months or years) except milliseconds?
The current way to add 3 years is date: { $add: [ "$date", 3*365*24*60*60000 ] }
My expected syntax format is date: { $add: [ "$date", { $years:3 } ] } which is not working
As mentioned in my comment, you will get this function Mongo 5.0
In the meantime you can use this workaround:
db.collection.aggregate([
{
$addFields: {
new_date: {
$dateFromParts: {
year: { $add: [{ $year: "$date" }, 3] },
month: { $month: "$date" },
day: { $dayOfMonth: "$date" },
hour: { $hour: "$date" },
minute: { $minute: "$date" },
second: { $second: "$date" },
millisecond: { $millisecond: "$date" }
}
}
}
}
])