Элемент массива обновления Mongo (драйвер .NET 2.0)

EDIT: Не ища javascript способ сделать это. Я ищу способ MongoDB С# 2.0 сделать это (я знаю, что это может быть невозможно, но я надеюсь, что кто-то знает решение).

Я пытаюсь обновить значение элемента, встроенного в массив в основном документе в моем mongodb.

Я ищу строго типизированный способ сделать это. Я использую драйвер Mongodb С# 2.0

Я могу сделать это, щелкнув элемент, обновив значение, а затем снова вставив его. Это просто не кажется правильным; потому что я переписываю то, что могло быть написано тем временем.

Вот что я пробовал до сих пор, но не повезло:

private readonly IMongoCollection<TempAgenda> _collection;

void Main()
{
    var collectionName = "Agenda";
    var client = new MongoClient("mongodb://localhost:27017");
    var db = client.GetDatabase("Test");
    _collection = db.GetCollection<TempAgenda>(collectionName);
    UpdateItemTitle(1, 1, "hello");
}

public void UpdateItemTitle(string agendaId, string itemId, string title){
    var filter = Builders<TempAgenda>.Filter.Eq(x => x.AgendaId, agendaId);
    var update = Builders<TempAgenda>.Update.Set(x => x.Items.Single(p => p.Id.Equals(itemId)).Title, title);
    var result = _collection.UpdateOneAsync(filter, update).Result;
}

Ответ 1

Понадобился время, чтобы понять это, поскольку он не упоминается ни в одной официальной документации (или где-либо еще). Тем не менее, я нашел этот в своем журнале отслеживания проблем, в котором объясняется, как использовать оператор позиционирования $ с драйвером С# 2.0.

Это должно делать то, что вы хотите:

public void UpdateItemTitle(string agendaId, string itemId, string title){
    var filter = Builders<TempAgenda>.Filter.Where(x => x.AgendaId == agendaId && x.Items.Any(i => i.Id == itemId));
    var update = Builders<TempAgenda>.Update.Set(x => x.Items[-1].Title, title);
    var result = _collection.UpdateOneAsync(filter, update).Result;
}

Обратите внимание, что ваше предложение Item.Single() было изменено на Item.Any() и перенесено в определение фильтра.

[-1] или .ElementAt(-1), по-видимому, обрабатывается специально (фактически все < 0) и заменяется позиционным оператором $.

Вышеупомянутые будут переведены на этот запрос:

db.Agenda.update({ AgendaId: 1, Items.Id: 1 }, { $set: { Items.$.Title: "hello" } })

Ответ 2

Спасибо, это было полезно. У меня есть дополнение, хотя, я использовал выше для массивов, нажав на вложенный массив и вытащив из него. Проблема, которую я обнаружил, заключается в том, что если бы у меня был массив int (так что не объект, просто простой массив int), который PullFilter фактически не работал - "Невозможно определить информацию о сериализации", что странно, поскольку это только массив of ints. То, что я закончил, делало его массивом объектов только с одним параметром int, и все это начало работать. Возможно, ошибка, или, может быть, мое отсутствие понимания. Во всяком случае, поскольку я изо всех сил пытался найти информацию о том, как вытащить и нажав на вложенные массивы объектов с помощью драйвера С# 2.0, мне показалось, что я должен опубликовать свои результаты здесь, поскольку они используют вышеупомянутый синтаксис.

var filter = Builders<MessageDto>.Filter.Where(x => x._id == entity.ParentID && x.NestedArray.Any(i => i._id == entity._id));
var update = Builders<MessageDto>.Update.PullFilter(x => x.NestedArray.ElementAt(-1).User, Builders<User>.Filter.Eq(f => f.UserID, userID));
Collection<MessageDto>(currentUser).UpdateOneAsync(filter, update);

А также:

var filter = Builders<MessageDto>.Filter.Where(x => x._id == entity.ParentID && x.NestedArray.Any(i => i._id == entity._id));
var update = Builders<MessageDto>.Update.Push(x => x.NestedArray.ElementAt(-1).Users, new User { UserID = userID });
Collection<MessageDto>(currentUser).UpdateOneAsync(filter, update);