c# - 尝试更新嵌套数组时出现 Mongo 错误:未找到标识符的数组过滤器
问题描述
我正在尝试在 Mongo 中更新代表具有以下场景的社区的文档。
- 一个社区有一组块
- 一个街区有一系列楼层
- 一层有一系列门
- 一扇门有一组标签名称
给定一个文档 ID 和有关必须放置在每扇门中的标签的信息,我想使用MongoDb C# 驱动程序 v2.10.4并mongo:latest
更新嵌套列表(几个级别)。我已经阅读了有关数组过滤器的文档,但我无法让它工作。
我从头开始创建了一个存储库来重现该问题,并在自述文件中提供了有关如何运行集成测试和使用 docker 运行本地 MongoDB 的说明。
但总而言之,我的方法对标签进行分组,以便我可以在所需的门上批量放置名称,然后迭代这些组并更新 Mongo 上的特定文档,在某些级别的深层嵌套对象中设置所需的值。我想不出更有效的方法。
上述 repo 中的所有代码。
数据库文件:
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>();
}
数组过滤器有问题的方法:
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
,它是一个字符串数组。
假设我无法更改存储库的方法签名,我很感激任何帮助以及关于它是否是正确方法的建议。
解决方案结果:感谢@mickl 的快速回答,它运行良好。在这个repo 的特定历史点上的结果完全符合建议。
解决方案
$[{houseBlockName}]
需要一个充当占位符的标识符,并在(位置过滤)中定义了相应的arrayfilters
过滤器。似乎您正在尝试直接传递不正确的过滤器值。
您的 C# 代码可能如下所示:
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.$[block].Floors.$[floor].Doors.$[door].LabelNames", names);
var arrayFilters = new List<ArrayFilterDefinition>();
ArrayFilterDefinition<BsonDocument> blockFilter = new BsonDocument("block.Name", new BsonDocument("$eq", houseBlockName));
ArrayFilterDefinition<BsonDocument> floorFilter = new BsonDocument("floor.Name", new BsonDocument("$eq", houseFloorName));
ArrayFilterDefinition<BsonDocument> doorFilter = new BsonDocument("door.Name", new BsonDocument("$eq", houseDoorName));
arrayFilters.Add(blockFilter);
arrayFilters.Add(floorFilter);
arrayFilters.Add(doorFilter);
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
var result = _communities.UpdateOne(filter, update, updateOptions);
推荐阅读
- qt - qtRunLoggedCommand 在哪里定义?
- vue.js - 带有 BootstrapVue 可编辑表格行的 VeeValidate
- android - 如何解决资源文件中的标识符预期错误
- arrays - 将一个数组的值与另一个数组相加
- c# - 无法在修改后的 C1 CMS 上添加或修改数据类型
- continuous-integration - Gitlab runner 上的 kubectl 凭证错误
- java - 我的 Minecraft 插件有问题吗?
- android - 从 API 获取图像并存储到房间数据库中
- vue.js - vue中的条件包装器渲染
- odoo-13 - OSError:找不到文件 Odoo 13