[SERVER-66740] findAndModify.lastErrorObject.updatedExisting always true after and update Created: 25/May/22  Updated: 01/Jul/22  Resolved: 03/Jun/22

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: 5.0.6
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Samuel Cadieux Assignee: Chris Kelly
Resolution: Duplicate Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates SERVER-28145 add ability to obtain modified flag f... Backlog
Related
is related to SERVER-28145 add ability to obtain modified flag f... Backlog
Operating System: ALL
Steps To Reproduce:
  1. Use Mongo 5.0.6
  2. Run the following commmand to insert a document:
    {{> db.runCommand({ "findAndModify" : "collection", "query" : { "_id" : ObjectId("628d26b2f8221751cdd7dcd2") }

    , "update" : { "$set" :

    { "name" : "some name" }

    }, "new": true, "upsert": true })}}
    {{}}

  3. Run the following command to update the document with the same values:{}{{{}> db.runCommand({ "findAndModify" : "collection", "query" : { "_id" : ObjectId("628d26b2f8221751cdd7dcd2") }

    , "update" : { "$set" :

    { "name" : "some name" }

    }, "new": true, "upsert": true }){}}}
    {{}}

  4. Observe the result state:
    {{{}lastErrorObject:
    Unknown macro: { n}

    ,{}}}{}

Participants:

 Description   

I've noticed an issue with findAndModify, where updatedExisting always return true when updating a field with the same value.

I found this blog post that describe the issue well: https://codehunter.cc/a/mongodb/findandupdate-how-to-check-if-document-was-really-updated

Although this behavior seems to be a bug, it's in line with the documention: https://www.mongodb.com/docs/manual/reference/command/findAndModify/#lasterrorobject

However, I would expect updatedExisting to be true if the document was upserted or if any modification was done to the existing document. Similar to how the update command output: https://www.mongodb.com/docs/manual/reference/command/update/#mongodb-data-update.nModified

Might be related to this other issue: https://jira.mongodb.org/browse/SERVER-12329



 Comments   
Comment by Samuel Cadieux [ 03/Jun/22 ]

Hi Chris, indeed SERVER-28145 from 2017 would solve this issue, but I'm hoping the priority on this issue would be increased.

We currently don't have a reliable way to tell what whether the result of a findAndModify operation was a no-op and we rely on this information in our system to notify state updates.

We've identified a few workarounds, but none is perfect or reliable. Can you think of a better workaround in the meantime?

Workaround 1: Use update instead of findAndModify
Currently, we're forced to use the update command instead. However, the update command doesn't return the result of the operation, requiring a second command to pull out the updated document.

This is an acceptable workaround if we query the document using a unique index.

However, problems arise if we need to update a document using a filter that is not unique.
Or worse yet, if the update definition modifies fields part of the filter definition, this makes it impossible to find the document that was updated.

Workaround2: Client-side comparison
A more costly workaround would be to use findAndModify but request the document in its previous state. And do a second query to get the updated document using the document id from the previous state and perform a client-side comparison. This almost solves our issue, however this might cause false positives given that the document might have been updated by another instance of our service.

Comment by Chris Kelly [ 03/Jun/22 ]

Hi Samuel,

Thanks for your report. According to the documentation, updatedExisting will be true if either of the following occur:

  • Modified an existing document.
  • Found the document, but it was already in the desired destination state so no update actually occurred.

In this case, when you first create the document this will be false, but running the findAndModify query while the document is in the desired destination state already will cause it to return true.

Adding extra information indicating whether changes were made (like nModified) is on the backlog in SERVER-28145

Regards,
Christopher

Comment by Samuel Cadieux [ 25/May/22 ]

To reproduce, run the following command twice using mongosh:
db.runCommand({ "findAndModify" : "collection", "query" : { "_id" : ObjectId("628d26b2f8221751cdd7dcd2") }, "update" : { "$set" : { "name" : "some name" } }, "new": true, "upsert": true })

Notice how the output of the second execution returns:
lastErrorObject: { n: 1, updatedExisting: true },

Generated at Thu Feb 08 06:06:17 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.