43

I'm currently upgrading my code to MongoDB C# driver 2.0 and I'm having issues upgrading the code to update documents.

using the old version I was able to do something like this:

MyType myObject; // passed in 
var collection = _database.GetCollection<MyType>("myTypes");
var result = collection.Save(myObject);

I'm struggling to find a way to do this in the new version. I have found a few examples of updating single fields like

var filter = Builders<MyType>.Filter.Eq(s => s.Id, id);
var update = Builders<MyType>.Update.Set(s => s.Description, description);
var result = await collection.UpdateOneAsync(filter, update);

I'd like to update all the fields as I was doing in the old version with the method Save.

Any ideas ?

Thanks a lot

mnemosyn
  • 45,391
  • 6
  • 76
  • 82
Alessandro Di Lello
  • 1,181
  • 1
  • 9
  • 22
  • 1
    check out the mongodb wrapper library [MongoDB.Entities](https://github.com/dj-nitehawk/MongoDB.Entities). updating an entity is as simple as: `var author = DB.Find("ObjectId"); author.Name = "Charles Dickens"; author.Save();` – Dĵ ΝιΓΞΗΛψΚ May 23 '19 at 11:19

4 Answers4

46

I think you're looking for ReplaceOneAsync():

MyType myObject; // passed in 
var filter = Builders<MyType>.Filter.Eq(s => s.Id, id);
var result = await collection.ReplaceOneAsync(filter, myObject)
mnemosyn
  • 45,391
  • 6
  • 76
  • 82
  • 3
    Thanks mnemosyn ! I was just about to post my own answer as I just found the ReplaceOneAsync a few minutes ago. Thanks anyway that's exactly what I needed ! – Alessandro Di Lello May 15 '15 at 12:45
  • 1
    Where are you getting the value for "id" from? – redwards510 Nov 16 '15 at 21:42
  • I think it's better if you work with BsonDocument instead of MyType. If MyType has BsonIgnoreExtraFields flag, the document will ignore fields that are not represented in MyType class. In insert method, method will only insert fields that exists in class and you will lose all other nonrepresented fields. – Jure Potocnik Nov 23 '16 at 14:17
  • @JurePotocnik: On the other hand, other decorators will be ignored... In any case, you need some kind of invariant checking, preferably in the object code imho. But the OP's question wasn't on the pros and cons of different migration strategies, which is a more complex topic I'm afraid. – mnemosyn Nov 23 '16 at 20:28
32

To add to mnemosyn's answer, while a simple ReplaceOneAsync does update a document it isn't equivalent to Save as Save would also insert the document if it didn't find one to update.

To achieve the same behavior with ReplaceOneAsync you need to use the options parameter:

MyType myObject; 
var result = await collection.ReplaceOneAsync(
    item => item.Id == id, 
    myObject, 
    new UpdateOptions {IsUpsert = true});
Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • What driver version are you in? I have tried 2.01 and 2.2.2. There UpdateOptions is not allowed. Required option type is "FindOneAndReplaceOptions". I have no clue on how to create that with an IsUpsert setting. – Jakob Lithner Jan 15 '16 at 15:48
  • @JakobLithner My code calls `ReplaceOneAsync`. are you sure you're not calling `FindOneAndReplaceAsync`? – i3arnon Jan 15 '16 at 15:50
  • Aaaah, there we are!!!! It is very much friday afternoon here. I need to take brake ... Thanks a lot :) – Jakob Lithner Jan 15 '16 at 15:51
  • Is there any way to achieve the same thing without changing the document ID? By the same thing, I mean doing a simple Idempotent "Upsert" operation, providing a new version of the document without specifying specific fields that have changed. – solvingJ Apr 20 '17 at 02:45
  • @solvingJ this doesn't change the document id – i3arnon Apr 20 '17 at 05:17
  • Can this be done in a single batch call? or does each document have to be updated in some kind of loop? It seems there is a way to do updates, but it only updates a single field OR you can do the whole record one at a time. It would be nice to know how to update an entire IEnumerable in one call. – jwrightmail Nov 03 '21 at 06:12
  • @jwrightmail https://stackoverflow.com/a/47105015/885318 – i3arnon Nov 04 '21 at 07:04
7

you can use LINQ as following:

await context.collection.ReplaceOneAsync(b=> b.Id == item.Id,item);
Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
reda bakr
  • 109
  • 1
  • 4
1

use ObjectId.Parse(id)

var filter = Builders<MyType>.Filter.Eq(s => s.Id, ObjectId.Parse(id));
var update = Builders<MyType>.Update.Set(s => s.Description, description);
var result = await collection.UpdateOneAsync(filter, update);