findOneAndUpdate causing duplication problem

爷,独闯天下 提交于 2021-01-07 03:56:05

问题


I am having a problem in findOneAndUpdate in mongoose. The case is that i am updating a document by finding it. The query is as follows:

UserModel.findOneAndUpdate({
individualId: 'some id'
}, {
$push: {
supporterOf: 'some string'
}
})

The 'supporterOf' is the ref of UserModel and its type is 'ObjectId'.

The issue i am facing here is that, 'some string' is being pushed twice under 'supporterOf' in the document.

Can anyone tell me that how to push an array element inside the document?


回答1:


I have recently encountered the same problem. However, I managed to overcome this issue by some other logics (details given below) but couldn't understand the reason behind that why findOneAndUpdate inserting duplicate entries in mongodb.

You can overcome this problem by following logic.

Use findOne or findById instead of findOneAndUpdate to search the document in your collection and then manually update your document and run save().

You can have better idea with this code snippet

return new Promise(function (resolve, reject) {
    Model.findOne({
            someCondition...
        }, function (err, item) {
            if (err) {
                reject(err);
            } else {
                item.someArray.push({
                    someKeyValue...
                });
                item.save().then((result) => {
                    resolve(result)
                }).catch((err) => {
                    reject(err)
                });
            }
        }).catch((err) => {
            reject(err)
        });
   });

This will not insert duplicate item. However, if you come to know the reasoning behind duplication, must do update this thread.




回答2:


I was having same problem, solution is little weird.

I was keeping await like below.

 **await** schema.findOneAndUpdate(queryParms, {
                "$push": {
                    "array1": arrayDetails,
                    "array2": array2Details
                }
            }, {
                "upsert": true,
                "new": true
            },
            function (error, updateResponse) {
                if (error) {
                    //mongoDb.closeMongoCon(mongoose);
                    console.log('error ', error);
                    deferred.reject(data);
                } else {
                    console.log('updateResponse ', updateResponse);
                    deferred.resolve(updateResponse);
                }
            });

simply removing await helped me resolving this problem. Need to find the root cause. any pointer for references is welcome.




回答3:


The problem with the accepted answer is that it only solves the problem by wrapping it in an unnecessary additional promise, when the findOneAndUpdate() method already returns a promise. Additionally, it uses both promises AND callbacks, which is something you should almost never do.

Instead, I would take the following approach:

I generally like to keep my update query logic separate from other concerns for both readability and re-usability. so I would make a wrapper function kind of like:

const update = (id, updateObj) => {
    const options = {
      new: true,
      upsert: true
    }
    return model.findOneAndUpdate({_id: id}, {...updateObj}, options).exec()
}

This function could then be reused throughout my application, saving me from having to rewrite repetitive options setup or exec calls.

Then I would have some other function that is responsible for calling my query, passing values to it, and handling what comes back from it.

Something kind of like:

const makePush = async () => {
   try {
     const result = await update('someObjectId', {$push: {someField: value}});
     // do whatever you want to do with the updated document
   catch (e) {
     handleError(e)
    }
 }

No need to create unnecessary promises, no callback hell, no duplicate requests, and stronger adherence to single responsibility principles.




回答4:


I was having the same problem. My code was:

const doc = await model.findOneAndUpdate(
{filter}, {update},
{new: true}, (err, item) =>  if(err) console.log(err) }
)
res.locals.doc = doc
next();

The thing is, for some reason this callback after the "new" option was creating a double entry. I removed the callback and it worked.




回答5:


I had the same problem. I found a solution for me:

I used a callback and a promise (so using keyword "await") simultaneously.

Using a callback and a promise simultaneously will result in the query being executed twice. You should be using one or the other, but not both.

  options = {
    upsert: true  // creates the object if it doesn't exist. defaults to false.
  };
  await Company.findByIdAndUpdate(company._id,
    { $push: { employees: savedEmployees } },
    options,
    (err) => {
       if (err) {
          debug(err);
       }
    }
  ).exec();

to

  options = {
    upsert: true  // creates the object if it doesn't exist. defaults to false.
  };
  await Company.findByIdAndUpdate(company._id,
    { $push: { employees: savedEmployees } },
    options
  ).exec();



回答6:


UserModel.findOneAndUpdate(
{ _id: id },
{ object }
)

Even if you use _id as a parameter don't forget to make the filter explicit by id




回答7:


The issue seems to stem from combining an await and a callback. I had the same issue until I realised I was using an (err, resp) callback and a .catch(...).

models[auxType].findOneAndUpdate(
    filter,
    updateObject,
    options,
    (err, resp)=>{
        if (err) {
            console.log("Update failed:",err)
            res.json(err)
        } else if (resp) {
            console.log("Update succeeded:",resp)
            res.json(resp)
        } else {
            console.log("No error or response returned by server")
        }
    })
    .catch((e)=>{console.log("Error saving Aux Edit:",e)}); // << THE PROBLEM WAS HERE!!

The problem resolved as soon as I removed the .catch(...) line.

From the mongoose documentation:

  • "Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. However, unlike promises, calling a query's .then() can execute the query multiple times." (https://mongoosejs.com/docs/queries.html#queries-are-not-promises)



回答8:


In my case, changing the async callback solved the problem.

changing this:

await schema.findOneAndUpdate(
    { queryData },
    { updateData },
    { upsert: true },
    (err) => {
      if (err) console.log(err); 
      else await asyncFunction();
    }
  );

To this:

await schema.findOneAndUpdate(
    { queryData },
    { updateData },
    { upsert: true },
    (err) => {
      if (err) console.log(err);
    }
  );
 if (success) await asyncFunction();


来源:https://stackoverflow.com/questions/55103351/findoneandupdate-causing-duplication-problem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!