[CSHARP-282] Empty UpdateBuilder will null out a document Created: 25/Jul/11  Updated: 02/Apr/15  Resolved: 26/Jul/11

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 1.2

Type: Bug Priority: Major - P3
Reporter: John Woakes Assignee: Robert Stam
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows Server 2008


Backwards Compatibility: Minor Change

 Description   

Using the code below, if a call is made to class method Handle() with an evnt with out any Changes this will pass an initialized but empty UpdateBuilder() to the MongoCollection Update command which will null out all the values in the document. I was expecting no changes to be made.

public class xyz
{
readonly MongoCollection<T> _docs;

public void Update(dynamic id, IMongoUpdate update)

{ _docs.Update(new QueryDocument("_id", id), update); }

}

public class abc
{
readonly xyz _atttributeTypes;

public void Handle(AttributeTypeUpdated evnt)

{ var update = new UpdateBuilder(); foreach (var change in evnt.Changes) update.SetWrapped(change.Key, change.Value); _atttributeTypes.Update(evnt.EventSourceId, update); }

}



 Comments   
Comment by John Woakes [ 27/Jul/11 ]

That's what I thought. The one difference is I used the public ToBsonDocument() method on UpdateBuilder to get the document where you created a new internal property Document.

Comment by Robert Stam [ 27/Jul/11 ]

That's reassuring. Thanks again for your help with this.

Comment by John Woakes [ 27/Jul/11 ]

I just looked at your solution and it is exactly the same as what we implemented at our end. Glad to be part of the process.

Comment by Robert Stam [ 26/Jul/11 ]

John: thanks for your help on this. This is a kind of subtle edge case I hadn't considered, and your feedback as been very helpful.

Comment by Robert Stam [ 26/Jul/11 ]

MongoCollection.Update now throws an ArgumentException when called with an empty UpdateBuilder. This prevents accidentally clearing all elements of a document (if that's what you want say so explicitly by using Update.Replace with an empty BsonDocument).

Comment by John Woakes [ 26/Jul/11 ]

Thank for listening Robert. It helped me too to talk it through.

Comment by Robert Stam [ 26/Jul/11 ]

New fix proposed. See previous comments.

Comment by Robert Stam [ 26/Jul/11 ]

I agree. I would have listed that as option 3 if it had occurred to me.

I will reopen this ticket and the fix will be to throw an exception if the UpdateBuilder is empty.

Thanks for your help on this.

Comment by John Woakes [ 26/Jul/11 ]

Actually an exception makes sense. The UpdateBuilder is in an incomplete state not suitable for execution...

Comment by John Woakes [ 26/Jul/11 ]

What we are going in our code is throw an exception. We don't want developers calling this with no changes.

Obviously this won't work for everyone but the results if you call this with an empty builder are pretty harsh if that is not what you intended. We actually lost production data because of this "feature".

Comment by Robert Stam [ 26/Jul/11 ]

Theoretically we could change the driver to handle an empty UpdateBuilder differently than an empty JSON document. The server may not know the difference, but the driver could.

One question would be: what to do when the UpdateBuilder is empty?

1. Don't even call the server
2. Call the server with an update document that does nothing (not sure how, there is no $nop operator)

The problem with the first is that we can't return a SafeModeResult if SafeMode is on, which the caller might be using to verify that the Update happened. The problem with the second is that I don't think it's possible to construct an update document that does nothing.

Any further thoughts?

Comment by John Woakes [ 26/Jul/11 ]

I understand that if you execute an Update() with an empty json document that that is saying replace the document with an empty document.

This is how I understand this - The UpdateBuilder is an abstraction that encapsulates updating parts of a document. It just happens that if the UpdateBuilder is empty it causes a different overloaded update() to execute on the server. From the driver's point of view an empty UpdateBuilder object conceptually should not replace the document with an empty document, it is just an unfortunate result of how the UpdateBuilder serializes its commands to JSon.

Comment by Robert Stam [ 26/Jul/11 ]

I checked with the server folks and they confirmed that it works this way by design.

Comment by John Woakes [ 26/Jul/11 ]

Ok, I was wondering if that might be the case. It is not the desired behaviour for us so we will have to guard against this happening in our code.

Comment by Robert Stam [ 25/Jul/11 ]

Here's the online documentation for update:

http://www.mongodb.org/display/DOCS/Updating#Updating-update%28%29

An empty document value for objNew is considered a replacement document instead of an empty list of update operators.

You should check in the client code for an empty update document and just don't call the server in that case.

Comment by Robert Stam [ 25/Jul/11 ]

I think that's just the way the server handles empty updates. See this mongo shell transcript:

> db.test.find()

{ "_id" : ObjectId("4e2dd696f7cd79c91b0f85f9"), "x" : 1, "y" : 2 }

> db.test.update(

{x:1}

,{})
> db.test.find()

{ "_id" : ObjectId("4e2dd696f7cd79c91b0f85f9") }

>

This is showing the exact same behavior without the C# driver involved.

Generated at Wed Feb 07 21:36:22 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.