首页 > 解决方案 > 如果存在另一个属性,则删除 MySQL JSON 属性

问题描述

在我的数据库中,有许多产品行带有名为“代码”的 JSON 列,我想:

{
  ...
  "access": {
    ...
  },
  "layouts": [
    {
      ...
      "grid": [
        {
          ...
          "default": "...",
          ...
        },
        {
          ...
        },
        {
          ...
        },
        {
          ...
        },
        {
          ...
          "default": "...",
          "mask": "...",
          ...
        }
      ]
    }
  ],
  ...
}

我该怎么做?

标签: mysqljson

解决方案


很多人会说:在 MySQL 之外的某种脚本中执行此操作。我会同意,但其中的乐趣在哪里。

但是,您将需要一个存储的例程才能执行您想要的操作。问题是JSON_REMOVE不接受通配符。

根据您的要求,我提出了以下例程(请测试并适应!):

DROP PROCEDURE IF EXISTS remove_defaults;
DELIMITER $$
CREATE PROCEDURE remove_defaults()
BEGIN
    DECLARE done BOOL;
    DECLARE i INT;
    DECLARE vID INT;
    DECLARE vGrid JSON;
    DECLARE vDoc JSON;

    DECLARE cur CURSOR FOR SELECT id, doc FROM t1;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur;

    SET done = FALSE;
    REPEAT
        FETCH cur INTO vID, vDoc;
        -- get the 'grid' array from the JSON document
        SET vGrid = JSON_EXTRACT(vDoc, '$.grid');
        SET i = 0;
        WHILE i < JSON_LENGTH(vGrid) DO
            -- check if this grid entry has 'mask' attribute
            IF JSON_CONTAINS_PATH(vGrid, 'one', CONCAT('$[',i,'].mask')) = 1 THEN
                -- it does have 'mask', so we remove the default
                SET vGrid = JSON_REMOVE(vGrid, CONCAT('$[',i,'].default'));
            END IF;
            SET i = i + 1;
        END WHILE;
        -- update the original JSON document with the new 'grid'
        UPDATE t1 SET doc = JSON_REPLACE(doc, '$.grid', vGrid) WHERE id = vID;
    UNTIL done END REPEAT;

    CLOSE cur;
END $$

这使用简化表:

CREATE TABLE t1
(
    id  INT AUTO_INCREMENT PRIMARY KEY,
    doc JSON
);

使用如下测试数据:

+----+-----------------------------------------------------------+
| id | doc                                                       |
+----+-----------------------------------------------------------+
|  1 | {"grid": [{"mask": "foo", "default": 1}, {"default": 2}]} |
|  2 | {"grid": [{"mask": "bar"}, {"default": 3}]}               |
+----+-----------------------------------------------------------+

这将导致:

+----+---------------------------------------------+
| id | doc                                         |
+----+---------------------------------------------+
|  1 | {"grid": [{"mask": "foo"}, {"default": 2}]} |
|  2 | {"grid": [{"mask": "bar"}, {"default": 3}]} |
+----+---------------------------------------------+

但是,如果您对存储例程感到不舒服,或者您无法将其添加到您的架构中,您可能确实在 MySQL 之外执行此操作。


推荐阅读