intercoder
intercoder

Reputation: 2389

How to update a MongoDB document field only once?

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 - I 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 every time the backend hits the route, a new photoCode gets assign to the model even if it has been already assigned. So it gets reassigned 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

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.

Upvotes: 2

Views: 449

Answers (2)

shravan20
shravan20

Reputation: 56

Write it in a neat asynchronous form. It will work.

const assignPhotoCodeToModel = async (modelID, photoCode) => {
  const filter = { id: modelID, photoCode : null };
  const update = { photoCode: photoCode };
  const options = { new: true, useFindAndModify: false };
  return await ModelModel.findOneAndUpdate(filter, update, options);
}

Upvotes: 1

Kai
Kai

Reputation: 3663

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)
      })
  })
}

Upvotes: 2

Related Questions