Search code examples
mongodbaggregation-frameworkprojection

Conditionally excluding field not working in MongoDB


I would like to get a user from the database. My function takes in a requesterId which is the ID of the user requesting this data, and a targetId which is the user to retrieve.

If the requester is in the target's friends array (strings), the phone field should be included in the projection. If not, it is excluded.

I have come up with the following query after reading the example here. However, the phone field is always returned no matter what. What am I doing wrong?

  getUser: function getUser(requesterId, targetId) {
    return db.collection('users').aggregate([
      {$match: {userId: targetId}},
      {
        $project:
          {
            firstName: 1,
            phone: {
              $cond: {
                if: {friends: requesterId},
                then: "$phone",
                else: "$$REMOVE"
              }
            }
          }
      },
      {$limit: 1}
    ]).toArray();
  }

Schema (created in Compass so no code):
userId - String
firstName - String
friends - Array(String)
phone - String

Indices: None on this collection

Example:

/* Bob's MongoDB data */ {userId: "BobID", firstName: "Bob", friends: ["AmyID"], phone: "1234567890"}
getUser(requesterId = 'AmyID', targetId = 'BobID');
/* Result */ {firstName: "Bob", phone: "1234567890"}

/* Amy's MongoDB data */ {userId: "AmyID", firstName: "Amy", friends: ["CassieID"], phone: "9876543210"}
getUser(requesterId = 'BobID', targetId = 'AmyID');
/* Result */ {firstName: "Amy", phone: "987654321"}

Bob's request for Amy's user should not return her phone number because he is not in her friends array.


Solution

  • The if: value must be a boolean expression, not a query object. To check whether a specified value is in an array, you can use the $in expression:

    db.collection('users').aggregate([
      {$match: {userId: targetId}},
      {
        $project:
          {
            firstName: 1,
            phone: {
              $cond: {
                if: {$in: [requesterId, '$friends']},
                then: "$phone",
                else: "$$REMOVE"
              }
            }
          }
      },
      {$limit: 1}
    ])