Home > front end >  Project a field based on condition MongoDB
Project a field based on condition MongoDB

Time:11-12

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:

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 on highPrivacy field

Playmongo

aggregate(
[{"$set": 
   {"user.phone": 
     {"$cond": 
       [{"$eq": ["$user.highPrivacy", true]}, "$$REMOVE", "$user.phone"]}}}])
  • Related