MongoDB .NET Driver:如何递增双层嵌套字段?
问题描述
需求:递增MongoDB实体中带有指定标识符的双层嵌套字段amount。以下是competition_dota2的文档示例:
{ "id" : "b350c9fd-3632-4b0a-b5cb-66e41d530f55", "type" : "COMPETITION_TYPE_ESPORTDOTA2", "status_type" : "COMPETITION_STATUS_TYPE_WAITING", "start_time" : { "seconds": "60", "nanos": 928852400 }, "coefficient_groups" : [ { "id" : "b350c9fd-3632-4b0a-b5cb-66e41d530f55", "name" : "winner", "type" : "OUTCOME_GROUP_TYPE_ONE_WINNER", "coefficients" : [ { "id" : "b350c9fd-3632-4b0a-b5cb-66e41d530f55", "description" : "team1 won", "rate" : 1.2, "status_type" : "COEFFICIENT_STATUS_TYPE_ACTIVE", "amount" : 0, "probability" : 50 }, { "id" : "3c203bd7-2d7e-4937-a82a-e451cedf2ba8", "description" : "team2 won", "rate" : 0, "status_type" : "COEFFICIENT_STATUS_TYPE_ACTIVE", "amount" : 0, "probability" : 50 } ] } ], "team1_id" : "b350c9fd-3632-4b0a-b5cb-66e41d530f55", "team2_id" : "b350c9fd-3632-4b0a-b5cb-66e41d530f55", "team1_kill_amount" : 0, "team2_kill_amount" : 0, "total_time" : { "seconds": "60", "nanos": 928852400 } }
我尝试用以下C#代码递增amount字段,但仅针对顶层模型CompetitionDota2Entity创建了查询选项,请问这样的实现是否可行?
var competitionIdstring = competitionId.ToString(); var сoefficientIdstring = сoefficientId.ToString(); var filterBuilder = Builders<CompetitionDota2Entity>.Filter; var updateBuilder = Builders<CompetitionDota2Entity>.Update; var filterCompetitionId = filterBuilder.Eq(x => x.Id, competitionId.ToString()); var update = Builders<CompetitionDota2Entity>.Update; var incAmount = update.Inc( "CompetitionDota2Entity.CoefficientGroups.$.Coefficients.$.Amount", amount); var existingCoefficientGroup = await _collection.FindOneAndUpdateAsync( filterCompetitionId, incAmount, _defaultCompetitionDota2EntityFindOption, token);
解答
你的实现不可行,存在两个核心问题:
1. 更新路径错误
MongoDB的更新路径不需要包含实体类名称CompetitionDota2Entity,应该直接使用文档中的嵌套字段路径(匹配JSON里的蛇形命名,或对应实体类映射到MongoDB的字段名)。正确的路径应该是"coefficient_groups.$.coefficients.$.amount"(对应JSON文档字段),如果你的C#实体类用驼峰命名且MongoDB驱动配置了自动映射,也可以用"CoefficientGroups.$.Coefficients.$.Amount",但绝对不能加实体类前缀。
2. 缺少嵌套数组的过滤条件
MongoDB的$占位符用于匹配数组中第一个符合过滤条件的元素,但你当前的filter只指定了顶层的competition id,没有匹配目标coefficient_group和coefficient的id,导致MongoDB无法定位到需要更新的嵌套元素。
修正后的代码
var competitionIdStr = competitionId.ToString(); var coefficientIdStr = сoefficientId.ToString(); // 假设你有目标coefficient_group的id变量,比如coefficientGroupId var coefficientGroupIdStr = coefficientGroupId.ToString(); var filterBuilder = Builders<CompetitionDota2Entity>.Filter; // 同时匹配competition id、目标coefficient_group的id、目标coefficient的id var filter = filterBuilder.And( filterBuilder.Eq(x => x.Id, competitionIdStr), filterBuilder.ElemMatch(x => x.CoefficientGroups, cg => cg.Id == coefficientGroupIdStr), filterBuilder.ElemMatch(x => x.CoefficientGroups[-1].Coefficients, c => c.Id == coefficientIdStr) ); var updateBuilder = Builders<CompetitionDota2Entity>.Update; // 使用正确的嵌套路径,去掉实体类名 var incAmount = updateBuilder.Inc("CoefficientGroups.$.Coefficients.$.Amount", amount); var existingCoefficientGroup = await _collection.FindOneAndUpdateAsync( filter, incAmount, _defaultCompetitionDota2EntityFindOption, token);
关键说明
- 用
ElemMatch分别匹配coefficient_groups和coefficients数组中的目标元素,确保$占位符能精准定位到需要更新的嵌套对象。 - 更新路径直接使用实体类的属性名即可,MongoDB驱动会自动处理与JSON字段名的映射(若配置了驼峰转蛇形规则)。
内容的提问来源于stack exchange,提问作者bynik
相关产品推荐
相关产品推荐

