I have a ranks collection with a permissions field which are bitwise operators:
[
{
"_id": "xxxx",
"name": "Rank 1",
"permissions": 1
},
{
"_id": "xxxxxxxxx",
"name": "Rank 2",
"permissions": 2
}
]
Example users:
[
{
"_id":"1234",
"ranks":[
"xxxx",
"xxxxxxxxx"
]
}
]
The users collection containts a ranks
value, which stores an array of the rank ids.
I'm wanting to get the user, and their ranks and set their permissions to a value.
const users = await this.collection.aggregate([
{
$match: { userID: '123' }
},
{ $limit: 1 },
{
$lookup: {
from: 'ranks',
localField: 'rank',
foreignField: '_id',
as: 'ranks'
}
},
{
$set: {
permissions: {
$arrayElemAt: ['$rank.permissions', 0]
}
}
},
{
$unwind: {
path: '$rank',
preserveNullAndEmptyArrays: true
}
}
]).toArray();
This obviously gets 1 value from the collection, I'm wanting to get all permissions and add the bitwise operators together.
Expected Output
{
"_id": "1234",
"ranks":[
"xxxx",
"xxxxxxxxx"
]
"permissions":3
}
Any help is appreciated!
CodePudding user response:
Here's one way to "or" all the rank permissions by using a server-side javascript "$function"
.
db.users.aggregate([
{
"$match": {
"_id": 42
}
},
{
"$lookup": {
"from": "ranks",
"localField": "ranks",
"foreignField": "_id",
"pipeline": [
{
"$project": {
"_id": 0,
"permissions": 1
}
}
],
"as": "permissions"
}
},
{
"$set": {
"permissions": {
"$function": {
"body": "function(perms) {return perms.reduce((prevV, currV) => prevV | currV, 0)}",
"args": ["$permissions.permissions"],
"lang": "js"
}
}
}
}
])
Try it on mongoplayground.net.
CodePudding user response:
With sample collection...
db = {
"permissions": [
{
"_id": "xxxx",
"name": "Rank 1",
"permissions": 1
},
{
"_id": "xxxxxxxxx",
"name": "Rank 2",
"permissions": 2
},
{
"_id": "xxxxxxx",
"name": "Rank 4",
"permissions": 4
}
],
"users": [
{
"_id": "1234",
"ranks": [
"xxxx",
"xxxxxxxxx"
]
},
{
"_id": "4567",
"ranks": [
"xxxx",
"xxxxxxx"
]
}
]
}
...try the following aggregation, which...
- Finds the
_id
for the user1234
in theusers
collection. - Looks for all the corresponding ranks in the
permissions
collection. - Unwinds to have one result per corresponding permission.
- Aggregates the permissions and ranks.
db.users.aggregate([
{
$match: {
"_id": "1234"
}
},
{
$lookup: {
from: "permissions",
localField: "ranks",
foreignField: "_id",
as: "ranks"
}
},
{
$unwind: "$ranks"
},
{
$group: {
_id: "$_id",
ranks: {
$push: "$ranks._id"
},
permissions: {
$sum: "$ranks.permissions"
}
}
}
])
See MongoDB playground at...
Important Note: This query groups the permissions by sum (rather than by boolean logical OR), so you must ensure that there are no duplicate permissions. If you can't ensure unique permissions per user, then suggest that the permissions
are $push
ed like the ranks
, and then perform some post processing on the list of permissions
to reduce via logical OR...