Combine $facet result with subdocument and then conditionally excluding document

Viewed 248

Suppose after the $facet stage I have a result including two arrays: roomInfo and hotelInfo.

Which looks like this:

{
  "roomInfo": [
    {
      _id: 'ab1',
      booked: 3
    },
    {
      _id: 'ab2',
      booked: 1
    }
  ],
  "hotelInfo": [
    {
      name: 'Radison Blue',
      roomDetails: [
        {
          _id: 'ab1',
          roomCount: 5
        },
        {
          _id: 'xy1',
          roomCount: 5
        }
      ]
    },
    {
      name: 'Intercontinental',
      roomDetails: [
        {
          _id: 'ab2',
          roomCount: 5
        }
      ]
    }
  ]
};

Expected Result

I want an output like this:

[
  {
    name: 'Radison Blue',
    roomDetails: [
      {
        _id: 'ab1',
        roomCount: 5,
        booked: 3
      },
      {
        _id: 'xy1',
        roomCount: 5,
        booked: 0
      }
    ]
  },
  {
    name: 'Intercontinental',
    roomDetails: [
      {
        _id: 'ab2',
        roomCount: 5,
        booked: 1
      }
    ]
  }
];

Basically, adding the booked property from roomInfo into the hotelInfo's roomDetails field after matching their ids.

  1. Additionally, after getting the above output result I want to exclude those hotels on which all the rooms(not for a single room) have the value of fields roomCount and booked equal. I want to do this inside the aggregation pipeline stage as I will have to deal with $skip and $limit later on.

How to achieve these use cases?

Thanks!

1 Answers

Basically the approach will be iterating over the hotels and matching each room accordingly, here is a quick working code sample:

db.collection.aggregate([
  {
    $unwind: "$hotelInfo"
  },
  {
    $project: {
      name: "$hotelInfo.name",
      "roomDetails": {
        $filter: {
          input: {
            $map: {
              input: "$hotelInfo.roomDetails",
              as: "info",
              in: {
                "$mergeObjects": [
                  "$$info",
                  {
                    "$arrayElemAt": [
                      {
                        $filter: {
                          input: "$roomInfo",
                          as: "room",
                          cond: {
                            $eq: [
                              "$$room._id",
                              "$$info._id"
                            ]
                          }
                        }
                      },
                      0
                    ]
                  }
                ]
              }
            }
          },
          as: "proccessedInfo",
          cond: {
            $ne: [
              "$$proccessedInfo.roomCount",
              "$$proccessedInfo.booked"
            ]
          }
        }
      }
    }
  }
])

Mongo Playground

With that said you mention you'd like to paginate calls in the future. the current approach does not seem scaleable, because these are "real data points" aka hotels it's fine if your scale is somewhat capped ( no more than several thousands hotels ). but if it's not I recommend you ask another question with the entire pipeline you have so we can adjust it to work better.

Related