I've got a collection of documents in MongoDB that all have a "date" field, which is an ISO8601 formatted date string (i.e. created by the moment.js format() method).
I'd like to be able to efficiently run queries against this collection that expresses the sentiment "documents that have a date that is after A and before B" (i.e. documents within a range of dates).
Should I be storing my dates as something other than ISO-8601 strings? Contingent upon that answer, what would the MongoDB query operation look like for my aforementioned requirement? I'm envisioning something like:
{$and: [
{date: {$gt: "2017-05-02T03:15:22-04:00"}},
{date: {$lt: "2017-06-02T03:15:22-04:00"}},
]}
Does that "just work"? I need some convincing.
You definitely want to use the built-in date data type with an index on your date field and not strings. String comparison is going to be slow as hell compared to comparing dates which are just 64bit integers.
As far as querying is concerned, check out the answer here:
return query based on date
Related
We have a collection holding 20M+ documents. It's a frequent operation to query it by time range.
Also there are some other fields like type, category.
We found if we search data in long range, like a month, with {modified: {$gte: new Date("2022-12-01"), $lte: new Date("2022-12-31")}, ...}, it costs more than {modifiedStr: {$gte: "2022-12-01", $lte: "2022-12-31"}, ...}.
Of course they both hits their indexes.
According my knowledge, index on Date field has better carinality than date string.
Counld anyone give us a explaination on this? Or this is just a illusion.
Will B+ tree depth be the answer?
Suppose I have documents in a mongo collections with a timestamp field. I want to query the documents based on the timestamp value (greater than, less than). In order to do that, instead of calculating each time the timestamp for my current date, I would like to embed the conversion from the date to timestamp in the query. I tried something like this (suppose "ts" is my timestamp field):
db.my_collection.find({"ts": {$lt: {$toLong : new Date("2020-12-09")}}})
instead of doing:
db.my_collection.find({"ts": {$lt: 1578524400}})
but it seems to return an empty result.
Is there a result to perform the date-to-timestamp conversion inside the query?
You can use $toLong but it's an aggregation pipeline operator, you need an aggregation pipeline not a plain find.
I've googled and googled this, and for the life of me I can't make it work...which I know I am just missing something totally simple, so I'm hoping someone here can save my sanity.
I have am trying to lookup a range of documents from a mongodb collection (using mongoose) based on a date range.
I have this code:
var startDate = new Date(req.query.startDate);
var stopDate = new Date(req.query.stopDate);
studentProgression.find({ $and: [ {'ACT_START': {$gte: startDate, $lte: stopDate} } ]})
But it doesn't return any documents.
The date in the MongoDb collection is stored as a string, and looks like this (for example):
ACT_START: "25-MAY-20"
a
I know I'm probaby tripping somewhere with the fact it's a string and not a date object in mongo, as I haven't had this issue before. I'd rather not go through the collection and change all the string dates to actual date objects.
Is there anyway to do this lookup the way I've laid it out?
Unfortunately, you have to change the format of your ACT_START field and cast it to a Date.
By doing $gte and/or $lte on a string field, mongo will compare the two strings based on their alphabetical order.
I have the following query on mongo
db.getCollection('someCollection').find({"status":"failed","start_date": {$gt: new Date("2019/03/01")}})
that will retrieve all the records that have a failed status and the start_date is equal or greater than "2019/03/01".
But when i try to only retrieve records specifically for "2019/03/01":
db.getCollection('someCollection').find({"status":"failed","start_date": {$eq: new Date("2019/03/01")}})
It doesn't retrieve anything.
$lt and $gt queries work is just $eq that doesn't work. is that the correct way to use the $eq?
thank you
When you use new Date("2019/03/01") the actual date being searched is 2019/03/01 00:00:00.00. That is, the Date is exactly midnight 2019/03/01 (down to the millisecond). Unless your record also has the exact same date recorded, it will not match. That's why you need to use {$gt: new Date("2019/03/01"), $lt: new Date("2019/03/02")}. Just think of it as that 1 "day" is actually a range of 24 hours. Which is why you need to specify it as a range, and not as a simple $eq comparison.
The reason why your first query works is because when you search for $gt 2019/03/01 you're really searching for $gt 2019/03/01 00:00:00.00. And so, of course every record started on 2019/03/01 will match.
One thing to take note of: technically, if you have a document made exactly at midnight i.e. with a timestamp of 2019/03/01 00:00:00.00, it won't match. So you really should use {$gte: new Date ('2019/03/01')} (note the extra 'e'). $gte is greater than or equal. This may sound trivial but is actually important, because if you don't use actual timestamps and record just the date when you create the record (i.e. you insert with {start_date: new Date('2019/03/01')}, all those timestamps will actually have 00:00:00.00 as their time component, and they won't match with a $gt comparison, only a $gte comparison. You probably use new Date() when creating the record, so you're getting the full timestamp, which is why it hasn't bitten you yet. But to be semantically correct, you should use $gte in your first query. Does that make sense?
I have a collection that contains a dateAcquired attribute (which is from an XML API Feed the app is consuming).
I am trying to write a .find() query that will pull back all of the entries that are greater than or equal to 1 month ago from today.
The dateAcquired field date looks like: "dateAcquired": "2014-03-28 06:08 AM".
How to do that query in mongodb?
As Neil Lunn already stated, you should use timestamps for your dates in mongo.
More information to parse dates and so on are here
If you use timestamps, then you may use something like this as find selector over you mongo collection:
{dateacquired:{$gte: date_from, $lte: date_to}}
You can calculate the dates with momentjs (recommended) or whatever.