I want to query mongo for documents in date range and also I want to get nerest one but outside of this range. For example:
Documents in db:
{id: 1, dDate: 2024.01.10}
{id: 2, dDate: 2024.01.11}
{id: 3, dDate: 2024.01.22}
{id: 4, dDate: 2024.01.23}
{id: 5, dDate: 2024.01.24}
{id: 6, dDate: 2024.01.30}
{id: 7, dDate: 2024.01.31}
I want to query for dates – gte: 2024.01.22 and lte: 2024.01.24
and in a result I want to receive documents:
{id: 2, dDate: 2024.01.11}
{id: 3, dDate: 2024.01.22}
{id: 4, dDate: 2024.01.23}
{id: 5, dDate: 2024.01.24}
{id: 6, dDate: 2024.01.30}
so basicity I want to get documents in range and also the nearest one (in the both sides) to this range
2
Answers
$facet
– Allow multiple pipelines to be executed in an aggregate query.1.1. "inRange" – Get the document with
dDate
within the search date range.1.2. "beforeRange" – Get the first matching document with
dDate
is before the starting search date range.1.3. "afterRange" – Get the first matching document with
dDate
is after the ending search date range.$set
– Add thedocs
field by combining the three array fields into a single array.$unwind
– Deconstruct thedocs
array field into multiple documents.$replaceWith
– Replace the input document with thedocs
object.$sort
– Order the document by thedDate
field ascending.Demo @ Mongo Playground
You can use
$setWindowFields
to get the previous and next date for each entry. Afterwards, you can decide whether a document should be included in the result by checking whether any of the dates is in your range:Above aggregation pipeline first sets the
prev
andnext
fields to the corresponding dates; then it adds a temporary fieldinclude
that is set totrue
if the document should be included in the output. After filtering the documents with a$match
stage, the temporary fields are removed from the documents so that the result is ready:You can check the mongoplayground here.
The pipeline can be optimized a bit by checking the include-condition directly in the match and omitting the temporary field; however, I hope that the query engine is able to sort this out. I’ve kept the field for demonstration purposes.
Sorting the data is necessary only once during the
$setWindowFields
stage.