如何使用C# MongoDB Driver根据传入数组过滤子文档列表?
MongoDB C#驱动过滤嵌套数组元素问题
模型结构
public class Box { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("relatedJobs")] public List<BoxJobs> RelatedJobs { get; init; } = default!; //更多属性 public class BoxJobs { [BsonElement("partnerId")] public string PartnerId { get; init; } = null!; //更多属性 } }
需求
根据传入的partnerIds数组过滤所有Box文档,需满足:Box至少包含一个relatedJob,且该relatedJob的partnerId存在于传入的数组中。
尝试的代码及错误
尝试使用以下代码实现过滤:
var builder = Builders<Box>.Filter; var filter = new FilterDefinitionBuilder<Box>().Empty; filter &= !partnerIds.Any() ? new FilterDefinitionBuilder<Box>().Empty : builder.AnyIn(box => box.RelatedJobs.Select(relatedJob => relatedJob.PartnerId), partnerIds); var cursor = Collection.Find(filter);
运行后出现错误:
Unable to determine the serialization information for box => box.RelatedJobs.Select(relatedJob => relatedJob.PartnerId).
解决方案
MongoDB C#驱动无法解析LINQ的Select表达式来映射到BSON的嵌套数组字段路径,需要直接针对嵌套数组的属性构建过滤条件,有两种可行方式:
方式一:使用AnyIn指定数组元素属性
利用驱动的特殊语法[-1]表示数组中的任意元素,直接指向relatedJobs数组内元素的PartnerId字段:
var builder = Builders<Box>.Filter; FilterDefinition<Box> filter; if (!partnerIds.Any()) { filter = builder.Empty; // partnerIds为空时返回所有文档,或按需改为builder.Where(b => b.RelatedJobs.Any()) } else { // 匹配relatedJobs数组中存在任意元素的PartnerId在partnerIds中 filter = builder.AnyIn(box => box.RelatedJobs[-1].PartnerId, partnerIds); } var cursor = Collection.Find(filter);
方式二:使用ElemMatch结合In
通过ElemMatch筛选数组中符合条件的元素,效果和方式一一致:
var builder = Builders<Box>.Filter; FilterDefinition<Box> filter; if (!partnerIds.Any()) { filter = builder.Empty; } else { filter = builder.ElemMatch(box => box.RelatedJobs, job => job.PartnerId.In(partnerIds)); } var cursor = Collection.Find(filter);
说明
- 两种方式都能正确映射到MongoDB的查询语法,驱动会将其转换为对应的BSON查询条件。
- 如果需要额外确保
RelatedJobs数组不为空(即使partnerIds为空时也过滤掉无关联Job的Box),可以在partnerIds为空时将filter改为builder.Where(b => b.RelatedJobs.Any())。
内容的提问来源于stack exchange,提问作者cs.kali
相关产品推荐
相关产品推荐

