当前位置: 首页 > 面试题库 >

从MySQL结果和PHP for D3.js树创建分层JSON?

束志业
2023-03-14
问题内容

我正在尝试使用PHP从数据库结果中创建以下JSON(大大简化了…):

{
    "name": "Bob",
    "children": [{
            "name": "Ted",
            "children": [{
                "name": "Fred"
            }]
        },
        {
            "name": "Carol",
            "children": [{
                "name": "Harry"
            }]
        },
        {
            "name": "Alice",
            "children": [{
                "name": "Mary"
            }]
        }
    ]
}

数据库表:

Table 'level_1':

level_1_pk| level_1_name
-------------------------
 1 | Bob


Table 'level_2':

level_2_pk| level_2_name | level_1_fk
-------------------------
 1 | Ted                 | 1
 2 | Carol               | 1
 3 | Alice               | 1


Table 'level_3':

level_3_pk| level_3_name | level_2_fk
-------------------------
 1 | Fred                | 1
 2 | Harry               | 2
 3 | Mary                | 3

代码:

$query = "SELECT * 
FROM level_1
LEFT JOIN level_2
ON level_1.level_1_pk = level_2.level_1_fk";
$result = $connection->query($query);
 while ($row = mysqli_fetch_assoc($result)){
        $data[$row['level_1_name']] [] = array(
            "name" => $row['level_2_name']
            );
    }

echo json_encode($data);

产生:

{"Bob":[{"name":"Ted"},{"name":"Carol"},{"name":"Alice"}]}

问题:

如何获得下一个级别level_3,并按照上面定义的JSON的要求在JSON中包含文本“ children”和level_3子级?

我想在JSON中有更多子级的情况下,我将需要PHP进行递归。

的SQL


问题答案:

这看起来不像是分层数据的合理设计。考虑另一种方法,例如 邻接表

解决方案#1-MySQL 8 JSON支持:

在MySQL
8中,您可以使用JSON_ARRAYAGG()JSON_OBJECT()仅通过SQL获得JSON结果:

select json_object(
  'name', l1.level_1_name,
  'children', json_arrayagg(json_object('name', l2.level_2_name, 'children', l2.children))
) as json
from level_1 l1
left join (
  select l2.level_2_name
       , l2.level_1_fk
       , json_arrayagg(json_object('name', l3.level_3_name)) as children
  from level_2 l2
  left join level_3 l3 on l3.level_2_fk = l2.level_2_pk
  group by l2.level_2_pk
) l2 on l2.level_1_fk = l1.level_1_pk
group by level_1_pk

结果是:

{"name": "Bob", "children": [{"name": "Ted", "children": [{"name": "Fred"}]}, {"name": "Carol", "children": [{"name": "Harry"}]}, {"name": "Alice", "children": [{"name": "Mary"}]}]}

db-fiddle演示

格式:

{
  "name": "Bob",
  "children": [
    {
      "name": "Ted",
      "children": [
        {
          "name": "Fred"
        }
      ]
    },
    {
      "name": "Carol",
      "children": [
        {
          "name": "Harry"
        }
      ]
    },
    {
      "name": "Alice",
      "children": [
        {
          "name": "Mary"
        }
      ]
    }
  ]
}

解决方案2-使用GROUP_CONCAT()构造JSON:

如果名称中不包含引号,则可以使用GROUP_CONCAT()以下版本手动构建JSON字符串:

$query = <<<MySQL
    select concat('{',
      '"name": ', '"', l1.level_1_name, '", ',
      '"children": ', '[', group_concat(
        '{',
        '"name": ', '"', l2.level_2_name, '", ',
        '"children": ', '[', l2.children, ']',
        '}'
      separator ', '), ']'        
    '}') as json
    from level_1 l1
    left join (
      select l2.level_2_name
           , l2.level_1_fk
           , group_concat('{', '"name": ', '"',  l3.level_3_name, '"', '}') as children
      from level_2 l2
      left join level_3 l3 on l3.level_2_fk = l2.level_2_pk
      group by l2.level_2_pk
    ) l2 on l2.level_1_fk = l1.level_1_pk
    group by level_1_pk
MySQL;

结果将是相同的(请参阅demo)

解决方案#3-使用PHP对象构造嵌套结构:

您还可以编写一个更简单的SQL查询并在PHP中构造嵌套结构:

$result = $connection->query("
    select level_1_name as name, null as parent
    from level_1
    union all
    select l2.level_2_name as name, l1.level_1_name as parent
    from level_2 l2
    join level_1 l1 on l1.level_1_pk = l2.level_1_fk
    union all
    select l3.level_3_name as name, l2.level_2_name as parent
    from level_3 l3
    join level_2 l2 on l2.level_2_pk = l3.level_2_fk
");

结果是

name    | parent
----------------
Bob     | null
Ted     | Bob
Carol   | Bob
Alice   | Bob
Fred    | Ted
Harry   | Carol
Mary    | Alice

演示

注意:该名称在所有表中都应该是唯一的。但是,如果有可能重复,我不知道您会期待什么结果。

现在,将行另存为对象,并以名称索引:

$data = []
while ($row = $result->fetch_object()) {
    $data[$row->name] = $row;
}

$data 现在将包含

[
    'Bob'   => (object)['name' => 'Bob',   'parent' => NULL],
    'Ted'   => (object)['name' => 'Ted',   'parent' => 'Bob'],
    'Carol' => (object)['name' => 'Carol', 'parent' => 'Bob'],
    'Alice' => (object)['name' => 'Alice', 'parent' => 'Bob'],
    'Fred'  => (object)['name' => 'Fred',  'parent' => 'Ted'],
    'Harry' => (object)['name' => 'Harry', 'parent' => 'Carol'],
    'Mary'  => (object)['name' => 'Mary',  'parent' => 'Alice'],
]

现在,我们可以在单个循环中链接节点:

$roots = [];
foreach ($data as $row) {
    if ($row->parent === null) {
        $roots[] = $row;
    } else {
        $data[$row->parent]->children[] = $row;
    }
    unset($row->parent);
}

echo json_encode($roots[0], JSON_PRETTY_PRINT);

结果:

{
    "name": "Bob",
    "children": [
        {
            "name": "Ted",
            "children": [
                {
                    "name": "Fred"
                }
            ]
        },
        {
            "name": "Carol",
            "children": [
                {
                    "name": "Harry"
                }
            ]
        },
        {
            "name": "Alice",
            "children": [
                {
                    "name": "Mary"
                }
            ]
        }
    ]
}

演示

如果可能有多个根节点(中有多行level_1_name),请使用

json_encode($roots);


 类似资料:
  • 我有一个父子关系数据库。数据如下所示,但可以以任何方式呈现(字典、列表列表、JSON等)。 我需要的输出是一个层次化的JSON树,它将用d3呈现。数据中有离散的子树,我将附加到根节点。所以我需要递归地遍历链接,并建立树结构。我最多只能遍历所有人并附加他们的孩子,但我不知道如何进行高阶链接(例如,如何将有孩子的人附加到其他人的孩子)。这类似于这里的另一个问题,但我无法提前知道根节点,因此无法实现公认

  • 问题内容: 我有对象T的列表,它具有父属性,其中顶级对象的父属性为null。我想将所有对象放入TreeSet(或TreeMap)中。顶级对象将是所有没有父级的根对象(父级为null),并且它们的下级将是其子级。 像这样 所以我可以得到Ra并找到它的子代(Ca1,Ca2,Ca11,Ca12…。) 更新:很抱歉,可能不清楚,节点指向父节点,如果parent为null,则它们是根节点。问题是父母需要了解

  • 问题内容: 我有一个MySQL表,如下所示: 现在,我想有一个简单的MySQL查询,只需向其提供ID [例如说id=19],然后就应该获取其所有子ID [即结果应具有ID ‘20,21,22’]…。 孩子的等级未知;它可能会有所不同.... 我知道如何使用for循环…但是如何使用单个MySQL查询实现相同的目标? 问题答案: 对于MySQL 8+:使用递归with语法。 对于MySQL 5.x:使

  • 我有一个MySQL表,如下所示: 现在,我想有一个MySQL查询,我只需向它提供id(例如),然后我应该获得它的所有子id(即,结果应该有id'20、21、22']... 不知道孩子的等级;它可以变化.... 我知道如何使用循环来实现...但是如何使用单个MySQL查询实现相同的功能呢?

  • 本文向大家介绍MongoDB 中创建分层JSON,包括了MongoDB 中创建分层JSON的使用技巧和注意事项,需要的朋友参考一下 使用以下语法在MongoDB中创建分层JSON- 让我们创建一个包含文档的集合- 在find()方法的帮助下显示集合中的所有文档- 这将产生以下输出-

  • 我的REST控制器需要以下格式的请求输入,它成功地将其转换为包含映射和字符串作为参数的Java对象: 我从html表单中获取数据,如下所示: 基本上,这段代码可以归结为: 这会导致包含{key1=的映射 但是,我最终会得到以下字符串:'{"myMap":{},"String":"myString"}'。所以我可能必须做一些不同的事情来对地图进行字符串化,但是我尝试的都不起作用。 有人能帮我吗?