I am trying to implement an Upsert method in C# using MongoDB driver 1.9.2 for .NET.
The idea is to pass an object to the method; if the object already exists in the MongoDB, then update data in all columns; if it doesn't exist, then create a new document in MongoDB.
My object has a member named id
. If my method receives an object that doesn't have an id
set, then a new record is created in MongoDB, just as expected.
However, if it does have an id
, for example "2", it throws this exception instead of updating the values:
Command 'findAndModify' failed: exception: insertDocument :: caused by :: 11000 E11000 duplicate key error index: XXXXXXXX.MyObjectClassName.$id dup key: {: 2 } ...
Here's how the method looks like:
public override void Save(TModel modelObject)
{
MongoServer server = ConnectMongo();
var database = server.GetDatabase(ModelDatabaseName);
// custom method that determines which column is the key column for this type of object, e.g. "id" or "requestID" or "taskID"
var query = BuildQueryByKey(modelObject);
var update = Update<TModel>.Replace(modelObject);
MongoCollection collection = database.GetCollection<TModel>(mWriteCollectionName);
FindAndModifyArgs args = new FindAndModifyArgs()
{
Upsert = true, //update if exists, otherwise insert
Query = query,
Update = update,
VersionReturned = FindAndModifyDocumentVersion.Modified
//Fields =
};
var result = collection.FindAndModify(args);
}
After researching on StackOverflow, I found that some people solved the issue by adding the [BsonIgnoreIfDefault]
attribute to the id column in the object definition, but it didn't change anything for me.
Any ideas what I'm doing wrong? Is there any sample implementation for the FindAndModify to update or insert an object in MongoDB?
Update:
I got it to work (partially) by manually building the query instead of using my custom method. So the custom method was returning a query that looked for id=2
, and turns out what I needed was _id=2
.
So the update works now, but the insert doesn't. Instead of auto-generating the _id, Mongo seems to expect that I will pass the next ID, e.g. "8" if I already have 7 rows. Then it inserts successfully. Can't it generate an auto-incremented ID automatically?
Yes there is, check this answer
I can't see what is happening in BuildQueryByKey. But you really need to find out what document your code is sending to the FindAndUpdate command.
Just print out your query and update vars to see what is happening.
EDIT: for your autogenerating _id, just remove it from your document ;-) Or set it to null and add the [BsonIgnoreIfDefault] attribute