How to update a MongoDB document field only once?

Hi there I’m trying to make a mongoose query to run only once if the field inside the document hasn’t been updated already, but I’m getting a bit lost with the $exist, $update, $ne don’t know what to use really.

I have the following query

const assignPhotoCodeToModel = (modelID, photoCode) => {
  const filter = { id: modelID }
  const update = { photoCode: photoCode }
  const options = { new: true, useFindAndModify: false }

  return new Promise((resolve, reject) => {

    ModelModel.findOneAndUpdate(filter, update, options)
      .then((response) => {
        resolve(response)
      })
      .catch((error) => {
        reject(error)
      })
  })
}

But I want this to run only if the field Model.photoCode is empty. If it already has a value I just want it to return that value.

The problem I’m having is that everytime the backend hits the route a new photoCode gets assign to the model even if it has been already assigned. So it gets reassign again again with a new one.

router.post(
  '/payment/success',
  (req, res, next) => {


 ...omitted_code...

                photoCodeModel
                .assignPhotoCodeToModel(req.body.modelId, photoCode)

... omitted_code

})

EDIT: 1:

Ok I’m writing this after trying the answers provided here. At first glance they seem to work, but now I’m getting into the error that when the Model.photoCode already has a value in it the return of the following function:

const assignPhotoCodeToModel = (modelID, photoCode) => {
  //the difference is here
  const filter = { id: modelID, photoCode : null }
  const update = { $set: { photoCode: photoCode } }

  const options = { new: true, useFindAndModify: false }

  return new Promise((resolve, reject) => {

    ModelModel.findOneAndUpdate(filter, update, options)
      .then((response) => {
        resolve(response)
      })
      .catch((error) => {
        reject(error)
      })
  })
}

returns null, while I’m actually expecting the same model document to be returned. I’m guessing is because of the filtering? When I remove the photoCode : null it goes back to “working”, but then I’m back to the problem that photoCode field gets populated with new values

Basically I would like that function populates the filed photoCode once, but every subsequent call should just bring me back the same model document

Answer

I think what you need is $set . And, following your logic, I think you have to query “document that doesn’t have photoCode yet”. It should be:

const assignPhotoCodeToModel = (modelID, photoCode) => {
  //the difference is here
  const filter = { id: modelID, photoCode : null }
  const update = { $set: { photoCode: photoCode } }

  const options = { new: true, useFindAndModify: false }

  return new Promise((resolve, reject) => {

    ModelModel.findOneAndUpdate(filter, update, options)
      .then((response) => {
        resolve(response)
      })
      .catch((error) => {
        reject(error)
      })
  })
}