My schema in MongoDB looks like this:
{
"_id": "be9e9198-86ab-456e-97e1-f1039cb07b59",
"isDeleted": false,
"user": {
"name": "john2",
"surname": "doe2",
"email": "[email protected]",
"phone": " 012345678912",
"age": 20,
"gender": "male",
"nationality": "smth",
"universityMajor": "ENGINEERING",
"preferences": null,
"highPrivacy": false,
}
(Other stuff)
.
.
.
}
I am trying to include the field user.phone
only when user.highPrivacy
is set to False. Otherwise, I want to exclude the field.
For example, given the above user, I should return the phone number. But if user.highPrivacy
was later set to True, it should not include it.
What I have tried so far is this:
dbConnection.aggregate([
{"$match" :
{"_id": userId, "isDeleted" : False}
},
{
"$project" : {
"postings" : 0,
"starredPostings" : 0,
"user.timestamp" : 0,
"user.phone" : { "$cond" : [{"$eq": ["$user.highPrivacy", True]}, 0, "$user.phone"] },
}
},
])
This keep giving me the error:
pymongo.errors.OperationFailure: Invalid $project :: caused by :: Cannot use expression other than $meta in exclusion projection
But the answers that are here:
- Conditionally include a field (_id or other) in mongodb project aggregation?
- Project different fields based on different condition
- https://kb.objectrocket.com/mongo-db/mongodb-project-condition-how-to-use-project-with-a-condition-469
are using the same projection as me, or at least I think they are.
So where exactly is the issue in my aggregation?
CodePudding user response:
I would use the $cond stage and the $$REMOVE keyword.
See example in playground: https://mongoplayground.net/p/x09lSOojjiY
Example collection data:
[
{
"_id": "1",
"isDeleted": false,
"user": {
"name": "john2",
"phone": " 012345678912",
"highPrivacy": false
}
},
{
"_id": "2",
"isDeleted": false,
"user": {
"name": "john2",
"phone": " 012345678912",
"highPrivacy": true
}
}
]
Aggregation query:
db.collection.aggregate([
{
$match: {
"isDeleted": false
}
},
{
$project: {
"isDeleted": 1,
"user.name": 1,
"user.highPrivacy": 1,
"user.phone": {
$cond: {
if: {
$eq: [ "$user.highPrivacy", true ]
},
then: "$user.phone",
else: "$$REMOVE"
}
}
}
}
])
Result:
[
{
"_id": "1",
"isDeleted": false,
"user": {
"highPrivacy": false,
"name": "john2"
}
},
{
"_id": "2",
"isDeleted": false,
"user": {
"highPrivacy": true,
"name": "john2",
"phone": " 012345678912"
}
}
]
CodePudding user response:
Query
- if you want the field to be calculated from expression and removed you don't make it be
0
you use the system variable$$REMOVE
- you can use
$project
or$set
the bellow does keeps or removes phone based onhighPrivacy
field
aggregate(
[{"$set":
{"user.phone":
{"$cond":
[{"$eq": ["$user.highPrivacy", true]}, "$$REMOVE", "$user.phone"]}}}])