Reputation: 8922
I m building an application in which I use to manage projects. A projects looks like the following :
{
"_id": ObjectId("..."),
"title": "MySuperProject",
"files": [
{
"title":"My skiing day !",
"right":[{
"role":"USER",
"access":["read"]
}]
},
{
"title":"My little dog, so cute !",
"right":[{
"role":"OTHER",
"access":["read"]
}]
}
]
}
We can see two different roles here : USER
and OTHER
.
When I get the above project with the USER
role, I need to have the following representation, without the OTHER
file :
{
"_id": ObjectId("..."),
"title": "MySuperProject",
"files": [
{
"title":"My skiing day !",
"right":{
"role":"USER",
"access":["read"]
}
}]
}
Does it exist a way to reduce a list inside of a document based on query or should I make it manually on the result ?
I m working on nodejs
and mongoose
.
Thanks for your help
EDIT : In fact the right
key was an ARRAY
Upvotes: 3
Views: 66
Reputation: 19700
This is one of the classic use cases of the $redact
stage. You could aggregate it as below:
var role = "USER";
var projectTitle = "MySuperProject";
db.t.aggregate([
{
$match: {
"title":projectTitle
}
},
{
$redact: {
$cond: [{
$eq: [role, {
$ifNull: ["$role", role]
}]
}, "$$DESCEND", "$$PRUNE"]
}
}
])
output:
{
"_id" : 1,
"title" : "MySuperProject",
"files" : [
{
"title" : "My skiing day !",
"right" : [
{
"role" : "USER",
"access" : [
"read"
]
}
]
},
{
"title" : "My little dog, so cute !",
"right" : [ ]
}
]
}
At each level, a document is evaluated, only if the document at the particular level, returns true to the $cond
presented by the $redact
stage, we $$DESCEND
into its sub-documents, else $$PRUNE
.
It would list you all the files per project, and an array of access roles for each file. If you would want to exclude files that the "user" has no rights on, you could $redact
again:
db.t.aggregate([
{
$match: {
"title": projectTitle
}
},
{
$redact: {
$cond: [{
$eq: [role, {
$ifNull: ["$role", role]
}]
}, "$$DESCEND", "$$PRUNE"]
}
},
{
$redact: {
$cond: [{
$gt: [{
$size: {
$ifNull: ["$right", [1]]
}
}, 0]
}, "$$DESCEND", "$$PRUNE"]
}
},
])
output:
{
"_id" : 1,
"title" : "MySuperProject",
"files" : [
{
"title" : "My skiing day !",
"right" : [
{
"role" : "USER",
"access" : [
"read"
]
}
]
}
]
}
The above approach avoids the costly $unwind
stage. It is always advisable to take different approaches and see which one suits you the best.
Upvotes: 4