简体   繁体   中英

How to filter child array data in mongodb collection?

The following code joins 'cruises' and 'rooms' collections.

    dbo.collection('cruises').aggregate([
      { $lookup: {from: 'rooms', localField: 'roomTypes.roomID', foreignField: 'roomID', as: 'roomTypes'} },
      { 
        $project: {
          _id: 0,
          'roomTypes': {
            _id: 0
          }
        }
      }
    ]).toArray(function(err, data) {
      if (err) {
        logger.error(`getCruises : Error reading cruises db`);
        logger.error(`  Error: ${err}`);
        callback(err, null);
      } else {
        let cruisesData = data;
        callback(null, cruisesData);
      }
    });

to produce the following output. The roomTypes comes from 'rooms' collection.

[
{
  "cruiseID": "00001",
  "title": "some title",
  "description": "some desc"
  "roomTypes": [
    {
      "roomID": "IPD",
      "roomDetails": {
        "roomType": "some type",
        "title": "some title",
        "description": "desc",
        "maxOccupants": 2
      },
      "capacity": [
        {
          "cruiseID": "00001",
          "available": 20
        },{
          "cruiseID": "00002",
          "available": 10
        }
      ]
},
{
  "cruiseID": "00002",
  "title": "some other title",
  "description": "some other desc"
  "roomTypes": [
    {
      "roomID": "IPD",
      "roomDetails": {
        "roomType": "some type",
        "title": "some title",
        "description": "desc",
        "maxOccupants": 2
      },
      "capacity": [
        {
          "cruiseID": "00001",
          "available": 20
        },{
          "cruiseID": "00002",
          "available": 10
        }
      ]
}
]

How do I change it to get the following output. Ie to show the capacity for the matching cruiseID . If it would be easier to achieve it with changed data model, feel free to suggest it as well.

[
{
  "cruiseID": "00001",
  "title": "some title",
  "description": "some desc"
  "roomTypes": [
    {
      "roomID": "IPD",
      "roomDetails": {
        "roomType": "some type",
        "title": "some title",
        "description": "desc",
        "maxOccupants": 2
      },
      "capacity": 20
},
{
  "cruiseID": "00002",
  "title": "some other title",
  "description": "some other desc"
  "roomTypes": [
    {
      "roomID": "IPD",
      "roomDetails": {
        "roomType": "some type",
        "title": "some title",
        "description": "desc",
        "maxOccupants": 2
      },
      "capacity": 10
}
]

You can use a extra pipeline stage at the end of your pipeline stages,

  • $map to iterate loop of roomTypes array
  • $reduce to check condition if cruiseID match then return available
  • $mergeObjects with current object of roomTypes and return document
  // <= skipping your pipeline stages
  {
    $addFields: {
      roomTypes: {
        $map: {
          input: "$roomTypes",
          in: {
            $mergeObjects: [
              "$$this",
              {
                capacity: {
                  $reduce: {
                    input: "$$this.capacity",
                    initialValue: 0,
                    in: {
                      $cond: [
                        { $eq: ["$$this.cruiseID", "$cruiseID"] },
                        "$$this.available",
                        "$$value"
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }

Playground


Second possible way you can do this,

Playground

You could do a simple array mapping.

Note:

This is just a workaround, you could probably improve your schema or query or something.

Here's the code. Basically just map the nested capacity property of each cruise and use find method to find the matching capacity and pluck the available property.

 var data = [{ "cruiseID": "00001", "title": "some title", "description": "some desc", "roomTypes": [{ "roomID": "IPD", "roomDetails": { "roomType": "some type", "title": "some title", "description": "desc", "maxOccupants": 2 }, "capacity": [{ "cruiseID": "00001", "available": 20 }, { "cruiseID": "00002", "available": 10 }] }] }, { "cruiseID": "00002", "title": "some other title", "description": "some other desc", "roomTypes": [{ "roomID": "IPD", "roomDetails": { "roomType": "some type", "title": "some title", "description": "desc", "maxOccupants": 2 }, "capacity": [{ "cruiseID": "00001", "available": 20 }, { "cruiseID": "00002", "available": 10 }] }] } ] var test = data.map(cruise => { return { ...cruise, roomTypes: cruise.roomTypes.map(room => { return { ...room, capacity: room.capacity.find(c => c.cruiseID === cruise.cruiseID).available } }) } }); console.log(test);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM