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
相关产品推荐
相关产品推荐

