Я пытаюсь обновить документ в Mon go, который представляет сообщество со следующим сценарием.
- У сообщества есть набор блоков
- Блок имеет набор этажей
- На полу есть набор дверей
- Дверь имеет набор имен этикеток
Имеется идентификатор документа и информация о этикетках, которые должны быть помещенным в каждую дверь, я хочу использовать драйвер MongoDb C# v2.10.4 и mongo:latest
для обновления вложенных списков (несколько уровней). Я читал документацию о фильтрах массивов, но у меня не получается, чтобы они работали.
Я создал репозиторий с нуля, чтобы воспроизвести проблему , с инструкциями в Readme о том, как запустить интеграционный тест и локальную MongoDB с docker.
Но, как итог, мой метод группирует метки, чтобы я мог массово размещать имена на желаемой двери и затем он выполняет итерацию по этим группам и обновляет в понедельник go указанный c документ, устанавливая желаемое значение внутри некоторых уровней глубоко вложенного объекта. Я не мог придумать более эффективного способа.
Весь код в приведенном выше репо.
Документ БД:
public class Community
{
public Guid Id { get; set; }
public IEnumerable<Block> Blocks { get; set; } = Enumerable.Empty<Block>();
}
public class Block
{
public string Name { get; set; } = string.Empty;
public IEnumerable<Floor> Floors { get; set; } = Enumerable.Empty<Floor>();
}
public class Floor
{
public string Name { get; set; } = string.Empty;
public IEnumerable<Door> Doors { get; set; } = Enumerable.Empty<Door>();
}
public class Door
{
public string Name { get; set; } = string.Empty;
public IEnumerable<string> LabelNames = Enumerable.Empty<string>();
}
Проблема c метод с фильтрами массива:
public async Task UpdateDoorNames(Guid id, IEnumerable<Label> labels)
{
var labelsGroupedByHouse =
labels
.ToList()
.GroupBy(x => new { x.BlockId, x.FloorId, x.DoorId })
.ToList();
var filter =
Builders<Community>
.Filter
.Where(x => x.Id == id);
foreach (var house in labelsGroupedByHouse)
{
var houseBlockName = house.Key.BlockId;
var houseFloorName = house.Key.FloorId;
var houseDoorName = house.Key.DoorId;
var names = house.Select(x => x.Name).ToList();
var update =
Builders<Community>
.Update
.Set($"Blocks.$[{houseBlockName}].Floors.$[{houseFloorName}].Doors.$[{houseDoorName}].LabelNames", names);
await _communities.UpdateOneAsync(filter, update);
}
}
Исключение равно
MongoDB.Driver.MongoWriteException with the message "A write operation resulted in an error.
No array filter found for identifier 'Block 1' in path 'Blocks.$[Block 1].Floors.$[Ground Floor].Doors.$[A].LabelNames'"
Вот более наглядный пример того, как вложенная структура выглядит в базе данных. Обратите внимание, что я хочу обновить значение LabelNames
, которое представляет собой массив строк.
I appreciate any help to have this working and suggestions on whether it's the right approach assuming that I cannot change the repository's method signature.
SOLUTION RESULT:
Thanks for the quick answer @mickl, it works perfectly.
Result at this спецификация репо c точка истории точно так, как было предложено.