Home > Blockchain >  MongoDB Aggregate Missing Nested Object
MongoDB Aggregate Missing Nested Object

Time:01-18

I am using MongoDB natively in Node (latest I believe). I have a collection of users (example object):

{
    uid: 'FifUPgoJLOLz872',
    email: '[email protected]',
    firstname: 'Bobby',
    lastname: 'Tables',
    role: 'admin'
}

And a collection of roles (example object):

{
    role: 'admin',
    permissions: [
        {
            permission: 'MANAGE_DATA',
            type: 'DATA',
            view: true,
            add: true,
            update: true,
            del: true
        },
        {
            permission: 'MANAGE_DATA_ENTRY',
            type: 'DATA',
            view: true,
            add: true,
            update: true,
            del: true
        },
    ]
}

I am trying to find a specific user and return user information along with the permissions array from the role collection based on the role in the user in the user collection.

I am using this aggregate function, which is correctly finding the user object, but it is not returning the nested "user" object in the result as defined by the projection.

const data = db.collection("users");
    data.aggregate([
        {$match: {uid: res.locals.uid}}, //matches the user correctly
        {$lookup: {from: 'roles', localField: 'role', foreignField: 'role', as: 'Roles'}},
        {$unwind: '$Roles'},
        {$addFields: {"permissions": '$Roles.permissions'}},
        {$project:{ user:{uid: 1, email: 1, firstname: 1, lastname: 1}, permissions: 1, _id: 0}}
    ]).toArray(function(err, result) {
        if (err)
        {
            console.log(err);
        }
        console.log(result);
});

The match is working, as 'role' is being fed into the lookup stage but for some reason it is not including it as a separate object. If I include the user fields in the projection without being nested, they come out as expected.

Actual Result:

[
   {
     permissions: [
       [Object], [Object]

     ]
   }
]

Expected Result:

[
   {
      user: {
          uid: 'FifUPgoJLOLz872',
          email: '[email protected]',
          firstname: 'Bobby',
          lastname: 'Tables',
          role: 'admin'
      },
      permissions: [
         [Object], [Object]

     ]
   }
]

Any idea why this is?

CodePudding user response:

In your $project clause, you are using 1. That means keeping the field. user:{uid: 1, ... means keeping the field user.uid, which is not present.

The correct way to achieve what you want is:

db.users.aggregate([
  {
    $match: {
      uid: "FifUPgoJLOLz872"
    }
  },
  //matches the user correctly
  {
    $lookup: {
      from: "roles",
      localField: "role",
      foreignField: "role",
      as: "Roles"
    }
  },
  {
    $unwind: "$Roles"
  },
  {
    $project: {
      user: {
        uid: "$uid",
        email: "$email",
        firstname: "$firstname",
        lastname: "$lastname",
        role: "$Roles.role"
      },
      permissions: "$Roles.permissions",
      _id: 0
    }
  }
])

Mongo Playground

  • Related