How to make partial updates from json data with the official C# driver

2,530 views
Skip to first unread message

sn

unread,
Jan 7, 2012, 2:47:41 AM1/7/12
to mongodb-user
Hi

I want to make a general method to do PARTIAL updates of a document
from json data. The json data contiains a subset of the fields of the
POCO being updated.

I have this:

public static void Update(MongoCollection collection, ObjectId
id, string jsonData) {
// assume jsonData does not contain the id field.
var bsonDoc =
BsonSerializer.Deserialize<BsonDocument>(jsonData);
IMongoUpdate updateDoc = new UpdateDocument("$set",
bsonDoc);
collection.Update(Query.EQ("_id",id), updateDoc);
}

This almost works, but my problem is that fields with type ObjectId
are deserialized as strings, because that is how they are represented
in JSON. (They have been serialized with the javascript JSON2 lib on
the client side).

So my question is: What is the best way to make a general partial
update method working with json data in with the official C# driver ?
How can I get poco fields deserialized correctly to the proper types
instead of just strings when using the BsonSerializer ?

sn

unread,
Jan 7, 2012, 8:05:17 AM1/7/12
to mongodb-user
Ok, found a solution:

First deserialize json to POCO.
Then wrap with BsonDocumentWrapper and convert this to a BsonDocument:

It looks something like this, where T is the POCO type:

T doc = JsonSerializer.DeserializeFromString<T>(json);
var wrapper = BsonDocumentWrapper.Create(doc);
var bsonDoc = wrapper.ToBsonDocument();
IMongoUpdate updateDoc = new UpdateDocument("$set", bsonDoc);


Robert Stam

unread,
Jan 7, 2012, 10:57:20 PM1/7/12
to mongod...@googlegroups.com
One thing to watch out for with this approach is whether any fields/properties in your POCO that are missing from the JSON string end up being changed to null in the database.

You could still use the BsonDocument approach you tried first if you know the name(s) of the field(s) that are supposed to be DateTime values but that were stored as strings in the JSON, because you can access those elements and replace their values with the parsed DateTime. You could write something like:

if (document.Contains("AppointmentTime") && document["AppointmentTime"].IsString)
{
    document["AppointmentTime"] = DateTime.Parse(document["AppointmentTime"].AsString);
}

--
You received this message because you are subscribed to the Google Groups "mongodb-user" group.
To post to this group, send email to mongod...@googlegroups.com.
To unsubscribe from this group, send email to mongodb-user...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/mongodb-user?hl=en.


Robert Stam

unread,
Jan 7, 2012, 11:02:09 PM1/7/12
to mongod...@googlegroups.com
Sorry, just realized your original question mentioned ObjectIds, not DateTime values.

But the same approach works with ObjectIds.

Also, if you can create the JSON with the C# driver instead of some other JSON library, all these values will round trip with no effort on your part. The C# driver uses "extended JSON" to represent values that normal JSON doesn't know about (like ObjectId and DateTime).

sn

unread,
Jan 9, 2012, 3:16:30 AM1/9/12
to mongodb-user
Hi Robert

Thanks for your reply. Regarding your first comment I, I believe that
using the $set modifier ensures that I am only doing a partial update:

IMongoUpdate updateDoc = new UpdateDocument("$set",
bsonDoc);
var result = Collection.Update(query, updateDoc);

So in this way missing props are should not end up being null. Are am
I missing something ?

By the way I just looked at the driver API. How do I make an update
that replaces a doc using the the C# driver, ie.
how do I make a :
db.somecollection.update({name:"joe"},replacementDoc) with the C#
driver?

Robert Stam

unread,
Jan 9, 2012, 10:37:30 AM1/9/12
to mongod...@googlegroups.com
When the POCO is serialized (inside the $set) the serialized form of the POCO probably includes all fields/properties of the POCO, including those which were not have been present in the input JSON. On the other hand, a BsonDocument would contain only the fields present in the input JSON.

In other words, while $set is indeed a partial update, if the argument to $set includes components that set values to BSON null those fields will be updated.

The way to replace an entire document is:

var update = Update.Replace(newDocument);
Reply all
Reply to author
Forward
0 new messages