Mehdi S.
Mehdi S.

Reputation: 471

mongo find only if every element match the condition

i want to find every room that are available in a given time-period by passing a start and a end date, every collection that fail to at least once in one of these two test needs to be entirely excluded from the find query.

for the moment, it looks like if at least one collection succeed to match one of these condition once, it is returned to me.

here is a sample of a collection

"resa": [
    {
        "_id": "5cf2a38372373620263c84f1",
        "start": "2019-06-01T15:23:00.000Z",
        "end": "2019-06-01T16:23:00.000Z"
    },
    {
        "_id": "5cf2a3a772373620263c84f2",
        "start": "2022-03-05T16:23:00.000Z",
        "end": "2022-03-05T17:23:00.000Z"
    }
]

and here is my attempt so far

$or: [
        { resa: { $all: [{ $elemMatch: { start: { $lt : req.query.start }, end: { $lt : req.query.start } } } ]} },
        { resa: { $all: [{ $elemMatch: { start: { $gt : req.query.end }, end: { $gt : req.query.end } } } ]} }
      ],

derivating from Mickl answer, i've tried it like so but it show me no results

  Post.find({ 
      capacity: { $gte : req.query.capacity },
      $expr: {
        $allElementsTrue: {
            $map: {
                input: "$resa",
                in: {
                    $or: [
                      {
                        $and: [
                          { $gte: [ "$$this.start", req.query.end ] },
                          { $gte: [ "$$this.end", req.query.end ] }
                        ]
                      },
                      {
                        $and: [
                          { $te: [ "$$this.start", req.query.start ] },
                          { $lte: [ "$$this.end", req.query.start ] }
                        ]
                      },
                      { resa: [] },
                  ]
                }
            }
        }
    }
    },

i've also tried to reverse the query by finding collection that are NOT matching condition that means they will not be available at the given period

      resa: {
        $elemMatch: { 
          $not: { 
            $or: [
              {
                $and: [
                { start: { $gte : req.query.start }},
                { start: { $lte : req.query.end } }]
              },
              {
                $and: [
                  { end: { $lte : req.query.end }},
                  { end: { $gte : req.query.start } }]
              },
            ],
          },
        },
      },

Upvotes: 2

Views: 81

Answers (1)

Mehdi S.
Mehdi S.

Reputation: 471

I managed to find the solution :

      resa: {
        $not: {
          $elemMatch: {
            $or: [
              {
                $and: [
                { start: { $gte : req.query.start }},
                { start: { $lte : req.query.end } }]
              },
              {
                $and: [
                  { end: { $gte : req.query.start }},
                  { end: { $lte : req.query.end } }]
              },
              {
                $and: [
                  { start: { $gte : req.query.start }},
                  { end: { $lte : req.query.end } }]
              },
              {
                $and: [
                  { start: { $lte : req.query.start }},
                  { end: { $gte : req.query.end } }]
              },
            ],
          },
        },
      },

the important part to understand is the assembly of

      resa: {
        $not: {
          $elemMatch: {
            $or: [
              {
                $and: [
                  { x: y},
                  { x: y }]
              },
              {
                $and: [
                  { x: y},
                  { x: y }]
              },
...

that is a bit confusing in the meaning : "i want to find all the collection that does not match {this and this} or {that and that}"

Upvotes: 1

Related Questions