我正在MySql(实际上是MariaDb)数据库中存储这样的对象/数据结构:
{
idx: 7,
a: "content A",
b: "content B",
c: ["entry c1", "entry c2", "entry c3"]
}
要存储它,我使用了2个表,非常类似于此答案中描述的方法:https://stackoverflow.com/a/17371729/3958875
即
表1:
+-----+---+---+
| idx | a | b |
+-----+---+---+
表2:
+------------+-------+
| owning_obj | entry |
+------------+-------+
然后创建一个将它们连接在一起的视图,所以我得到了:
+-----+------------+------------+-----------+
| idx | a | b | c |
+-----+------------+------------+-----------+
| 7 | content A1 | content B1 | entry c11 |
| 7 | content A1 | content B1 | entry c21 |
| 7 | content A1 | content B1 | entry c31 |
| 8 | content A2 | content B2 | entry c12 |
| 8 | content A2 | content B2 | entry c22 |
| 8 | content A2 | content B2 | entry c32 |
+-----+------------+------------+-----------+
我的问题是将其恢复为对象形式的最佳方法是什么? (例如,我想要idx在5到20之间的所有条目上面指定的对象类型的数组)
我可以想到2种方法,但这两种方法似乎都不是很有效。
首先,我们可以将整个表发送回服务器,它可以创建一个以键为主键或其他唯一索引的哈希图,并收集不同的c列,并以此方式进行重建,但是这意味着它必须发送大量重复数据,并花费更多的内存和处理时间才能在服务器上进行重建。如果我们有多个数组,或者数组中有数组,这种方法的缩放也不会很令人满意。
第二种方法是执行多个查询,过滤Table 1
并获取所需的idx列表,然后针对每个idx发送针对Table 2
的查询,其中owning_obj
=当前的IDX。这将意味着发送更多的查询。
这两个选项似乎都不是很好,所以我想知道是否有更好的方法。目前,我认为这可以利用JSON_OBJECT()
,但我不确定如何使用。
这似乎是一种常见情况,但我似乎找不到确切的措词来寻找答案。
PS:与MySql / MariaDb接口的服务器是用Rust编写的,尽管在此问题中这并不相关
答案 0 :(得分:0)
您可以使用GROUP_CONCAT
将所有c
的值组合成一个逗号分隔的字符串。
SELECT t1.idx, t1.a, t1.b, GROUP_CONCAT(entry) AS c
FROM table1 AS t1
LEFT JOIN table2 AS t2 ON t1.idx = t2.owning_obj
GROUP BY t1.idx
然后在PHP中爆炸字符串:
$result_array = [];
while ($row = $result->fetch_assoc()) {
$row['c'] = explode(',', $row['c']);
$result_array[] = $row;
}
但是,如果输入项可能很长,请确保增加group_concat_max_len
。
如果您使用的是MySQL 8.0,则也可以使用JSON_ARRAYAGG()
。这将创建一个entry
值的JSON数组,您可以使用json_decode()
将其转换为PHP数组。这样比较安全,因为如果任何值包含逗号,GROUP_CONCAT()
都会弄乱。您可以更改分隔符,但需要一个永远不会有任何值的分隔符。不幸的是,这不在MariaDB中。