27

I'm using the MongoDB .Net driver in my project. I want to update all of the properties of my object that is stored in MongoDB. In the documentation, update is shown like this:

var filter = Builders<BsonDocument>.Filter.Eq("i", 10);
var update = Builders<BsonDocument>.Update.Set("i", 110);

await collection.UpdateOneAsync(filter, update);

But I don't want to call the Set method for all of the properties, since there are many properties and can be many more in the future.

How can I update the whole object using the MongoDB .Net driver?

i3arnon
  • 113,022
  • 33
  • 324
  • 344
Sefa
  • 8,865
  • 10
  • 51
  • 82
  • 1
    Yon only use [**`$set`**](http://docs.mongodb.org/manual/reference/operator/update/set/) and related operators (which is all these driver builders are doing) on the fields you actually want to update. So if you just need to change one then you list one. Is that what your problem is or is it that you want to change 20 out of 50 properties in your update? –  Jun 17 '15 at 13:29
  • 1
    @user3561036 number of updated properties are unknown so i'm ok with updating all of them at once, even is value is still the same. – Sefa Jun 17 '15 at 13:31
  • 1
    That's basically an "update document" without any operators such as `$set`. But there is a handy helper method that does this for you rather than just serializing the whole document. –  Jun 17 '15 at 13:37

3 Answers3

52

You can do that with ReplaceOneAsync instead of UpdateOneAsync.

You need a filter to match the existing document (a filter with the document id is the simplest) and the new object.

Hamster hamster = ...
var replaceOneResult = await collection.ReplaceOneAsync(
    doc => doc.Id == hamster.Id, 
    hamster);
i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • 3
    But how do I give them same IDs without first sending an additional request to the database for the already existing ID? Am I missing something here? – Reynevan Jun 05 '17 at 17:04
  • 1
    @Reynevan 1. You can get the id from the db. 2. You can create the Id yourself in code. – i3arnon Jun 05 '17 at 22:21
  • 1
    In my scenario I'm creating objects and then adding them to a database. When I run the app next time there's no guarantee that the objects it creates aren't already there. If I try to upsert them, they don't have matching `_id`s. If I get the id from the DB that's one additional request to the DB. I have ~800 objects per batch. This just doesn't seem that efficient. – Reynevan Jun 06 '17 at 14:26
  • 1
    @Reynevan it's not. You should create the ids yourself in a deterministic way in code. – i3arnon Jun 06 '17 at 15:38
  • 3
    But in this way, if a field is missing on the existing document, it will be removed, won't it? And the point is to set unknown number of fields to new values, overwrite or add as needed, without removing the missing ones. – Bartosz Dec 13 '19 at 14:46
5
var update = new BsonDocument("$set", new BsonDocument(entityType.GetProperties().Where(p => p.Name != "Id").Select(p => new KeyValuePair<string, object>(p.Name, entityType.GetProperty(p.Name).GetValue(task, null)))));
var options = new UpdateOptions();
collection.UpdateOne<MyTask>(item => item.Name == "cheque", update, options);

this code uses reflection to include all properties of the given object
to the update statement, no need to manually add all properties, as u see the Id is explicitly excluded from the update statement to avoid exception.

Behnam Abdy
  • 345
  • 5
  • 10
1

If you want to update your whole BsonDocument, there is an implicit conversion from BsonDocument to UpdateDefinition.

https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver/UpdateDefinition.cs

var doc = new BsonDocument() { .... }
UpdateDefinition<BsonDocument> update = doc;
bengin
  • 31
  • 2
  • Yeah, but to get the document from a POCO you'd need to serialize it into BsonDocument first if I am right, eg.: `var updateDefinition = BsonDocument.Create(yourComplexObjectYouWishToFullUpdate);` and then `var update = new UpdateManyModel(filterYouHave, updateDefinition);`? – Vedran Mandić Feb 16 '23 at 09:36