Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updateOne update property with same value doesn't return nModified = 1 #84

Closed
globules-io opened this issue Jan 5, 2016 · 7 comments
Closed

Comments

@globules-io
Copy link

Hi!
I'm using
$collection->updateOne($query, ['$set' => [$prop => $value]]);
While using $set with updateOne, if the value is different than the one currently set for the document, it will return nMatched = 1, nModified = 1. If the value is the same, it will return nMatched = 1 and nModified = 0. I understand why, since it didn't update with the same value. But from a user stand point, I still need to be able to return that the document has been modified to avoid checking if the user is trying to update with the same value (which has no incidence). So question, is there a way to have the driver returning nModified = 1 even if the value was the same?

@jmikola
Copy link
Member

jmikola commented Jan 6, 2016

The write results fields in each driver are coming directly from the database, so this is a question better suited to the mongodb-user list than a driver project.

I still need to be able to return that the document has been modified to avoid checking if the user is trying to update with the same value (which has no incidence)

I don't follow why the current result is an issue. You say that you need to return whether the document is actually modified, which nModified indeed reports. You then say that there is no incidence where you should be updating the same value, which is the case that would cause nMatched = 1 and nModified = 0.

@globules-io
Copy link
Author

I base the operation on being a success if nModified = 1. If the user updates with the same value, it returns nModified = 0 and isn't a success, and returns an error to the front end. This only occurs if the end user updates a property with the same value. My only workaround is to test if the end user is trying to update the value of the document with the current value, which is kind of a pain. I'm just looking for a solution to get a success whether the value is the same or different, and not create a special case if the value is the same.

@jmikola
Copy link
Member

jmikola commented Jan 7, 2016

There are three possibilities:

  • nMatched = 0, nModified = 0: the criteria matched nothing
  • nMatched = 1, nModified = 0: the criteria matched but the $set resulted in no change to the document
  • nMatched = 1, nModified = 1: the criteria matched and $set changed the document

I'm just looking for a solution to get a success whether the value is the same or different, and not create a special case if the value is the same.

If I understand correctly, you don't care if $set changes the document at all. It seems like your error condition is the criteria not matching anything, in which case you can just use nMatched.

This only occurs if the end user updates a property with the same value.

Earlier you said "avoid checking if the user is trying to update with the same value (which has no incidence)". What did you mean by "no incidence" there. I took that to mean such a scenario does not occur.

Alternatively, you could incorporate the value you expect to $set into the update criteria with $ne to ensure that you never find a document that already has the value you're attempting to change. This wouldn't work with other updates (e.g. $inc) but it seems quite feasible for $set, where you know exactly what the post-modified value would become.

@globules-io
Copy link
Author

Thank you for your comment, I will use nMatched = 1 and will consider that if the document is matched, the update must have had occurred properly.
By no incidence I meant that it doesn't matter to me that the end user updates with the same value, it shouldn't be considered as a "fault" but still considered as an update. Sorry for not explaining properly.

@Zelfapp
Copy link

Zelfapp commented Mar 23, 2016

My updateOne() code below does in fact update the mongo document, but nModified is always returned as "null". updateOne() is "New in version 3.2." and I'm still using version 2.4.6, so maybe that is part of the issue? Seems like I should still be getting nModified = 1 and be able to get this report from $response->getModifiedCount().

The other issue I wanted to point out is: with the legacy mongo driver, on an update I could simply look for $response['ok']. It was unclear from documentation that I needed to call either $response->isAcknowledged(), or $response->getModifiedCount() to get information back from the response.

updateOne() code:

$filter = [
    '_id' => new \MongoDB\BSON\ObjectID('56e345f426d0f93939d833cb')
];

$data = [
    '$set' => [
        'hello_world' => 'testing3'
    ]
];

$response = $collection->updateOne($filter, $data);

Response:
screenshot_3

Updated document:

{
    "_id" : ObjectId("56e345f426d0f93939d833cb"),
    "email" : "test@mydomain.com",
    "first_name" : "Testing",
    "hello_world" : "testing3"
}

Environment
Windows 10
Wamp
PHP 5.5.12
Mongodb driver 1.1.4
Latest version of new php library (Installed with composer: composer require "mongodb/mongodb=^1.0.0")
Mongo instance version 2.4.6

@jmikola
Copy link
Member

jmikola commented Mar 23, 2016

In the future, please open a new issue instead of replying to an existing, closed issue. Otherwise, it's quite possible that your reply might go unnoticed.

My updateOne() code below does in fact update the mongo document, but nModified is always returned as "null". How can I verify a document has been updated?

The nModified field is only supported via the write commands in MongoDB 2.6+. There is no equivalent field to check in older versions of the server.

Typically, you would access UpdateResult::getModifiedCount() in the library or WriteResult::getModifiedCount() in the extension.

The other issue is, with legacy mongo driver on an update I could simply look for $response['ok']. However, when checking the response with $response['isAcknowledged'] I'm getting: "Fatal error: Cannot use object of type MongoDB\UpdateResult as array". How do I check responses?

The UpdateResult class in the library wraps the extension's WriteResult class; however, I noticed that the PHP.net documentation for that class is incomplete. I've opened PHPC-653 to track the task of updating the extension documentation. The library docs are currently being worked on in #144.

As for checking responses, I would suggest looking at the various result classes in the library. There are getter methods and an isAcknowledged() method for relevant write result fields. If you're using the extension directly, you will want to refer to the WriteResult methods. Note that since the extension only provides an executeBulkWrite() API for issuing writes, its WriteResult is akin to the library's BulkWriteResult class. The library just adds exceptions when accessing results if the write is unacknowledged in order to comply with the CRUD specification:

If you have a choice, consider providing the acknowledged member and raising an error if the other fields are accessed in an unacknowledged write. Instead of users receiving a null reference exception, you have the opportunity to provide an informative error message indicating the correct way to handle the situation.

The various other result classes in the library are specific to insert, update, and delete operations. Similarly, they throw if you attempt to access a result field when the result is unacknowledged.

@Zelfapp
Copy link

Zelfapp commented Mar 23, 2016

I'll certainly open new issues in new thread. Thanks for the info. Looks like I'll be upgrading to 2.6+.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants