node.js - Filter multiple arrays with $redact -


i m trying make mongodb request fill filters first on list , on list.

explanations

i have following objects in database :

{   "_id": objectid("..."),   "title": "mysuperproject",   "files": [     {       "title":"my skiing day !",       "right":[{         "role":"user",         "access":["read"]       }]     },     {       "title":"my little dog, cute !",       "right":[{         "role":"other",         "access":["read"]       }]     }   ],  "people": [     {       "username":"borat",       "role":"otherone",       "right":[{         "role":"user",         "access":["read"]       }]     },     {       "username":"thomas",       "role":"other",       "right":[{         "role":"other",         "access":["read"]       }]     }   ] } 

what need

i need pass parameter function current user role. in case pass "user" role.

this way, need retrieve result :

{   "_id": objectid("..."),   "title": "mysuperproject",   "files": [     {       "title":"my skiing day !",       "right":[{         "role":"user",         "access":["read"]       }]     }   ],  "people": [     {       "username":"borat",       "role":"other",       "right":[{         "role":"user",         "access":["read"]       }]     }   ] } 

that reduces both list on item role matches mine.

what have

i have query reduces list of files "role" attribute.

the fact in people list, have 2 time role attribute :

  • one time determine people role
  • one time detemine kind of people can access (right access) people profile

and query reduces people resultset matching first role met (the people.role instead of people.right.role).

my query following :

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"]     }   }, ]) 

sum : need query reduces people , file list matching both right.role values

the $redact pipeline stage not best tool not translate "different conditions @ different levels" nor "treating differnt arrays differently" nature of it's intended function.

the better cases here plain old array filtering, there have been methods around time.

the best option $filter mongodb 3.2 if have that:

db.t.aggregate([     { "$project": {         "title": 1,         "files": {             "$filter": {                 "input": "$files",                 "as": "file",                 "cond": { "$eq": [ "$$file.right.role", "user" ] }             }         },         "people": {             "$filter": {                 "input": "$people",                 "as": "person",                 "cond": { "$eq": [ "$$person.right.role", "user" ] }             }         }     }} ]) 

for mongodb 2.6, , if array elements "distinct" , no 2 same within document, can "emulate" newer function using $map , $setdifference remove false results array:

db.t.aggregate([     { "$project": {         "title": 1,         "files": {             "$setdifference": [                 { "$map": {                     "input": "$files",                     "as": "file",                     "in": {                        "$cond": [                            { "$eq": [ "$$file.right.role", "user" ] },                            "$$file",                            false                        ]                     }                 }},                 [false]             ]         },         "people": {             "$setdifference": [                 { "$map": {                     "input": "$people",                     "as": "person",                     "in": {                        "$cond": [                            { "$eq": [ "$$person.right.role", "user" ] },                            "$$person",                            false                        ]                     }                 }},                 [false]             ]         }     }} ]) 

it's same basic conditional test, except in latter case $map returns element per array element provided input. either matched element or value of false, removed "set comparison" false $setdifference.

these both single pipeline stage operations, fastest ways this.

as always, unless need information carry forward further aggregation pipeline stages, or if indeed reduce content arrays "significant" amount saves considerable network traffic, better "filtration" in client database itself.

neither of these processes have overhead, client code arguably straight-forward, , might gained "little" less network traffic lost in cost of processing on server.


Comments

Popular posts from this blog

java - Run spring boot application error: Cannot instantiate interface org.springframework.context.ApplicationListener -

reactjs - React router and this.props.children - how to pass state to this.props.children -

Excel VBA "Microsoft Windows Common Controls 6.0 (SP6)" Location Changes -