使用C# MongoDB驱动LINQ在投影中检查字段是否存在
在MongoDB C# LINQ中正确检测投影阶段的字段存在性
问题背景
MongoDB中,字段存在性检查与字段是否为null的检查存在明确差异:
- 聚合框架的
$eq: ["$字段", null]:仅当字段存在且为null时返回true,字段不存在时返回false find方法的{ 字段: { $eq: null } }:会匹配字段不存在或存在且为null的文档
你当前的LINQ代码使用三元运算符a.InexistentField is not null,生成的聚合管道仅用$ne: ["$InexistentField", null]做判断,无法区分字段不存在和字段为null的场景,导致逻辑不符合预期。
解决方案:同时检查字段存在性与非null
要在投影阶段正确区分两种场景,需要同时使用$exists和$ne操作符。在C# LINQ中,可以借助MongoDB驱动提供的Exists()扩展方法实现:
using MongoDB.Driver.Linq; // ... collection.AsQueryable() .Where(a => a.Id == "6310e8bdcb2982dee9af3924") .Select(a => new { Test = a.InexistentField.Exists() && a.InexistentField != null ? a.InexistentField.Property.Field : null });
生成的聚合管道说明
上述LINQ代码会生成包含$and条件的聚合管道,同时验证字段存在性和非null:
databaseName.CollectionName.Aggregate( [ { "$match": { "_id": ObjectId("6310e8bdcb2982dee9af3924") } }, { "$project": { "Test": { "$cond": { "if": { "$and": [ { "$exists": ["$InexistentField", true] }, { "$ne": ["$InexistentField", null] } ] }, "then": "$InexistentField.Property.Field", "else": null } }, "_id": 0 } } ] )
该管道的逻辑:
- 仅当
InexistentField确实存在于文档中且不为null时,才提取嵌套的Property.Field值 - 若字段不存在或字段值为null,直接返回null
兼容早期驱动版本的替代写法
如果你使用的MongoDB驱动版本不支持Exists()扩展方法,可以通过手动构造投影定义实现相同逻辑:
var projection = Builders<YourEntity>.Projection .Expression(a => (a.InexistentField != null && Builders<YourEntity>.Filter.Exists(x => x.InexistentField).Render(a, null, null).Document["InexistentField.$exists"].AsBoolean) ? a.InexistentField.Property.Field : null); var result = collection.AsQueryable() .Where(a => a.Id == "6310e8bdcb2982dee9af3924") .Select(projection) .FirstOrDefault();
内容的提问来源于stack exchange,提问作者Joao Paulo Salles Beraldo
相关产品推荐
相关产品推荐

