I have two collections, resource-policies
and role-permissions
. I'm trying to get all the permissions for resource1
, including the ones that are defined in the matching record from role-permissions
.
resource-policies
{
resource: 'resource1',
permissions: [
'permission:read',
'role:admin'
]
}
role-permissions
{
name: 'role:admin',
permissions: ['permission:write', 'permission:delete']
}
Desired Result
[
{
resource: 'resource1',
permissions: [
'permission:read',
'permission:write',
'permission:delete'
]
}
]
Here's my current attempt. I'm stuck on the $map
projection to create the final combinded permissions field.
resourcePoliciesCollection.aggregate([
{
$match: {
$expr: {
$eq: ['$resource', resource]
},
},
},
{
$lookup: {
from: 'role-permissions',
localField: 'permissions',
foreignField: 'permissions',
as: 'rolePermissions',
},
},
{
$project: {
_id: -1,
permissions: {
$map: {
input: '$permissions',
in: {
$cond: [
{ $eq: ['$$this', '$rolePermissions.name'] },
'$rolePermissions.permissions',
'$$this',
],
},
},
},
resource: 1,
},
}
])
But this produces the following, which is without the permissions from role-permissions
.
{
"_id": ObjectId("5a934e000102030405000000"),
"permissions": [
"permission:read",
"role:admin"
],
"resource": "resource1"
}
CodePudding user response:
Your schema is suggesting a recursive structure. I prefer using $graphLookup
for this reason and perform $setUnion
to get all the permissions. Finally do a filter to remove the role entries(i.e. entries starting with "role:")
db.resourcepolicies.aggregate([
{
$match: {
$expr: {
$eq: [
"$resource",
"resource1"
]
}
}
},
{
"$graphLookup": {
"from": "rolepermissions",
"startWith": "$permissions",
"connectFromField": "permissions",
"connectToField": "name",
"as": "rpLookup"
}
},
{
"$project": {
_id: 0,
resource: 1,
permissions: {
"$reduce": {
"input": "$rpLookup",
"initialValue": "$permissions",
"in": {
"$setUnion": [
"$$value",
"$$this.permissions"
]
}
}
}
}
},
{
"$addFields": {
"permissions": {
"$filter": {
"input": "$permissions",
"as": "p",
"cond": {
// remove permissions entry which contains "role:"
$eq: [
-1,
{
"$indexOfCP": [
"$$p",
"role:"
]
}
]
}
}
}
}
}
])