user9366125
user9366125

Reputation:

Mongoose findOneAndUpdate when value is not in array

I have the below Mongoose function where I am trying to do a select WHERE email = req.body.email and referenceId is not in an array.

referenceId is a string array [String] which has an array of object ID's.

const refereeSchema = new Schema({
  firstName: {
    type: String,
    required: true
  },
  lastName: {
    type: String,
    required: true
  },
  email: {
    type: String,
    required: true,
    unique: true
  },
  referenceId: [
    {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    }
  ],
  token: {
    type: String,
    required: true
  },
  password: {
    type: String
  },
  company: {
    type: String,
    required: true
  },
  role: {
    type: String,
    required: false
  },
  startedOn: Date,
  endedOn: Date,
  createdAt: Date,
  updatedAt: Date
});


  Referee.findOneAndUpdate({
    email: req.body.email,
    referenceId: {
      '$ne': [new mongo.ObjectID(req.params.referenceId)]
    }
  }, {
    $push: {
      referenceId: new mongo.ObjectID(req.body.referenceId)
    }
  }, {
    new: true
  }, (err, doc) => {
    if (err) {
      res.status(401).send(err);
    }
    res.send(doc);
  });

Each time I run the above it always matches and pushes the ObjectId even though it already existed before.

{ referenceId:
   [ 5ba94232b492890982e7a417,
     5ba94232b492890982e7a417,
     5c20d8f907a55accd720c27f,
     5c20d8f907a55accd720c27f,
     5c20d8f907a55accd720c27f,
     5c20d8f907a55accd720c27f,
     5c20d8f907a55accd720c27f,
     5c20d8f907a55accd720c27f ],
  _id: 5c20e86d72d5c1ce20b961fa,
  firstName: 'Richard',
  lastName: 'Hendricks',
  email: '[email protected]',
  token: '319d9f5a-68e1-6f47-a9f1-7fbbf617a45c',
  company: 'Pied Piper',
  role: '',
  __v: 0 }

Could someone please help me?

I'd like to do a check to see if the ObjectId is already in the array then DO NOTHING else push it.

Upvotes: 4

Views: 3045

Answers (2)

the_mahasagar
the_mahasagar

Reputation: 1201

$push will just push data in array, you should use $addToSet

$addToSet only ensures that there are no duplicate items added to the set and does not affect existing duplicate elements. $addToSet does not guarantee a particular ordering of elements in the modified set

more details

Referee.findOneAndUpdate({
    email: req.body.email,
    referenceId: {
       '$ne': [new mongo.ObjectID(req.params.referenceId)]
    }
   }, {
     $addToSet: {
        referenceId: new mongo.ObjectID(req.body.referenceId)
     }
   }, {
     new: true
   }, (err, doc) => {
     if (err) {
        res.status(401).send(err);
     }
     res.send(doc);
 });

more ever, you can use $elemMatch or $nin as find query, so that document itself doesnt return if id is in referenceId

$elemMatch :

referenceId: {
  '$elemMatch': { '$ne': new mongo.ObjectID(req.params.referenceId) }
}

$nin:

referenceId: {
   '$nin': [new mongo.ObjectID(req.params.referenceId)]
}

Upvotes: 5

Paul
Paul

Reputation: 36349

Consider using the $elemMatch operator in complement of $ne. $ne against the array itself will always return true in this case, because the array you're passing in the parameter is never going to equal the array in the document.

I haven't tested this, but something along these lines should work:

Referee.findOneAndUpdate({
    email: req.body.email,
    referenceId: {
      '$elemMatch': { '$ne': new mongo.ObjectID(req.params.referenceId) }
    }
  }, {
    $push: {
      referenceId: new mongo.ObjectID(req.body.referenceId)
    }
  }, {
    new: true
  }, (err, doc) => {
    if (err) {
      res.status(401).send(err);
    }
    res.send(doc);
  });

Also, you probably already know this but there are actually two ObjectId classes you might be importing, the one you want is mongoose.Types.ObjectId

Upvotes: 1

Related Questions