asp.net 如何筛选集合中具有不同类型的嵌套对象

j5fpnvbx  于 2023-02-01  发布在  .NET
关注(0)|答案(1)|浏览(168)

Vehicle集合中,我有两种不同类型的文档-SuvTruck

public abstract class BaseCar 
{
   public Guid Id { get; set; }
   public Guid Title { get; set; }
   public int YearOfProduction { get; set; }
   ...
}

public class Suv : BaseVehicle 
{
   ...
   public List<Engine> Engines { get; set; }
}

public class Truck : BaseVehicle 
{
   ...
   public List<TruckPart> Parts { get; set; }
}

public class TruckPart 
{
   ...
   public List<Engine> Engines { get; set; }
}

public class Engine 
{
   ...
   public int HorsePower { get; set; }
}

现在我想通过YearOfProductionHorsePower过滤Vehicles的集合,得到所有的id's,除了分别得到每种类型的文档,然后对每种类型的文档进行排序之外,有没有其他的方法呢?

var suv = database.GetCollection<Suv>("vehicles");
var trucks = database.GetCollection<Trucks>("vehicles");

//filters for suvs, trucks and then displaying a list of ids of all matching vehicles
pokxtpni

pokxtpni1#

    • 先决条件**

要在MongoDB类中实现多态概念,需要应用BsonKnownTypes属性,让序列化器知道应该Map到哪个inherit/sub-class。
参考文件:Polymorphism in MongoDB .NET Driver

[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(Suv), typeof(Truck))]
public abstract class BaseVehicle
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    public int YearOfProduction { get; set; }
}

您的BSON文档需要包含_t字段,该字段是指定其类型的鉴别符。例如:

{
  "_id": "4bb69277-f61d-46f2-91ed-1e9b65ddf66d",
  "YearOfProduction": 2020,
  "Engines": [
    {
      "HorsePower": 800
    }
  ],
  "Title": "Suv 2",
  "_t": "Suv"
}
    • 方法1:使用MongoDB. NET驱动程序可流畅运行到BsonDocument**

使用MongoDB. NET驱动程序,很难用Fluent API实现查询过滤器(由于强类型),因此下面的扩展方法是将FilterDefinition<T>转换为BsonDocument

public static class IMongoCollectionExtensions
{
    public static BsonDocument QueryToBson<T>(this IMongoCollection<T> collection,
        FilterDefinition<T> filter)
    {
        return filter.Render(
            collection.DocumentSerializer,
            collection.Settings.SerializerRegistry);
    }
}

一堆Fluent查询,需要将它们组合成一个BsonDocument

IMongoCollection<BaseVehicle> _collection = _db.GetCollection<BaseVehicle>("vehicle");
IMongoCollection<Suv> _suvCollection = _db.GetCollection<Suv>("vehicle");
IMongoCollection<Truck> _truckCollection = _db.GetCollection<Truck>("vehicle");
IMongoCollection<BsonDocument> _bsonCollection = _db.GetCollection<BsonDocument>("vehicle");

FilterDefinition<Suv> suvFilter = Builders<Suv>.Filter.ElemMatch(x => x.Engines,
    Builders<Engine>.Filter.Eq(y => y.HorsePower, 1000));

FilterDefinition<Truck> truckFilter = Builders<Truck>.Filter.ElemMatch(x => x.Parts,
    Builders<TruckPart>.Filter.ElemMatch(y => y.Engines,
        Builders<Engine>.Filter.Eq(z => z.HorsePower, 1000)));

FilterDefinition<BaseVehicle> baseFilter = Builders<BaseVehicle>.Filter.Eq(x => x.YearOfProduction, 2022);

FilterDefinition<BsonDocument> filter = _collection.QueryToBson(baseFilter);
filter &= (FilterDefinition<BsonDocument>)_suvCollection.QueryToBson(suvFilter)
    | (FilterDefinition<BsonDocument>)_truckCollection.QueryToBson(truckFilter);

var result = await _collection.Find(_bsonCollection.QueryToBson(filter))
    .ToListAsync();
    • 方法二:将查询作为BsonDocument**传递

这种方法在没有Fluent API的情况下会简单得多。和往常一样,您可以构建查询并使用MongoDB Compass(导出到特定语言)将其转换为BsonDocument

db.collection.find({
  "YearOfProduction": 2022,
  $or: [
    {
      "Engines": {
        "$elemMatch": {
          "HorsePower": 1000
        }
      }
    },
    {
      "Parts": {
        "$elemMatch": {
          "Engines": {
            "$elemMatch": {
              "HorsePower": 1000
            }
          }
        }
      }
    }
  ]
})

您的查询应如下所示:

FilterDefinition<BaseVehicle> filter = new BsonDocument
{
    { "YearOfProduction", 2022 },
    { "$or", new BsonArray
        {
            new BsonDocument("Engines",
                new BsonDocument("$elemMatch",
                    new BsonDocument("HorsePower", 1000))),
            new BsonDocument("Parts",
                new BsonDocument("$elemMatch",
                    new BsonDocument("Engines",
                        new BsonDocument("$elemMatch",
                            new BsonDocument("HorsePower", 1000)))))
        } 
    }
};

相关问题