Let\'s say I have a collection of documents that look like this:
{
\"_id\" : ObjectId(\"5afa6df3a24cdb1652632ef5\"),
\"createdBy\" : {
\"_id\
You can still use aggregate()
here with MongoDB 3.2, but just using $redact instead:
db.boards.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$and": [
{ "$ne": [ "$createdBy._id", "$owner._id" ] },
{ "$setIsSubset": [["$createdBy._id"], "$acl.profile._id"] }
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Or with $where for the MongoDB 3.2 shell, you just need to keep a scoped copy of this
, and your syntax was a bit off:
db.boards.find({
"$where": function() {
var self = this;
return (this.createdBy._id != this.owner._id)
&& this.acl.some(function(e) {
return e.profile._id === self.createdBy._id
})
}
})
Or in an ES6 compatible environment then:
db.boards.find({
"$where": function() {
return (this.createdBy._id != this.owner._id)
&& this.acl.some(e => e.profile._id === this.createdBy._id)
}
})
The aggregate is the most performant option of the two and should always be preferable to using JavaScript evalulation
And for what it's worth, the newer syntax with $expr would be:
db.boards.find({
"$expr": {
"$and": [
{ "$ne": [ "$createdBy._id", "$owner._id" ] },
{ "$in": [ "$createdBy._id", "$acl.profile._id"] }
]
}
})
Using $in in preference to $setIsSubset where the syntax is a little shorter.
NOTE The only reason the JavaScript comparison here works is because you have mistakenly stored
ObjectId
values as "strings" in those fields. Where there is a "real"ObjectId
just like in the_id
field, the comparison needs to take the "string" fromvalueOf()
in order to compare:
return (this.createdBy._id.valueOf() != this.owner._id.valueOf())
&& this.acl.some(e => e.profile._id.valueOf() === this.createdBy._id.valueOf())
Without that it's actually an "Object Comparison" with JavaScript and
{ a: 1 } === { a: 1 }
is actuallyfalse
. So avoiding that complexity is another reason there are native operators for this instead.