HOWTO · MongoDB
How to Find Objects Between Two Dates in MongoDB
Learn to query MongoDB documents by date range, compare dates, and choose comparison operators for inclusive or exclusive boundaries.
On this page
MongoDB date-range queries compare a stored BSON Date field with Date values. Use the field name that appears in your documents, and write range bounds in UTC when that is the intended time zone.
Query documents between two dates in MongoDB
For a data collection whose day field is stored as a BSON Date, use db.data.find({ day: { $gte: ISODate("2022-01-21T00:00:00Z"), $lt: ISODate("2022-01-24T00:00:00Z") } }). This range includes the start instant and excludes the end instant, so it covers the UTC dates January 21 through January 23. Replace data and day with your collection and date-field names.
The next runnable example is the executable counterpart to this date-range query: it uses the same day field and the same inclusive start and exclusive end instants. It models comparisons locally and does not connect to MongoDB.
Run this example:
const records = [
{ day: new Date("2022-01-20T00:00:00Z"), amount: 40 },
{ day: new Date("2022-01-21T00:00:00Z"), amount: 32 },
{ day: new Date("2022-01-22T00:00:00Z"), amount: 19 },
{ day: new Date("2022-01-23T00:00:00Z"), amount: 29 },
{ day: new Date("2022-01-24T00:00:00Z"), amount: 35 },
];
const start = new Date("2022-01-21T00:00:00Z");
const end = new Date("2022-01-24T00:00:00Z");
const matches = records.filter(({ day }) => day >= start && day < end);
for (const { day, amount } of matches) {
console.log(`${day.toISOString()} amount=${amount}`);
}
2022-01-21T00:00:00.000Z amount=32
2022-01-22T00:00:00.000Z amount=19
2022-01-23T00:00:00.000Z amount=29
Choose inclusive or exclusive date boundaries
MongoDB comparison operators define whether a bound is included. $gt means strictly greater than and $lt means strictly less than; neither includes a document exactly at its bound. $gte means greater than or equal to, and $lte means less than or equal to; each includes equality. Combine $gte with $lt for a common start-inclusive, end-exclusive interval. Use $gte and $lte together when both exact endpoint instants should match.
Choose bounds as instants, not just calendar labels. For a full UTC day, an end-exclusive query can start at midnight on that day and end at midnight on the following day. This avoids guessing the final millisecond of the day.
Find documents after or before a date
For documents after a point, use db.data.find({ day: { $gt: ISODate("2022-01-22T00:00:00Z") } }); this omits a document exactly at that instant. Use $gte if it should match. For documents before a point, use db.data.find({ day: { $lt: ISODate("2022-01-22T00:00:00Z") } }); use $lte to include the instant itself. A one-sided query needs only one comparison operator inside the date field’s condition.
Compare date and timestamp values
A BSON Date stores a UTC instant with millisecond precision, so the same range pattern works for timestamps. For example, query an arrival-time field with db.flights.find({ PassengerArrivalTime: { $gte: ISODate("2018-05-19T11:10:23Z"), $lt: ISODate("2018-08-25T16:40:12Z") } }). Include the Z when the supplied text represents UTC. If the source time is in another time zone, convert it to the correct UTC instant before using it as a bound.
Check BSON Date types and time zones
Store the field as a BSON Date, not a string such as "2022-01-21". Date comparison operators generally compare values within compatible BSON types; a string date is not a substitute for a Date value. In mongosh, ISODate("2022-01-21T00:00:00Z") creates a Date value for the query. In application code, construct the driver’s date type from a well-defined instant and pass it as a Date parameter.
A date-only value does not identify a universal instant until you choose a time zone. Decide whether the intended calendar day is UTC or a local zone, then convert both range bounds consistently. For local calendar days, calculate the next local midnight using that zone’s rules and convert each boundary to UTC; do not assume every local day has the same elapsed duration. If a query unexpectedly omits records, verify the stored BSON type, field name, and UTC instants at both bounds.