In the official documentation of mongodb they mention upserts, so it would be really nice to write an upsert command instead of:
if (_campaignRepo.Exists(camp))
{
_campaignRepo.DeleteByIdAndSystemId(camp);
}
_campaignRepo.Save(camp);
something which would implement that logic on the db level if it is possible. So what is the way to do an upsert if there is one?
The following code is from a working app:
weekplanStore.Update(
Query.EQ("weekNumber", week),
Update.Replace(rawWeekPlan),
UpdateFlags.Upsert);
The weekplanStore is my MongoDB collection, and the code will update the document found with the query in the first argument or insert a new one if none is found. The "trick" is to use the UpdateFlags.Upsert modifier.
The rawWeekPlan is the object inserted or updated, and has the following type:
private class RawWeekPlan
{
public ObjectId id;
public int weekNumber;
public WeekPlanEntry[] entries;
}
and turned into bson by the driver automatically.
Version 2 of the MongoDB C# driver requires setting the IsUpsert
flag in the write commands. This example will upsert an entire document.
var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } };
var result = await collection.ReplaceOneAsync(
filter: new BsonDocument("_id", 123),
options: new UpdateOptions { IsUpsert = true },
replacement: newDoc);
Version 1 of the MongoDB C# driver implements this logic within the Save
command.
var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } };
collection.Save(newDoc);
The Save method is a combination of Insert and Update. If the Id member of the document has a value, then it is assumed to be an existing document and Save calls Update on the document (setting the Upsert flag just in case it actually is a new document after all). Otherwise it is assumed to be a new document and Save calls Insert after first assigning a newly generated unique value to the Id member.
Reference: http://mongodb.github.io/mongo-csharp-driver/1.11/driver/#save-tdocument-method
Note: This does require the proper mapping of the Id field however. More info on that here: http://mongodb.github.io/mongo-csharp-driver/1.11/serialization/#identifying-the-id-field-or-property
Starting from v2.0 of the driver there's a new async-only API. The old API should no longer be used as it's a blocking facade over the new API and is deprecated.
The currently recommended way to upsert a document is by calling and awaiting ReplaceOneAsync
with the IsUpsert
flag turned on and a filter that matches the relevant document:
Hamster hamster = ...
var replaceOneResult = await collection.ReplaceOneAsync(
doc => doc.Id == hamster.Id,
hamster,
new UpdateOptions {IsUpsert = true});
You can check whether the operation was an insert or an update by looking at ReplaceOneResult.MatchedCount
:
You can use the regular update command, but just pass it the Upsert update flag
MongoCollection collection = db.GetCollection("matches");
var query = new QueryDocument("recordId", recordId);
var update = Update.Set("FirstName", "John").Set("LastName","Doe");
matchCollection.Update(query, update, UpdateFlags.Upsert, SafeMode.False);
That code is adapted from a working application (shortened for clarity)
来源:https://stackoverflow.com/questions/7240028/upserting-in-mongo-db-using-official-c-sharp-driver