Обновление в Mongo DB с использованием официального драйвера С#
В официальной документации mongodb упоминаются upserts, поэтому было бы очень приятно написать команду upsert вместо:
if (_campaignRepo.Exists(camp))
{
_campaignRepo.DeleteByIdAndSystemId(camp);
}
_campaignRepo.Save(camp);
что-то, что реализовало бы эту логику на уровне db, если это возможно. Итак, каков способ сделать upsert, если он есть?
Ответы
Ответ 1
Следующий код из рабочего приложения:
weekplanStore.Update(
Query.EQ("weekNumber", week),
Update.Replace(rawWeekPlan),
UpdateFlags.Upsert);
WeekplanStore - это моя коллекция MongoDB, и код обновит документ, найденный с помощью запроса, в первом аргументе или добавит новый, если он не найден. "Трюк" заключается в использовании модификатора UpdateFlags.Upsert.
rawWeekPlan - это объект, вставленный или обновленный, и имеет следующий тип:
private class RawWeekPlan
{
public ObjectId id;
public int weekNumber;
public WeekPlanEntry[] entries;
}
и автоматически переключится на bson с помощью драйвера.
Ответ 2
Версия 2 драйвера MongoDB С# требует установки флага IsUpsert
в командах записи. В этом примере будет показан весь документ.
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);
Версия 1 драйвера MongoDB С# реализует эту логику в команде Save
.
var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } };
collection.Save(newDoc);
Метод Save представляет собой комбинацию вставки и обновления. Если элемент Id документа имеет значение, то предполагается, что он является существующим документом, и Save вызывает Update для документа (устанавливая флаг Upsert на тот случай, если он действительно является новым документом). В противном случае предполагается, что это новый документ, и "Сохранить" вызывает "Вставить" после первого присвоения вновь сгенерированного уникального значения члену Id.
Ссылка: http://mongodb.github.io/mongo-csharp-driver/1.11/driver/#save-tdocument-method
Примечание. Однако для этого требуется правильное отображение поля Id. Больше информации об этом здесь: http://mongodb.github.io/mongo-csharp-driver/1.11/serialization/#identifying-the-id-field-or-property
Ответ 3
Начиная с версии 2.0 драйвера есть новый API с асинхронным интерфейсом. Старый API больше не должен использоваться, поскольку он блокирует фасад над новым API и устарел.
Рекомендуемый в настоящее время способ повышения уровня документа - вызов и ожидание ReplaceOneAsync
с включенным флагом IsUpsert
и фильтром, соответствующим соответствующему документу:
Hamster hamster = ...
var replaceOneResult = await collection.ReplaceOneAsync(
doc => doc.Id == hamster.Id,
hamster,
new UpdateOptions {IsUpsert = true});
Вы можете проверить, была ли операция вставкой или обновлением, просмотрев ReplaceOneResult.MatchedCount
:
Ответ 4
Вы можете использовать регулярную команду обновления, но просто передайте ей флаг обновления Upsert
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);
Этот код адаптирован из рабочего приложения (сокращен для ясности)