Update all properties of object in MongoDb
Asked Answered
D

3

28

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?

Domineer answered 17/6, 2015 at 13:25 Comment(3)
Yon only use $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?Lordinwaiting
@Lordinwaiting number of updated properties are unknown so i'm ok with updating all of them at once, even is value is still the same.Domineer
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.Lordinwaiting
H
54

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);
Homeland answered 17/6, 2015 at 13:33 Comment(5)
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?Amerind
@Amerind 1. You can get the id from the db. 2. You can create the Id yourself in code.Homeland
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 _ids. 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.Amerind
@Amerind it's not. You should create the ids yourself in a deterministic way in code.Homeland
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.Pneumonic
L
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.

Lithosphere answered 28/2, 2018 at 14:32 Comment(7)
Please, comment your code. You must explain why your answer is good.Troth
This is awesome, but what about the case where you have nested objects? That throws an "cannot be mapped to a BsonValue" exception. Has anyone tried to make that work?Mosher
@Mosher - well, then you just need some recursion in reflection. I don't think this is the proper way to go, actually.Pneumonic
@Pneumonic - any suggestions? this didn't feel right to me either - but it's the only thing I could come up with :(Mosher
@Mosher - I think the native API methods, like 'FindOneAndUpdate' etc are the way to go...Pneumonic
this code needs update , you need to check for [BsonIngoreAttribute] and exclude bson ignored propertiesFantasy
also exclude setters only or getters only from the updateFantasy
T
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;
Trangtranquada answered 7/3, 2020 at 12:14 Comment(1)
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<YourObjectClass>(filterYouHave, updateDefinition);?Discursive

© 2022 - 2024 — McMap. All rights reserved.