如何使用mysqli和PHP按类别分组获取关联食谱数据?
解决分类分组的JSON格式问题
看起来你遇到的核心问题是:当前的JOIN查询会返回每条产品对应一条记录,直接转JSON就会生成重复的分类条目。我们可以通过两种常用方式实现按类别分组的目标格式,下面分别说明:
方法一:PHP端手动分组查询结果(推荐,易维护)
这种方式先获取所有关联数据,再通过PHP遍历将同一分类的产品聚合到一起,逻辑清晰且容易调整:
步骤1:执行查询并获取结果
保留你的JOIN查询(可以精简下字段只保留需要的内容):
// 调整查询,只获取必要字段 $query = "SELECT c.id AS category_id, c.category_name, p.id AS recipe_id, p.recipe_name FROM " . $this->table_name . " p LEFT JOIN categories c ON p.category_id = c.id"; // 执行查询(这里假设你的数据库连接是$this->db,根据实际情况调整) $result = $this->db->query($query); $rawData = $result->fetch_all(MYSQLI_ASSOC);
步骤2:遍历结果进行分组
初始化目标结构,然后把同一分类的产品归到对应的recipes数组中:
// 初始化最终要输出的JSON结构 $finalResponse = [ "data" => [ "menu" => [] ], "status" => "1", "message" => "" ]; // 用分类ID作为临时键,避免重复创建分类条目 $categoryMap = []; foreach ($rawData as $item) { $catId = $item['category_id']; // 如果该分类还未加入临时映射,先创建分类基础信息 if (!isset($categoryMap[$catId])) { $categoryMap[$catId] = [ "id" => md5($catId), // 对应你示例中的哈希ID,可根据需求替换生成方式 "category_name" => $item['category_name'], "recipes" => [] ]; } // 将当前产品添加到对应分类的recipes数组 $categoryMap[$catId]['recipes'][] = [ "id" => $item['recipe_id'], "recipe_name" => $item['recipe_name'] ]; } // 把分类映射转成索引数组,放入menu中 $finalResponse['data']['menu'] = array_values($categoryMap); // 输出格式化后的JSON echo json_encode($finalResponse, JSON_PRETTY_PRINT);
方法二:SQL结合GROUP_CONCAT实现分组
这种方式在SQL层面将每个分类下的产品合并为JSON字符串,再在PHP中解析:
步骤1:修改查询语句
利用MySQL的JSON_OBJECT和GROUP_CONCAT函数聚合产品数据:
SELECT c.id AS category_id, c.category_name, GROUP_CONCAT( JSON_OBJECT( 'id', p.id, 'recipe_name', p.recipe_name ) SEPARATOR ',' ) AS recipes_json FROM products p LEFT JOIN categories c ON p.category_id = c.id GROUP BY c.id, c.category_name;
步骤2:PHP解析结果并生成目标JSON
$query = "SELECT c.id AS category_id, c.category_name, GROUP_CONCAT( JSON_OBJECT( 'id', p.id, 'recipe_name', p.recipe_name ) SEPARATOR ',' ) AS recipes_json FROM products p LEFT JOIN categories c ON p.category_id = c.id GROUP BY c.id, c.category_name"; $result = $this->db->query($query); $rawData = $result->fetch_all(MYSQLI_ASSOC); $finalResponse = [ "data" => [ "menu" => [] ], "status" => "1", "message" => "" ]; foreach ($rawData as $item) { // 将拼接的JSON字符串转为数组,处理空值情况 $recipes = !empty($item['recipes_json']) ? json_decode('[' . $item['recipes_json'] . ']', true) : []; $finalResponse['data']['menu'][] = [ "id" => md5($item['category_id']), "category_name" => $item['category_name'], "recipes" => $recipes ]; } echo json_encode($finalResponse, JSON_PRETTY_PRINT);
注意事项
- 你的
categories表用utf8编码,products表用latin1,建议统一编码(比如都改成utf8mb4),避免出现乱码问题。 - 使用
GROUP_CONCAT时,默认有长度限制(默认1024字节),如果产品数量较多,需要先执行SET group_concat_max_len = 102400;调整长度。
内容的提问来源于stack exchange,提问作者Chitra Nandpal
相关产品推荐
相关产品推荐

