在从mysql读取时,从json数组的每个json对象中过滤掉不需要的字段

doinxwow  于 2021-06-25  发布在  Mysql
关注(0)|答案(1)|浏览(562)

假设我在mysql数据库中有一个表,其中有一列是json类型的,我在其中一个记录中保存了以下json

  1. {
  2. "about": "person",
  3. "info": [
  4. {
  5. "fName": "John",
  6. "lName": "Booker",
  7. "sex": "male",
  8. "age": 20
  9. },
  10. {
  11. "fName": "Laurie",
  12. "lName": "Sparks",
  13. "sex": "female"
  14. },
  15. {
  16. "fName": "Adam",
  17. "lName": "Bate",
  18. "age": 26
  19. }
  20. ]
  21. }

有没有什么方法可以让我提取以下信息?

  1. [
  2. {
  3. "sex": "male",
  4. "age": 20
  5. },
  6. {
  7. "sex": "female"
  8. },
  9. {
  10. "age": 26
  11. }
  12. ]
  13. ``` `$.info[*]` 给我这个

[
{
"fName": "John",
"lName": "Booker",
"sex": "male",
"age": 20
},
{
"fName": "Laurie",
"lName": "Sparks",
"sex": "female"
},
{
"fName": "Adam",
"lName": "Bate",
"age": 26
}
]

  1. 以及 `$.info[*].sex` 以及 `$.info[*].age` 分别给我这些

["male", "female"]

[20, 26]

  1. 我想我也可以通过以下方法来工作,但我不知道怎么做

["male", "female", null]

[20, null, 26]

  1. 原始问题背景
  2. 我目前使用的应用程序在mysql数据库中保存了一些json内容。此json可能具有某些字段,这些字段的值是巨大的base64编码图像。有时我的客户并不关心获取这些base64编码的图像。因此,为了提高性能,减少从数据库传输到应用程序的数据量,避免在应用程序端进行处理,我希望检索json数组中每个json对象元素中的所有字段,这些字段不涉及存储这些巨大的图像信息。
  3. 我目前的实现是从数据库中获取整个json对象,然后使用json模式(受此项目启发)获取必要的字段,但其性能没有达到预期的sla。我真的很想在mysql服务器上做尽可能多的数据处理,然后再把它放到我的应用程序中,如果需要的话,再进一步处理它。
  4. 附言:我明白;不像aws s3这样的东西;数据库可能不是存储大型json文档的最佳选择。但是我想利用数据库的批读取功能,这在其他nosql数据存储中可能是不可用的
r7s23pms

r7s23pms1#

更新
从MySQL8.0开始,使用 JSON_TABLE 提取 sex 以及 age 每个对象的值:

  1. SELECT JSON_ARRAYAGG(JSON_OBJECT('sex', j.sex, 'age', j.age)) AS filtered
  2. FROM test t
  3. JOIN JSON_TABLE(t.j,
  4. '$.info[*]'
  5. COLUMNS (
  6. sex VARCHAR(6) PATH '$.sex',
  7. age INT PATH '$.age'
  8. )
  9. ) j

假设一列 j 有了您的原始数据,可以:

  1. [
  2. {"age": 20, "sex": "male"},
  3. {"age": null, "sex": "female"},
  4. {"age": 26, "sex": null}
  5. ]

如果你想避开 null 值,可以使用 CASE 表达式来检查它们并更改基于该表达式创建的对象:

  1. SELECT JSON_ARRAYAGG(
  2. CASE WHEN j.sex IS NULL THEN JSON_OBJECT('age', j.age)
  3. WHEN j.age IS NULL THEN JSON_OBJECT('sex', j.sex)
  4. ELSE JSON_OBJECT('sex', j.sex, 'age', j.age)
  5. END
  6. ) AS filtered
  7. FROM test t
  8. JOIN JSON_TABLE(t.j,
  9. '$.info[*]'
  10. COLUMNS (
  11. sex VARCHAR(6) PATH '$.sex',
  12. age INT PATH '$.age'
  13. )
  14. ) j
  15. WHERE j.sex IS NOT NULL OR j.age IS NOT NULL

输出:

  1. [
  2. {"age": 20, "sex": "male"},
  3. {"sex": "female"},
  4. {"age": 26}
  5. ]

dbfiddle上的(两个查询的)演示
原始答案
不幸的是,我不认为这可以直接用内置的mysql json函数(如果 JSON_REMOVE 会接受通配符路径(可能是)。但是,它可以通过以下存储函数实现:

  1. CREATE FUNCTION filter_json(j JSON) RETURNS JSON
  2. BEGIN
  3. DECLARE n INT DEFAULT 0;
  4. DECLARE info, sex, age, data JSON;
  5. SET info = JSON_ARRAY();
  6. WHILE JSON_CONTAINS_PATH(j, 'one', CONCAT('$.info[', n, ']')) DO
  7. SET data = JSON_OBJECT();
  8. SET sex = JSON_EXTRACT(j, CONCAT('$.info[', n, '].sex'));
  9. IF sex IS NOT NULL THEN
  10. SET data = JSON_INSERT(data, '$.sex', sex);
  11. END IF;
  12. SET age = JSON_EXTRACT(j, CONCAT('$.info[', n, '].age'));
  13. IF age IS NOT NULL THEN
  14. SET data = JSON_INSERT(data, '$.age', age);
  15. END IF;
  16. SET info = JSON_ARRAY_APPEND(info, '$', data);
  17. SET n = n + 1;
  18. END WHILE;
  19. RETURN info;
  20. END;

请注意,根据您的环境,您可能需要更改分隔符(例如,使用 DELIMITER // )在进入函数之前。
对于此查询:

  1. SELECT filter_json('{ "about": "person", "info": [ { "fName": "John", "lName": "Booker", "sex": "male", "age": 20 }, { "fName": "Laurie", "lName": "Sparks", "sex": "female" }, { "fName": "Adam", "lName": "Bate", "age": 26 } ] }')

您将获得所需的输出:

  1. [
  2. {"age": 20, "sex": "male"},
  3. {"sex": "female"},
  4. {"age": 26}
  5. ]

在dbfiddle上演示

展开查看全部

相关问题