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

如何将指定MongoDB聚合查询转换为C# MongoDB Driver流畅语法?

如何将MongoDB的带let和pipeline的$lookup转换为C# MongoDB Driver流畅语法

原MongoDB查询的核心逻辑是:遍历his数据库的Account集合所有文档,通过$lookup关联LinkedEntities集合,同时用AccountId和InstitutionGroupId两个字段进行匹配,最后排除关联结果中的AccountId和_id字段,将结果存入AccountwithLinkedEntities数组。

你当前的C#代码存在两个关键问题,导致和原查询不匹配:

  1. 额外添加了Match过滤条件,原查询并未对Account集合做前置过滤
  2. 使用的是单字段匹配的Lookup重载,没有实现原查询中基于双字段的条件匹配和投影排除

以下是两种正确的实现方案:

方案一:强类型流畅语法(推荐)

先确保实体类定义正确,新增一个用于接收投影后结果的类:

public class Account
{
    public string AccountId { get; set; }
    public string InstitutionGroupId { get; set; }
    // 其他原有字段
    public List<LinkedEntitiesProjection> AccountwithLinkedEntities { get; set; }
}

// 对应原查询中投影后的LinkedEntities结构(排除AccountId和_id)
public class LinkedEntitiesProjection
{
    public string InstitutionGroupId { get; set; }
    // 这里添加LinkedEntities中除AccountId、_id外的所有字段
}

public class LinkedEntities
{
    public ObjectId Id { get; set; }
    public string AccountId { get; set; }
    public string InstitutionGroupId { get; set; }
    // 其他原有字段
}

然后构建聚合查询:

// 构建Lookup内部的匹配和投影逻辑
var lookupPipeline = new PipelineDefinition<LinkedEntities, LinkedEntitiesProjection>()
    // 使用$expr引用let变量进行双字段匹配
    .Match(Builders<LinkedEntities>.Filter.Where(le =>
        le.InstitutionGroupId == "$$institutionGroup_id" &&
        le.AccountId == "$$account_id"))
    // 排除指定字段
    .Project(Builders<LinkedEntities>.Projection
        .Exclude(le => le.AccountId)
        .Exclude(le => le.Id));

// 执行聚合
var accountWithLinkedEntities = await _mongoDbContext.Accounts.Aggregate()
    .Lookup<Account, LinkedEntities, LinkedEntitiesProjection>(
        foreignCollectionName: _mongoDbContext.LinkedEntities.CollectionNamespace.CollectionName,
        localFields: new[]
        {
            new ExpressionFieldDefinition<Account, object>(a => a.AccountId),
            new ExpressionFieldDefinition<Account, object>(a => a.InstitutionGroupId)
        },
        foreignFields: new[]
        {
            // 此处为占位,实际匹配逻辑在lookupPipeline中
            new ExpressionFieldDefinition<LinkedEntities, object>(le => le.AccountId),
            new ExpressionFieldDefinition<LinkedEntities, object>(le => le.InstitutionGroupId)
        },
        @as: a => a.AccountwithLinkedEntities,
        let: new BsonDocument
        {
            { "account_id", "$AccountId" },
            { "institutionGroup_id", "$InstitutionGroupId" }
        },
        pipeline: lookupPipeline)
    .ToListAsync();

return accountWithLinkedEntities;

方案二:直接构建BsonDocument(与原查询完全对应)

如果需要完全复刻原MongoDB查询的结构,可以直接构建BsonDocument形式的聚合阶段:

var lookupStage = new BsonDocument("$lookup", new BsonDocument
{
    { "from", "LinkedEntities" },
    { "let", new BsonDocument
        {
            { "account_id", "$AccountId" },
            { "institutionGroup_id", "$InstitutionGroupId" }
        }
    },
    { "pipeline", new BsonArray
        {
            new BsonDocument("$match", new BsonDocument
                {
                    { "$expr", new BsonDocument("$and", new BsonArray
                        {
                            new BsonDocument("$eq", new BsonArray { "$InstitutionGroupId", "$$institutionGroup_id" }),
                            new BsonDocument("$eq", new BsonArray { "$AccountId", "$$account_id" })
                        })
                    }
                }),
            new BsonDocument("$project", new BsonDocument
                {
                    { "AccountId", 0 },
                    { "_id", 0 }
                })
        }
    },
    { "as", "AccountwithLinkedEntities" }
});

var accountWithLinkedEntities = await _mongoDbContext.Accounts.Aggregate()
    .AppendStage<Account>(lookupStage)
    .ToListAsync();

return accountWithLinkedEntities;

关键说明

  • 方案一利用强类型API保证类型安全,适合大多数业务场景
  • 方案二完全对应原MongoDB查询语句,适合复杂聚合逻辑的快速迁移

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:52:51