0

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?

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

1 Comment

that worked perfectly. I thought it would build the nested object on the fly instead of look for the nested object, thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.