Home > Back-end >  Filter nested of nested in Mongoose Populate
Filter nested of nested in Mongoose Populate

Time:09-18

I have an object that looks like this: (that is the output of Mongoose query)

let systems = [
    {
        "maxUserLevel": 1,
        "subsystems": [
            {
                "sections": [],
                "name": "apple"
            },
            {
                "sections": [
                    {
                        "name": "banana"
                    }
                ],
                "name": "sun",
            },
            {
                "sections": [],
                "name": "orange"
            }
        ],
        "systemID": "12345"
    },
    {
        "maxUserLevel": 3,
        "subsystems": [
            {
                "sections": [],
                "name": "blue"
            },
            {
                "sections": [
                    {
                        "name": "pink"
                    }
                ],
                "name": "red",
            },
        ],
        "systemID": "15654"
    }];

The Mongoose query:

this.model.System.find({username: user.username}, {
    _id: 0,
    allowedOrganizations: 0,
    name: 0,
    updatedAt: 0,
    createdAt: 0,
    versionKey: 0
})
    .populate(
        {
            path: "subsystems",
            populate: {
                path: "sections",
                select: "name -_id",
                match: {
                    allowedUsers: user.id
                }
            },
            select: "name metadata -_id",
        }
    )
    .exec((error, systems) => {
        return res.status(200).json({
            data: systems,
            success: true
        });
    });

I'm looking for a way to removes the subsystems that do not have sections. After hours of searching I think there's no way to filter populate based on nested populate, so I tried with some ways like this:

if (systems.subsystems.length > 0) {
    let test = [];
    systems.subsystems.forEach((value, index) => {
        if (value.sections.length !== 0) {
            test[index] = value;
        }
        if (systems.subsystems.length === index   1) {
            return test;
        }
    })
}

But I'm not sure if this is the correct way.

CodePudding user response:

You can use an aggregate query with $filter like this:

db.collection.aggregate([
  {
    "$project": {
      "_id": 1,
      "maxUserLevel": 1,
      "subsystems": {
        "$filter": {
          "input": "$subsystems",
          "as": "s",
          "cond": {
            "$ne": [
              "$$s.sections",
              []
            ]
          }
        }
      }
    }
  }
])

Example here

Also your query should contains a $match stage (like your find stage) and $lookup.

CodePudding user response:

I'm not sure this is the best way, but it solved my problem:

const _ = require('lodash');

systems.forEach((value, index) => {
    systems[index].subsystems = _.filter(value.subsystems,
        item => !item.sections.length == 0
    );

    if (systems.length === index   1) {
        return systems;
    }
});

It removes all subsystems that do not have sections.

  • Related