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

如何使用C#类聚合MongoDB中的多个集合

解决.NET 8 Blazor Server中MongoDB关联查询的低效问题

问题背景

在.NET 8 Blazor Server应用中使用MongoDB C# Driver,将Team、League、Player三个类分别存储在独立集合中——这些数据需独立更新且可被其他类复用,因此未采用嵌套文档的存储方式。当前通过TeamData类存储关联ID,但希望从数据库获取数据时直接得到完整的Team类实例。现有的循环逐个查询关联数据的方式冗长且低效,需借助AggregateAsync实现关联查询,同时尽量复用现有类结构,减少“魔法字符串”的使用。

解决方案

利用MongoDB聚合框架的$lookup操作在数据库层面完成关联查询,结合C# Driver的强类型API避免硬编码字段名,仅需一次网络请求即可获取完整的Team数据,彻底解决N+1查询的低效问题。

完整实现代码

public async Task<List<Team>> GetAllTeams()
{
    IMongoCollection<TeamData> teamCollection = Database.GetCollection<TeamData>("Teams");
    IMongoCollection<League> leagueCollection = Database.GetCollection<League>("Leagues");
    IMongoCollection<Player> playerCollection = Database.GetCollection<Player>("Players");

    var aggregatePipeline = teamCollection.Aggregate()
        // 关联League集合,强类型指定字段映射
        .Lookup(
            foreignCollection: leagueCollection,
            localField: teamData => teamData.LeagueId,
            foreignField: league => league.Id,
            @as: (TeamData td) => td.League)
        // 关联Player1
        .Lookup(
            foreignCollection: playerCollection,
            localField: teamData => teamData.Player1Id,
            foreignField: player => player.Id,
            @as: (TeamData td) => td.Player1)
        // 关联Player2
        .Lookup(
            foreignCollection: playerCollection,
            localField: teamData => teamData.Player2Id,
            foreignField: player => player.Id,
            @as: (TeamData td) => td.Player2)
        // 将聚合结果投影为Team实例,取关联数组的第一个元素(ID唯一,仅匹配一条)
        .Projection(teamData => new Team
        {
            Id = teamData.Id,
            Number = teamData.Number,
            League = teamData.League.FirstOrDefault(),
            Player1 = teamData.Player1.FirstOrDefault(),
            Player2 = teamData.Player2.FirstOrDefault()
        });

    return await aggregatePipeline.ToListAsync();
}

关键说明

  • 强类型关联:使用lambda表达式指定localField和foreignField,完全复用现有类结构,避免了硬编码字段名的“魔法字符串”,提升代码可维护性。
  • 数据库端关联:所有关联逻辑在MongoDB服务器执行,仅需一次网络请求,相比原循环查询的多次请求,性能大幅提升。
  • 数组处理:Lookup默认返回匹配文档的数组,由于ID是唯一索引,用FirstOrDefault()即可获取唯一匹配的关联对象,同时处理关联ID无效的空值场景。

可选优化

  • 可在聚合管道开头添加Match阶段,过滤掉关联ID无效的TeamData,减少不必要的关联操作。
  • 若需确保关联对象非空,可在投影阶段添加空值判断,或在数据库层面通过约束保证关联ID的有效性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 10:32:31