You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何针对含不同类型嵌套对象的Vehicle集合进行筛选

问题描述

MongoDB的Vehicle集合里存着Suv和Truck两种类型的文档,对应的C#模型定义如下:

public abstract class BaseCar 
{
   public Guid Id { get; set; }
   public string Title { get; set; } // 原代码中Title为Guid类型应为笔误,此处修正为string
   public int YearOfProduction { get; set; }
   // 其他属性
}

public class Suv : BaseCar 
{
   // 其他属性
   public List<Engine> Engines { get; set; }
}

public class Truck : BaseCar 
{
   // 其他属性
   public List<TruckPart> Parts { get; set; }
}

public class TruckPart 
{
   // 其他属性
   public List<Engine> Engines { get; set; }
}

public class Engine 
{
   // 其他属性
   public int HorsePower { get; set; }
}

现在需要按YearOfProduction(生产年份)和HorsePower(马力)筛选集合,获取所有符合条件的车辆ID。除了分别查询两种类型文档再合并结果的方式外,还有其他实现方案吗?

当前初步实现代码如下:

var suvCollection = database.GetCollection<Suv>("vehicles");
var truckCollection = database.GetCollection<Truck>("vehicles");

// 分别为SUV和Truck编写筛选逻辑,然后合并ID列表
解决方案

当然有更高效的实现方式,不用分开查询两种类型,下面给出两种可行方案:

1. 使用BaseCar集合配合LINQ查询

直接获取BaseCar类型的集合,利用MongoDB LINQ的多态查询能力,一次查询即可筛选出符合条件的文档并提取ID:

var vehicleCollection = database.GetCollection<BaseCar>("vehicles");

// 示例筛选条件:2020年生产、马力不低于300
var targetYear = 2020;
var minHorsePower = 300;

var matchingIds = vehicleCollection.AsQueryable()
    .Where(car => 
        car.YearOfProduction == targetYear &&
        (
            // SUV的引擎中至少有一个符合马力要求
            car is Suv suv && suv.Engines.Any(e => e.HorsePower >= minHorsePower) ||
            // Truck的任意零件下的引擎中至少有一个符合马力要求
            car is Truck truck && truck.Parts.Any(p => p.Engines.Any(e => e.HorsePower >= minHorsePower))
        ))
    .Select(car => car.Id)
    .ToList();

这种方式依赖MongoDB对继承类型的支持——驱动默认会在文档中存储_t字段标记具体子类,LINQ会自动转换为对应的MongoDB查询语句,一次请求就能获取所有符合条件的ID。

2. 使用BsonDocument构建原生查询

如果需要更灵活的控制,也可以直接编写原生MongoDB查询语句,通过$or条件同时匹配两种类型的文档:

var vehicleCollection = database.GetCollection<BsonDocument>("vehicles");

var filter = Builders<BsonDocument>.Filter.And(
    Builders<BsonDocument>.Filter.Eq("YearOfProduction", 2020),
    Builders<BsonDocument>.Filter.Or(
        // 匹配SUV类型,且存在引擎马力>=300
        Builders<BsonDocument>.Filter.And(
            Builders<BsonDocument>.Filter.Eq("_t", "Suv"),
            Builders<BsonDocument>.Filter.ElemMatch("Engines", Builders<BsonDocument>.Filter.Gte("HorsePower", 300))
        ),
        // 匹配Truck类型,且存在零件下的引擎马力>=300
        Builders<BsonDocument>.Filter.And(
            Builders<BsonDocument>.Filter.Eq("_t", "Truck"),
            Builders<BsonDocument>.Filter.ElemMatch("Parts", Builders<BsonDocument>.Filter.ElemMatch("Engines", Builders<BsonDocument>.Filter.Gte("HorsePower", 300)))
        )
    )
);

var matchingIds = vehicleCollection.Find(filter)
    .Project(Builders<BsonDocument>.Projection.Include("Id")) // 仅返回Id字段,减少数据传输
    .ToList()
    .Select(doc => doc.GetValue("Id").AsGuid)
    .ToList();

这种方式不依赖实体类,直接操作BsonDocument,适合复杂查询场景,同样只需要一次数据库查询。

注意事项

  • 确保MongoDB文档中存在_t字段(MongoDB驱动默认会为继承类型添加该字段,标记具体子类),否则无法区分Suv和Truck。
  • 可以为YearOfProduction、_t以及嵌套的HorsePower字段创建索引,提升查询性能。

内容的提问来源于stack exchange,提问作者Adam Wróbel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 18:50:41