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

C# MongoDB关联集合查询带列表属性对象的实现方案

报错原因

原有代码无法正常执行有两个核心问题:

  1. MongoDB C# 驱动的LINQ翻译器不支持在$project投影阶段直接使用new List<T>()的集合初始化语法,无法将该段C#代码翻译成MongoDB可识别的聚合管道语句,因此抛出对应异常。
  2. 普通join是内连接逻辑,会返回分类与菜单项一一对应的笛卡尔积结果,即一个分类下有N个菜单项就会返回N条重复分类数据的记录,完全无法实现「一个分类嵌套对应多个菜单项」的一对多结构需求。
推荐实现方案

优先使用MongoDB原生$lookup聚合算子实现关联,兼容性最好,不会出现LINQ翻译兼容问题,代码如下:

var categoryCollection = database.GetCollection<CategoryDomainModel>("Categories");
var menuCollection = database.GetCollection<MenuItemDomainModel>("Menus");

// 1. 构造过滤条件:筛选指定餐厅的分类
var categoryFilter = Builders<CategoryDomainModel>.Filter.Eq(c => c.RestaurantID, restaurantID);

// 2. 构建聚合管道
var categoriesAndMenus = categoryCollection.Aggregate()
    .Match(categoryFilter)
    // 关联Menus集合:本地关联键为分类_id,外键为菜单项的CategoryID,关联结果赋值给Menus字段
    .Lookup<CategoryDomainModel, MenuItemDomainModel, CategoryAndMenusDomainModel>(
        foreignCollection: menuCollection,
        localField: c => c._id,
        foreignField: m => m.CategoryID,
        @as: res => res.Menus
    )
    // 补全分类本身的字段映射
    .Project(res => new CategoryAndMenusDomainModel
    {
        _id = res._id,
        RestaurantID = res.RestaurantID,
        CategoryName = res.CategoryName,
        Status = res.Status,
        Menus = res.Menus
    })
    .ToList();

如果偏好LINQ语法,可以使用GroupJoin实现,注意不要手动初始化List,直接将分组结果转为列表即可,该写法在2.18及以上版本的MongoDB C#驱动中可正常翻译:

var categoriesAndMenus = (from category in categoryCollection.AsQueryable()
                          where category.RestaurantID == restaurantID
                          join menuItem in menuCollection.AsQueryable()
                              on category._id equals menuItem.CategoryID into menuGroups
                          select new CategoryAndMenusDomainModel
                          {
                              _id = category._id,
                              RestaurantID = category.RestaurantID,
                              CategoryName = category.CategoryName,
                              Status = category.Status,
                              Menus = menuGroups.ToList()
                          }).ToList();
补充说明
  • 如果需要对关联出来的菜单项做过滤(比如仅查询上架状态的菜品),可以使用带管道参数的Lookup重载,在关联阶段直接完成菜单项筛选,性能更优。
  • 上述两种写法最终生成的MongoDB聚合管道逻辑一致,返回结果完全符合CategoryAndMenusDomainModel的结构要求,不会出现分类重复、菜单项缺失的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:45:35