skip to Main Content

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?

2

Answers


  1. 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"
        }
      }
    ]
    
    Login or Signup to reply.
  2. 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"]}}}])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search