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

Nodejs环境下MongoDB实现餐馆、菜单、分组、商品多级关联查询

MongoDB实现查询菜单及其关联分组、选项方案

前置说明

你给出的返回结构是单个餐品菜单的嵌套关联数据,对应关联逻辑为:菜单关联多个附加选项分组,每个分组关联多个选项条目,我们用MongoDB的聚合管道$lookup操作实现关联嵌套查询,可和你原有MySQL返回结构完全对齐。

具体实现步骤

1. 确认集合关联字段映射

四个集合的关联字段和你原有结构保持一致即可:

  • menus集合:通过restaurant_id关联restaurants集合的主键,自身主键对应你原有结构的id字段
  • groups集合:通过menu_id关联menus集合的主键
  • items集合:通过group_id关联groups集合的主键

2. 原生MongoDB聚合查询语句

如果要查询id=20的单个菜单,完整聚合语句如下:

db.menus.aggregate([
  // 第一步:匹配目标菜单,用Mongo默认_id的话改匹配条件为{_id: ObjectId("xxx")}即可
  {
    $match: { id: 20 }
  },
  // 第二步:关联查询当前菜单对应的所有分组
  {
    $lookup: {
      from: "groups",
      localField: "id",
      foreignField: "menu_id",
      as: "group"
    }
  },
  // 第三步:嵌套关联每个分组对应的选项条目
  {
    $unwind: {
      path: "$group",
      preserveNullAndEmptyArrays: true // 保留没有分组的菜单,避免数据丢失
    }
  },
  {
    $lookup: {
      from: "items",
      localField: "group.id",
      foreignField: "group_id",
      as: "group.item"
    }
  },
  // 第四步:把拆分的分组重新合并为数组
  {
    $group: {
      _id: "$_id",
      id: { $first: "$id" },
      restaurant_id: { $first: "$restaurant_id" },
      name: { $first: "$name" },
      detail: { $first: "$detail" },
      regular_price: { $first: "$regular_price" },
      discount_price: { $first: "$discount_price" },
      category_id: { $first: "$category_id" },
      photo: { $first: "$photo" },
      status: { $first: "$status" },
      created_at: { $first: "$created_at" },
      updated_at: { $first: "$updated_at" },
      group: { $push: "$group" }
    }
  },
  // 可选:外层包data字段就加这一步
  {
    $project: {
      _id: 0,
      data: "$$ROOT"
    }
  }
])

3. Laravel下MongoDB扩展的实现方案

如果你在Laravel中使用jenssegers/laravel-mongodb扩展,可以直接定义模型关联,写法和你原有MySQL逻辑完全一致:
首先定义模型关联:

  • Menu模型:
class Menu extends Jenssegers\Mongodb\Eloquent\Model
{
    public function group()
    {
        return $this->hasMany(Group::class, 'menu_id', 'id');
    }
}
  • Group模型:
class Group extends Jenssegers\Mongodb\Eloquent\Model
{
    public function item()
    {
        return $this->hasMany(Item::class, 'group_id', 'id');
    }
}

查询时直接预加载关联即可:

$menu = Menu::with('group.item')->where('id', 20)->first();
// 外层包data直接返回 return response()->json(['data' => $menu]); 即可

注意事项

  • 如果你用MongoDB默认的_id作为主键,把上述关联字段的id替换为_id,查询时记得转ObjectId类型
  • 没有关联数据的分组会自动返回空数组,和你原有结构中的空item数组完全对齐
  • 如果需要同时返回餐馆的基础信息,在聚合匹配步骤之后再加一个关联restaurants的$lookup即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 23:36:02