MongoDB C#驱动:仅当foo更大时将bar更新为foo的值
问题描述
我有如下结构的MongoDB文档:
_id: ObjectId('deadbeefdeadbeefdeadbeef') foo: 6 bar: 0
需求是:仅当foo的值大于bar时,将bar更新为foo的值。
尝试了两种常规更新方式都无法生效:
- 使用
Max方法时,无法在更新语句中引用当前文档的foo字段:
_collection.UpdateMany( filter: document => true, update: Builders<MyDocument>.Update.Max(document => document.Bar, ___) // 无法在此处引用foo );
- 尝试在过滤器中直接比较两个字段,驱动抛出异常:
_collection.UpdateMany( filter: document => document.Bar < document.Foo, update: Builders<MyDocument>.Update.Set(document => document.Bar, ___) ); // System.ArgumentException: Unsupported filter: ({document}{bar} < {document}{foo})
使用的是MongoDB C#驱动2.13.0,找不到相关的内部字段引用资料,求优雅实现方式。
解决方案
在MongoDB 4.2及以上版本中,使用聚合管道执行更新是引用文档内部字段的最优方案,C#驱动2.13.0完全支持这种方式。
方法一:使用聚合管道构造更新
先通过过滤器筛选出bar < foo的文档,再用聚合管道的$set操作将bar赋值为foo:
// 构造跨字段比较的过滤器 var filter = Builders<MyDocument>.Filter.Lt(document => document.Bar, document => document.Foo); // 用聚合管道定义更新逻辑,直接引用当前文档的foo字段 var update = Builders<MyDocument>.Update.Pipeline( new BsonDocument("$set", new BsonDocument("bar", "$foo")) ); // 执行批量更新 _collection.UpdateMany(filter, update);
方法二:直接构造原生Bson更新语句
如果觉得管道写法繁琐,也可以用Raw方法传入原生Bson,效果一致:
var filter = Builders<MyDocument>.Filter.Lt("bar", "foo"); var update = Builders<MyDocument>.Update.Raw( new BsonDocument("$set", new BsonDocument("bar", "$foo")) ); _collection.UpdateMany(filter, update);
关键说明
- 之前过滤器报错的原因:不能直接在lambda表达式中写
document.Bar < document.Foo,必须用驱动提供的FilterDefinitionBuilder方法(如Lt)来构造跨字段比较的过滤器。 - 聚合管道更新的优势:支持直接引用当前文档的字段值,无需提前查询字段内容,原子性执行更新操作。
内容的提问来源于stack exchange,提问作者Will Maynard
相关产品推荐
相关产品推荐

