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

MongoDB C#驱动聚合管道切换输出模型及关联查询实现

解决方案

1. 原生聚合管道+类型映射实现DTO输出

通过构建原生BsonDocument聚合管道,完成Lookup关联后直接指定输出类型为目标DTO,无需修改存储模型。核心是用$lookup关联集合,$unwind将关联数组转为单个对象,最后通过Aggregate<TOutput>完成类型映射。

代码示例

// 存储模型
public class BarDb
{
    public ObjectId Id { get; set; }
    public ObjectId FooId { get; set; }
    // 其他业务字段
}

// 返回用DTO
public class BarDTO
{
    public ObjectId Id { get; set; }
    public FooDb Foo { get; set; }
    // 其他业务字段
}

public class FooDb
{
    public ObjectId Id { get; set; }
    public string Name { get; set; }
    // 其他业务字段
}

// 聚合查询实现
var barCollection = _mongoDatabase.GetCollection<BarDb>("bars");

var aggregationPipeline = new BsonDocument[]
{
    // 关联Foo集合
    new BsonDocument("$lookup", new BsonDocument
    {
        { "from", "foos" },
        { "localField", "FooId" },
        { "foreignField", "_id" },
        { "as", "Foo" }
    }),
    // 将Lookup返回的数组转为单个对象,保留空值场景
    new BsonDocument("$unwind", new BsonDocument
    {
        { "path", "$Foo" },
        { "preserveNullAndEmptyArrays", true }
    }),
    // 可选:排除原关联ID字段,精简DTO结构
    new BsonDocument("$project", new BsonDocument("FooId", 0))
};

// 执行聚合并映射为BarDTO
var result = await barCollection.Aggregate<BarDTO>(aggregationPipeline).ToListAsync();

2. Fluent API兼容方案

若偏好Fluent语法,可通过AppendStage插入原生Lookup阶段,避免Linq表达式不支持的问题,后续继续用Fluent方法完成类型映射:

var result = await barCollection.Aggregate()
    .AppendStage<BsonDocument>(new BsonDocument("$lookup", new BsonDocument
    {
        { "from", "foos" },
        { "localField", "FooId" },
        { "foreignField", "_id" },
        { "as", "Foo" }
    }))
    .AppendStage<BsonDocument>(new BsonDocument("$unwind", "$Foo"))
    .Project<BarDTO>(Builders<BsonDocument>.Projection.Exclude("FooId"))
    .ToListAsync();

3. 通用CRUD仓库适配

为适配统一仓库架构,可封装泛型聚合方法,支持跨模型的DTO输出:

public class GenericMongoRepository<TDocument> : IGenericRepository<TDocument>
{
    private readonly IMongoCollection<TDocument> _collection;

    public GenericMongoRepository(IMongoDatabase database)
    {
        _collection = database.GetCollection<TDocument>(typeof(TDocument).Name);
    }

    public async Task<List<TOutput>> AggregateToDtoAsync<TOutput>(PipelineDefinition<TDocument, BsonDocument> pipeline)
    {
        return await _collection.Aggregate<TOutput>(pipeline).ToListAsync();
    }
}

// 调用示例
var pipeline = new PipelineDefinition<BarDb, BsonDocument>(new[]
{
    new BsonDocument("$lookup", ...),
    new BsonDocument("$unwind", ...)
});
var barDtos = await _genericRepository.AggregateToDtoAsync<BarDTO>(pipeline);

核心优势

  • 无需修改存储模型,避免冗余字段
  • 单次聚合查询完成关联与映射,性能优于多次查询
  • 适配通用CRUD架构,无需新增Read模型增加复杂度

内容的提问来源于stack exchange,提问作者GiBhu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:07:12