如何将包含数组的 JSON 表迁移到 SQL?

Posted

技术标签:

【中文标题】如何将包含数组的 JSON 表迁移到 SQL?【英文标题】:How to migrate a JSON table that contains an array to SQL? 【发布时间】:2020-11-26 03:45:43 【问题描述】:

我是一名实习前端开发人员。从来没有真正喜欢过后端,所以我对 SQL 知之甚少。

但是,在我需要做后端的冒险时期之一,因为我也被分配了。好吧,我们有一个内部系统来跟踪我们正在重建的一些关于我们自己的数据。以前的系统使用 JSON 文件来存储其数据,格式如下:


  "id": 123,
  "userId": 522,
  "effortDate": "2020-06-05",
  "data": [
    
      "projectId": 14,
      "value": 7
    ,
    
      "projectId": 23,
      "value": 3
    
  ],
  "updatedAt": "2020-06-08T10:13:11-03:00",
  "createdAt": "2020-06-08T10:13:11-03:00"

我们正在转向基于 SQL 的数据库。所以,根据我对关系数据库工作原理的基本了解,

我已经建立了这个模型:

.

问题是:至少目前,我们为应用程序使用相同的前端,所以我需要以与当时只是 JSON 时相同的格式解析数据。而对于系统的基本运行,需要all从现在开始的数据,两张表,一直都需要。

我的第一个想法是将它们与两个不同的 SELECT 强制混合。我猜这不是很糟糕(也许是因为它有效),除了我们正在处理成千上万的条目,所以我担心事情可能会变慢。这是我用来解析它的代码:

public function getAllEfforts() 
  /* Get all data from `effort` */
  $effortQuery = "SELECT id, userId, effortDate, createdAt, updatedAt
                  FROM efforts;";

  $efforts = $this->pdo
    ->query($effortQuery)
    ->fetchAll(PDO::FETCH_ASSOC);

  /* Get all data from `effort_data` */
  $effortDataQuery = "SELECT id, effortId, projectId, value
                      FROM efforts_data;";

  $effortsData = $this->pdo
    ->query($effortDataQuery)
    ->fetchAll(PDO::FETCH_ASSOC);

  /* Since, `effort` doesn't have a data field, let's define the array wished here */
  foreach($efforts as &$effortsUnity) 
    $effortsUnity['data'] = [];
  

  /* Push the stuff from `effort_data` to the just created data array */
  foreach($effortsData as &$effortDataUnity) 
    $effortIndex = ($effortDataUnity['effortId'] - 1);

    unset($effortDataUnity['id']);
    unset($effortDataUnity['effortId']);

    array_push(
      $efforts[$effortIndex]['data'],
      $effortDataUnity
    );
  
  
  return $efforts;

我的问题是:有没有办法只使用 SQL 来做到这一点? 或者除了使用 MongoDB 或其他目前无法实现的基于 JSON 的数据库之外的任何其他最佳方式。

对不起,如果我不够清楚,这是我在这里的第一个问题,我愿意澄清任何问题。

非常感谢。

【问题讨论】:

【参考方案1】:

我的问题是:有没有办法只使用 SQL 来做到这一点?

是的,这就是你在efforts idefforts_data effortId之间建立关系的原因:

SELECT e.id, e.userId, e.effortDate, e.createdAt, e.updatedAt,
       ed.id, ed.effortId, ed.projectId, ed.value
FROM efforts AS e, efforts_data AS ed
WHERE e.id = ed.effortId

【讨论】:

逗号分隔的表很久不用了,因为这基本上是一个crossjoin,加入后过滤,进行prper join 我也不喜欢我所谓的“WHERE-clause joins”。【参考方案2】:

您可以利用 mysql 的 JSON 函数直接从数据库生成嵌套的 JSON 结构。

考虑:

SELECT 
    id, 
    userId, 
    effortDate, 
    createdAt, 
    updatedAt,
    (
        SELECT JSON_ARRAYAGG(
            JSON_OBJECT('projectId', ed.projectId, 'value', ed.value)
        )
        FROM efforts_data ed
        WHERE ed.effortId = e.id
    ) AS data
FROM efforts

这会为每个efforts 提供一行,其中有一列名为data,其中包含由来自表efforts_data 的对象数组组成的JSON 有效负载。

如果您愿意,您可以向前迈出一步,将每一行填充到一个对象中:

SELECT JSON_OBJECT(
    'id', id, 
    'userId', userId, 
    'effortDate', effortDate, 
    'createdAt', createdAt, 
    'updatedAt', updatedAt,
    'data', (
        SELECT JSON_ARRAYAGG(
            JSON_OBJECT('projectId', ed.projectId, 'value', ed.value)
        )
        FROM efforts_data ed
        WHERE ed.effortId = e.id
    )
) res
FROM efforts

在 MySQL JSON_ARRAYAGG() 尚不可用,一种解决方法是GROUP_CONCAT() 和字符串连接。基本上你会重写这个:

SELECT JSON_ARRAYAGG(
           JSON_OBJECT('projectId', ed.projectId, 'value', ed.value)
)
FROM efforts_data ed
WHERE ed.effortId = e.id

作为:

SELECT CONCAT(
    '[', 
    GROUP_CONCAT(JSON_OBJECT('projectId', ed.projectId, 'value', ed.value)),
    ']'
)
FROM efforts_data ed
WHERE ed.effortId = e.id

【讨论】:

非常感谢。我什至不知道 MySQL 有内置的 JSON 功能。我正在寻找那些。不过,我收到了 PDO 异常(“#1305 - FUNCTION sistema_do_peru.JSON_ARRAYAGG 不存在”)。也许它可能只是我的 MySQL 版本,我会尝试自己修复它。谢谢你给我指路! @GabrielAndrade:你运行的是哪个版本的 MySQL? JSON_ARRAYAGG() 在 5.7.22 中引入。 select version() 可以告诉你当前的版本。 JSON_ARRAYAGG 在 MariaDB 10.5.0 中被添加。 see documentation @GabrielAndrade 顺便说一句,您可以单独安装 MySQL per se 并运行它而不是从 XAMPP 运行 MariaDB,这就是我现在的工作方式,因为 MariaDB 还有其他陷阱。跨度> @GabrielAndrade:我为您的 MariaDB 版本添加了解决方法。

以上是关于如何将包含数组的 JSON 表迁移到 SQL?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Access 查询迁移到 SQL 视图?

如何将数据库从 SQL 服务器迁移到 SQL Azure,其中包含带有数据的 asp.net 成员资格提供程序

如何在 Rails 迁移中将列(包含内容)移动到另一个表?

怎么将数据库从Oracle迁移到SQL Server,或从Oracle迁移到MySQL

使用扩展的JSON将SQL Server数据迁移到MongoDB

从数组冒泡排序迁移到链表冒泡排序