Обновление в Mongo DB с использованием официального драйвера C #

В официальной документации mongodb упоминаются upserts, поэтому было бы неплохо написать команду upsert вместо:

if (_campaignRepo.Exists(camp))
{
    _campaignRepo.DeleteByIdAndSystemId(camp);
}

_campaignRepo.Save(camp);

что-то, что реализовало бы эту логику на уровне db, если это возможно. Так как же сделать апсерт, если он есть?


person Yurii Hohan    schedule 30.08.2011    source источник


Ответы (4)


Следующий код взят из рабочего приложения:

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 драйвером.

person Christian Horsdal    schedule 30.08.2011
comment
Это работает для вложенных коллекций? Вы пробовали это? Потому что в моем случае это не работает для них - person Yurii Hohan; 02.09.2011

Версия 2 драйвера MongoDB C # требует установки флага IsUpsert в командах записи. В этом примере будет вставлен весь документ.

var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } };
var result = await collection.ReplaceOneAsync(
                filter: new BsonDocument("_id", 123),
                options: new ReplaceOptions { IsUpsert = true },
                replacement: newDoc);

Версия 1 драйвера MongoDB C # реализует эту логику в команде Save.

var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } };
collection.Save(newDoc);

Метод Save представляет собой комбинацию Insert и Update. Если член Id документа имеет значение, то предполагается, что это существующий документ, и Save вызывает Update в документе (установка флага Upsert на всякий случай, если это действительно новый документ). В противном случае предполагается, что это новый документ, и Save вызывает Insert после первого присвоения вновь созданного уникального значения члену 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.

person Mani Gandham    schedule 30.08.2011
comment
Это больше невозможно с новым API. - person Asad Saeeduddin; 14.08.2015
comment
Обновлено. Хотя я думаю, что новый API усложнил использование команд upsert. - person Mani Gandham; 15.08.2015
comment
Что передается фильтру, если идентификатор newDocs равен нулю, то есть это вставка? Просто пустой документ bson? - person BenCr; 02.11.2015
comment
@BenCr, если вы просто делаете обычную вставку вместо upsert, вам следует использовать метод InsertOneAsync. Для этого не требуется указывать поле идентификатора, поскольку MongoDB создаст его во время вставки, но вы также можете создавать эти идентификаторы, не обращаясь к базе данных, точно так же, как GUID, так что это зависит от вас. Дополнительная информация в документации драйвера C # здесь: mongodb. github.io/mongo-csharp-driver/2.1/reference/driver/crud/ - person Mani Gandham; 04.11.2015

Начиная с версии 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:

person i3arnon    schedule 15.05.2015
comment
Я пытаюсь использовать ReplaceOneAsync, но выдает исключение: «Имя элемента» недействительно, я использую фильтр для updateOneasync, он работает, но не с replaceone. не могли бы вы мне помочь? - person sifa vahora; 02.11.2017
comment
UpdateOptions устарел, используйте новый ReplaceOptions {IsUpsert = true}); Теперь - person Alde; 11.05.2020

Вы можете использовать обычную команду обновления, но просто передайте ей флаг обновления 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);

Этот код адаптирован из рабочего приложения (сокращен для ясности)

person jeffsaracco    schedule 30.08.2011