如何使用C#更新MongoDB中子数组指定元素的字段
解决MongoDB子数组元素更新问题
嘿,我懂你遇到的麻烦了——你想更新文档里Tokens数组中Tokennumber为"444"的元素的LoginDate字段,但当前代码反而在根文档新增了一个LoginDate节点,完全没碰对目标字段对吧?
问题出在哪?
你写的Set("LoginDate", DateTime.Now)没有指定要更新的是数组内匹配元素的LoginDate,MongoDB会默认把这个字段加到根文档层级,这就是为啥会出现多余的节点。
修正方案
要更新数组中匹配条件的元素,得用MongoDB的位置操作符$,它会指代ElemMatch筛选出的数组元素。下面是两种可行的写法:
方式1:使用字符串路径(简单直接)
var result = _users.FindOneAndUpdate( // 筛选出包含目标token的文档 Builders<Users>.Filter.ElemMatch(u => u.Tokens, t => t.Tokennumber == decryptedtoken), // 指定更新数组中匹配元素的LoginDate字段 Builders<Users>.Update.Set("Tokens.$.LoginDate", DateTime.Now) );
方式2:强类型写法(避免硬编码字符串)
如果你想保持强类型,避免拼写错误,可以用MongoDB Driver提供的索引语法[-1],它和$的作用一致:
var result = _users.FindOneAndUpdate( Builders<Users>.Filter.ElemMatch(u => u.Tokens, t => t.Tokennumber == decryptedtoken), Builders<Users>.Update.Set(u => u.Tokens[-1].LoginDate, DateTime.Now) );
额外提示:更新多个匹配元素
如果你的Tokens数组里可能有多个Tokennumber等于decryptedtoken的元素,上面的方法只会更新第一个匹配项。要是想更新所有符合条件的元素,就得用数组过滤器(Array Filters):
// 定义数组过滤器,匹配Tokennumber等于目标值的元素 var updateOptions = new FindOneAndUpdateOptions<Users> { ArrayFilters = new List<ArrayFilterDefinition> { new BsonDocumentArrayFilterDefinition<BsonDocument>( new BsonDocument("t.Tokennumber", decryptedtoken) ) } }; var result = _users.FindOneAndUpdate( // 筛选出包含目标token的文档 Builders<Users>.Filter.AnyIn(u => u.Tokens.Select(t => t.Tokennumber), new[] { decryptedtoken }), // 使用占位符[t]指代过滤器匹配的元素 Builders<Users>.Update.Set("Tokens.$[t].LoginDate", DateTime.Now), updateOptions );
这样就能一次性更新数组中所有Tokennumber匹配的元素的LoginDate啦。
内容的提问来源于stack exchange,提问作者eyal berda
相关产品推荐
相关产品推荐

