I've a collection called events. Sample document is like this.
I want to select documents with in date range of '2019-01-11' to '2019-11-27'.
What I've done is this. But this seems not working.
How do I achieve this using MongoDB Mongoose?
$match: {
createdAt: {
$gte: {
$dayOfYear: '2019-01-11'
},
$lte: {
$dayOfYear: '2019-11-27'
}
}
}
Use the Date() object instead. I am not sure if this affects the timezone as well.
db.collection.find({
"createdAt": {
"$gte": new Date('2019, 1, 11'),
"$lt" : new Date(2019, 11, 27)
}
})
Related
So I try to use MongoDB $match to get data between 2 dates, but it turns out that the data is not returning a.k.a empty here. What it looks like:
db.collection.aggregate([
{
$match: {
date: {
$gte: new Date("2022-10-23"),
$lt: new Date("2022-10-25"),
},
}
},
{
$group: {
_id: "$title",
title: {
$first: "$title"
},
answer: {
$push: {
username: "$username",
date: "$date",
formId: "$formId",
answer: "$answer"
}
}
}
},
])
Here is the data that I try to run on the Mongo playground:
https://mongoplayground.net/p/jKx_5kZnJNz
I think there is no error with my code anymore... but why it gives an empty return.
Migrate the comment to the answer post for the complete explanation.
Issue 1
The document contains the date field as a string type while you are trying to compare with Date which leads to incorrect output.
Ensure that you are comparing both values in the exact type.
Either that migrate the date value to Date type or
converting the date field to Date type in the query via $toDate.
{
$match: {
$expr: {
$and: [
{
$gte: [
{
$toDate: "$date"
},
new Date("2022-10-23")
]
},
{
$lt: [
{
$toDate: "$date"
},
new Date("2022-10-25")
]
}
]
}
}
}
Issue 2
Since you are using $lt ($lt: new Date("2022-10-25")), it won't include the documents with date: new Date("2022-10-25").
For inclusive end date, you shall use $lte.
Demo # Mongo Playground
I have tried using mongo db aggregation pipeline with the elemMatch operator but it doesn't output the result that i need, but if i use the same conditions inside a find() it works perfectly. plz help me with this issue
working version when using find()
Bookings.find(
{
sessionDates: { $elemMatch: { $gte: startDate, $lt: endDate } },
tourId: tourId,
sessionStatus: "PENDING"
}
)
not working when using with aggregation
Bookings.aggregate(
[
{
$match: {
sessionDates: { $elemMatch: { $gte: startDate, $lt: endDate } },
tourId: tourId,
sessionStatus: "PENDING"
}
}
]
);
here is a sample of the data I am using
{
"sessionDates": [
"2022-05-16T00:00:00.000Z",
"2022-05-17T00:00:00.000Z",
"2022-05-18T00:00:00.000Z"
],
"_id": "6228592690b8903618a95280",
"tourId": "62270fb22e7c5942d010b151",
"sessionStatus": "PENDING",
"createdAt": "2022-03-09T07:37:10.237Z",
"updatedAt": "2022-03-09T07:38:24.003Z",
"__v": 0
}
Mongoose does not cast aggregation pipeline stages (1), (2) and you have to do it manually and make sure the values have the correct type, in your example you must cast tourId to an ObjectId using mongoose.Types.ObjectId and the same thing for startDate and endDate if sessionDates values type is Date and not String:
Bookings.aggregate(
[
{
$match: {
sessionDates: { $elemMatch: { $gte: startDate, $lt: endDate } },
// If sessionDates values type is `Date`
// sessionDates: { $elemMatch: { $gte: new Date(startDate), $lt: new Date(endDate) } },
tourId: new mongoose.Types.ObjectId(tourId),
sessionStatus: "PENDING"
}
}
]
);
I have db schema that has string date format("date":"2020-09-01 16:07:45").
I need to search between given date range, I know this is possible if we're using ISO date format but I'm not sure if we can query with date format being string.
I have tried the following query, it doesn't seem to show accurate results.
db.daily_report_latest.find({"date":{$gte: "2021-01-01 00:00:00", $lte:"2021-03-01 00:00:00"}},{"date":1})
Is there any alternative to this? Appreciate your help.
You're right, you can't query a date field with a string, but you can just cast it to date type like so:
Mongo Shell:
db.daily_report_latest.find({
"date": {$gte: ISODate("2021-01-01T00:00:00Z"), $lte: ISODate("2021-03-01T00:00:00Z")}
}, {"date": 1});
For nodejs:
db.daily_report_latest.find({
"date": {$gte: new Date("2021-01-01 00:00:00"), $lte: new Date("2021-03-01 00:00:00")}
}, {"date": 1});
For any other language just check what the mongo driver date type is and do the same.
Note that the mongo shell isn't able to parse the string input in the format you provided, you should read here about the supported formats and transform your string pre-query like I did.
Another thing to consider for the nodejs usecase is timezones, the string will be parsed as the machine current timezone so again you need to adjust to that.
You can use $dateFromString feature of aggregation. (Documentation)
pipeline = []
pipeline.append({"$project": {document: "$$ROOT", "new_date" : { "$dateFromString": { "dateString": '$date', "timezone": 'America/New_York' }}}})
pipeline.append({"$match":{"new_date": {"$gte": ISODate("2021-01-01 00:00:00"), "$lte":ISODate("2021-03-01 00:00:00")}}})
data = db.daily_report_latest.aggregate(pipeline=pipeline)
So in the both the solutions, first typecast the date field in DB to date and then compare it with your input date range.
SOLUTION #1: For MongoDB Version >= 4.0 using $toDate.
db.daily_report_latest.find(
{
$expr: {
$and: [
{ $gte: [{ $toDate: "$date" }, new Date("2021-01-01 00:00:00")] },
{ $lte: [{ $toDate: "$date" }, new Date("2021-03-01 00:00:00")] }
]
}
},
{ "date": 1 }
)
SOLUTION #2: For MongoDb version >= 3.6 using $dateFromString.
db.daily_report_latest.find(
{
$expr: {
$and: [
{ $gte: [{ $dateFromString: { dateString: "$date" }}, new Date("2021-01-01 00:00:00")] },
{ $lte: [{ $dateFromString: { dateString: "$date" }}, new Date("2021-03-01 00:00:00")] }
]
}
},
{ "date": 1 }
)
I have below collection data in mongo db.
"enddate" : ISODate("2019-03-27T14:30:00.000Z"),
"date" : ISODate("2019-03-27T10:30:00.000Z"),
I have two date like start date "2019-03-26T19:30:00.000Z" and end date "2019-03-26T20:30:00.000Z"
I want to find above two date time period exits in collection or not.
Please help to make mongodb query.
advt.date = m.utc().toISOString();
advt.enddate = me.utc().toISOString();
advt.time = m.utc().toISOString();
advt.endtime = me.utc().toISOString();
var Query = Advertisement.find({
$or: [
{ $and:[{ date: { $gte: advt.date }, enddate:{ $lte: advt.enddate } }] } ,
{ $and:[{ enddate: { $gte: advt.date }, date:{ $lte: advt.enddate } }] }
],"ad_type":"splash", "isDeleted":false, "_id":{ $ne: advt._id }
});
You can use ObjectId.getTimestamp() for that purpose.
Also check this Link
In the following query I'm trying to find entries in my articles collection made in the last week, sorted by the number of votes on that article. The $match doesn't seem to work(maybe I dont know how to use it). The following query works perfectly, so its not a date format issue,
db.articles.find(timestamp:{
'$lte':new Date(),
'$gte':new Date(ISODate().getTime()-7*1000*86400)}
})
But this one doesn't fetch any results. Without the $match it also fetches the required results(articles sorted by votecount).
db.articles.aggregate([
{
$project:{
_id:1,
numVotes:{$subtract:[{$size:"$votes.up"},{$size:"$votes.down"}]}}
},
{
$sort:{numVotes:-1}
},
{
$match:{
timestamp:{
'$lte':new Date(),
'$gte':new Date(ISODate().getTime()-7*1000*86400)}
}
}
])
You are trying to match at the end of your pipeline, which supposes you have projected timestamp field, and you haven't done that.
I believe what you want is to filter data before aggregation, so you should place match at the top of your aggregation array.
Try this:
db.articles.aggregate([{
$match: {
timestamp: {
'$lte': new Date(),
'$gte': new Date(ISODate().getTime() - 7 * 1000 * 86400)
}
}
}, {
$project: {
_id: 1,
numVotes: {
$subtract: [{
$size: "$votes.up"
}, {
$size: "$votes.down"
}]
}
}
}, {
$sort: {
numVotes: -1
}
}])