【问题标题】:MariaDB JSON remove key and its valuesMariaDB JSON 删除键及其值
【发布时间】:2020-12-13 16:03:43
【问题描述】:

我有一个类似的TABLBE

CREATE TABLE `saved_links` (
 `link_entry_id` bigint(20) NOT NULL AUTO_INCREMENT,
 `link_id` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
 `user_data_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`link_entry_id`),
 UNIQUE KEY `link_id` (`link_id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='saved Links'

并插入

INSERT INTO `saved_links`(`link_id`, `user_data_json` ) 
VALUES ( 
        'AABBCC',  
        '[{
            "mama@gmail_DOT_com": {"u_email": "mama@gmail_DOT_com", "private": "no"}}, 
          {
           "papa@gmail_DOT_com": {"u_email": "papa@gmail_DOT_com", "private": "no"}},
          {
           "daughter@gmail_DOT_com": {"u_email": "daughter@gmail_DOT_com", "private": "no"}},
          {
           "son@gmail_DOT_com": {"u_email": "son@gmail_DOT_com", "private": "no"}
        }]'  
    ), ( 
        'DDEEFF',  
            '[{
               "mama@gmail_DOT_com": {"u_email": "mama@gmail_DOT_com", "private": "no"}}, 
              {
               "papa@gmail_DOT_com": {"u_email": "papa@gmail_DOT_com", "private": "no"}} 
               
               ]'  
    ) ;

选择*

---------------------------------------------------
`link_id` | `user_data_json` 
----------------------------------------------------
`AABBCC` | [{
         |         "mama@gmail_DOT_com": {"u_email": "mama@gmail_DOT_com", "private": "no"}}, 
         |         {
         |          "papa@gmail_DOT_com": {"u_email": "papa@gmail_DOT_com", "private": "no"}},
         |         {
         |          "daughter@gmail_DOT_com": {"u_email": "daughter@gmail_DOT_com", "private": "no"}},
         |         {
         |          "son@gmail_DOT_com": {"u_email": "son@gmail_DOT_com", "private": "no"}}]
---------------------------------------------------------------------------------------------  
`DDEEFF` | [{
         |         "mama@gmail_DOT_com": {"u_email": "mama@gmail_DOT_com", "private": "no"}}, 
         |         {
         |          "papa@gmail_DOT_com": {"u_email": "papa@gmail_DOT_com", "private": "no"}}
         |         ]
---------------------------------------------------------------------------------------------    

     

我想从AABBCC 中删除"papa@gmail_DOT_com" 和他所有的values

我尝试过(我使用的是 10.4.15-MariaDB)

    UPDATE `saved_links` 
      SET `user_data_json` = IFNULL( 
        JSON_REMOVE( `user_data_json`,  JSON_UNQUOTE( 
            REPLACE( JSON_SEARCH(
                `user_data_json`, 'all', 'papa@gmail_DOT_com', NULL, '$**.papa@gmail_DOT_com'), '.u_email', '' ) ) ), `user_data_json` )
 where `link_id` = 'AABBCC'  

返回

 ---------------------------------------------------
    `link_id` | `user_data_json` 
    ----------------------------------------------------
    `AABBCC` | [{
             |         "mama@gmail_DOT_com": {"u_email": "mama@gmail_DOT_com", "private": "no"}}, 
             |         {}, //-> Notice these empty braces that are left behind.
             |         {
             |          "daughter@gmail_DOT_com": {"u_email": "daughter@gmail_DOT_com", "private": "no"}},
             |         {
             |          "son@gmail_DOT_com": {"u_email": "son@gmail_DOT_com", "private": "no"}}]

有没有办法避免删除后出现空的{}

UPDATE01- 如果您尝试:

UPDATE `saved_links` SET 
`user_data_json` = 
      JSON_REMOVE(`user_data_json`, '$.papa@gmail_DOT_com') 
 WHERE  `link_id`= 'AABBCC'

这会删除user_data_json WHERE link_id= 'AABBCC' 列中的所有数据`

谢谢

【问题讨论】:

  • 使用JSON_REMOVE ?
  • 已经用过...看看我在帖子中尝试了什么
  • 我编辑了标签,因为您使用的是 MariaDB,而不是 MySQL。这两个产品对 JSON 数据有不同的实现。它们不应被视为同一个数据库产品。
  • @BillKarwin 谢谢。虽然我仍然卡住了。如果您有任何想法,请告诉我

标签: mariadb key mysql-json mariadb-10.4


【解决方案1】:

我在这个谜题上玩了一段时间,并想出了另一种方法。 您可以使用 json_search(加上其他功能)最终使用 json_remove。 一旦您创建了一个 json 数组,我们必须考虑您的设计者决定按原样上传数据。 所以,这是我的代码:

UPDATE saved_links sl 
SET user_data_json = 
JSON_REMOVE(user_data_json, 
    SUBSTRING_INDEX( 
        JSON_UNQUOTE( 
            JSON_SEARCH(sl.user_data_json,'one','papa@gmail_DOT_com') 
        )
    ,'.', 1) 
)
WHERE link_id='AABBCC'
  1. json_search(sl.user_data_json,'one','papa@gmail_DOT_com')

    • 返回"$[1].papa@gmail_DOT_com.u_email"
  2. JSON_UNQUOTE

    • 返回$[1].papa@gmail_DOT_com.u_email
  3. SUBSTRING_INDEX(@JSON,'.',1)

    • 返回$[1]
  4. 最后,您将使用最后一个返回作为 JSON_REMOVE 路径。

我不知道您的 JSON 密钥是否始终与 u_email 相同,但如果是真的,那么您可以使用它。

【讨论】:

    【解决方案2】:

    select json_remove(user_data_json,'$[1]') from saved_links where link_entry_id=19;

    将返回:

    [{"mama@gmail_DOT_com": {"private": "no", "u_email": "mama@gmail_DOT_com"}},
     {"daughter@gmail_DOT_com": {"private": "no", "u_email": "daughter@gmail_DOT_com"}},
     {"son@gmail_DOT_com": {"private": "no", "u_email": "son@gmail_DOT_com"}}]
    

    我并没有真正使用 JSON,而是从这里的第二个示例中获得灵感:https://mariadb.com/kb/en/json_remove/

    编辑:

    您可以对此进行优化:

    with recursive abc as (
      Select 0 as i 
      union all 
      select i+1 from abc where i<2) 
    select link_entry_id, link_id,i, json_keys(user_data_json,concat('$[',i,']')) 
    from saved_links,abc;
    

    输出:

    +---------------+---------+------+----------------------------------------------+
    | link_entry_id | link_id | i    | json_keys(user_data_json,concat('$[',i,']')) |
    +---------------+---------+------+----------------------------------------------+
    |            19 | AABBCC  |    0 | ["mama@gmail_DOT_com"]                       |
    |            20 | DDEEFF  |    0 | ["mama@gmail_DOT_com"]                       |
    |            19 | AABBCC  |    1 | ["papa@gmail_DOT_com"]                       |
    |            20 | DDEEFF  |    1 | ["papa@gmail_DOT_com"]                       |
    |            19 | AABBCC  |    2 | ["daughter@gmail_DOT_com"]                   |
    |            20 | DDEEFF  |    2 | NULL                                         |
    +---------------+---------+------+----------------------------------------------+
    

    有了这个,您可以将"papa@gm...."“转换”为1

    编辑2: 结合来自 Mariadb 或来自 MySQL 的不同 JSON 函数可以做很多事情:

    SELECT 
       j.person,
       JSON_KEYS(j.person), 
       JSON_EXTRACT(JSON_KEYS(j.person),'$[0]'), 
       JSON_UNQUOTE(JSON_EXTRACT(JSON_KEYS(j.person),'$[0]')),
       JSON_VALUE(JSON_KEYS(j.person),'$[0]')
    FROM 
       JSON_TABLE('[{
                "mama@gmail_DOT_com": {"u_email": "mama@gmail_DOT_com", "private": "no"}}, 
              {
               "papa@gmail_DOT_com": {"u_email": "papa@gmail_DOT_com", "private": "no"}},
              {
               "daughter@gmail_DOT_com": {"u_email": "daughter@gmail_DOT_com", "private": "no"}},
              {
               "son@gmail_DOT_com": {"u_email": "son@gmail_DOT_com", "private": "no"}
            }]', 
                      '$[*]' COLUMNS(person JSON PATH '$[0]')) j
                      
    

    输出(请向右滚动,最后一列比第一列更有趣?):

    + ----------- + ------------------------ + --------------------------------------------- + ----------------------------------------------------------- + ------------------------------------------- +
    | person      | JSON_KEYS(j.person)      | JSON_EXTRACT(JSON_KEYS(j.person),'$[0]')      | JSON_UNQUOTE(JSON_EXTRACT(JSON_KEYS(j.person),'$[0]'))      | JSON_VALUE(JSON_KEYS(j.person),'$[0]')      |
    + ----------- + ------------------------ + --------------------------------------------- + ----------------------------------------------------------- + ------------------------------------------- +
    | {"mama@gmail_DOT_com": {"private": "no", "u_email": "mama@gmail_DOT_com"}} | ["mama@gmail_DOT_com"]   | "mama@gmail_DOT_com"                          | mama@gmail_DOT_com                                          | mama@gmail_DOT_com                          |
    | {"papa@gmail_DOT_com": {"private": "no", "u_email": "papa@gmail_DOT_com"}} | ["papa@gmail_DOT_com"]   | "papa@gmail_DOT_com"                          | papa@gmail_DOT_com                                          | papa@gmail_DOT_com                          |
    | {"daughter@gmail_DOT_com": {"private": "no", "u_email": "daughter@gmail_DOT_com"}} | ["daughter@gmail_DOT_com"] | "daughter@gmail_DOT_com"                      | daughter@gmail_DOT_com                                      | daughter@gmail_DOT_com                      |
    | {"son@gmail_DOT_com": {"private": "no", "u_email": "son@gmail_DOT_com"}} | ["son@gmail_DOT_com"]    | "son@gmail_DOT_com"                           | son@gmail_DOT_com                                           | son@gmail_DOT_com                           |
    + ----------- + ------------------------ + --------------------------------------------- + ----------------------------------------------------------- + ------------------------------------------- +
    

    编辑(2020-12-26): 我确实看过 mariadb,下面是在版本 10.5.8 上测试的。

    select json_extract(json_array(user_data_json,"papa@gmail_DOT_com"), '$[1]') from saved_links;
    +-----------------------------------------------------------------------+
    | json_extract(json_array(user_data_json,"papa@gmail_DOT_com"), '$[1]') |
    +-----------------------------------------------------------------------+
    | "papa@gmail_DOT_com"                                                  |
    | "papa@gmail_DOT_com"                                                  |
    +-----------------------------------------------------------------------+
    

    但不希望使用$[1],因此必须确定1 的正确值:

    WITH RECURSIVE data AS (
      SELECT 
        link_entry_id, 
        link_id, 
        0 as I, 
        JSON_KEYS(user_data_json, '$[0]') jk
      FROM saved_links
      UNION ALL
      SELECT 
        sl.link_entry_id, 
        sl.link_id, 
        I+1, 
        JSON_KEYS(user_data_json, CONCAT('$[',i+1,']')) 
      FROM saved_links sl, (select max(i) as I from data) x
      WHERE JSON_KEYS(user_data_json, CONCAT('$[',i+1,']'))<>'')
    SELECT * FROM data
    ;
    

    .

    +---------------+---------+------+----------------------------+
    | link_entry_id | link_id | I    | jk                         |
    +---------------+---------+------+----------------------------+
    |            19 | AABBCC  |    0 | ["mama@gmail_DOT_com"]     |
    |            20 | DDEEFF  |    0 | ["mama@gmail_DOT_com"]     |
    |            19 | AABBCC  |    1 | ["papa@gmail_DOT_com"]     |
    |            20 | DDEEFF  |    1 | ["papa@gmail_DOT_com"]     |
    |            19 | AABBCC  |    2 | ["daughter@gmail_DOT_com"] |
    |            19 | AABBCC  |    3 | ["son@gmail_DOT_com"]      |
    +---------------+---------+------+----------------------------+
    

    I 是查找papa@gmail_DOT_com 的正确值

    WITH RECURSIVE data AS (
      SELECT 
        link_entry_id, 
        link_id, 
        0 as I, 
        JSON_KEYS(user_data_json, '$[0]') jk
      FROM saved_links
      UNION ALL
      SELECT 
        sl.link_entry_id, 
        sl.link_id, 
        I+1, 
        JSON_KEYS(user_data_json, CONCAT('$[',i+1,']')) 
      FROM saved_links sl, (select max(i) as I from data) x
      WHERE JSON_KEYS(user_data_json, CONCAT('$[',i+1,']'))<>'')
    SELECT 
       json_remove(user_data_json, concat('$[',I,']'))
    FROM saved_links sl 
    INNER JOIN data d ON d.link_entry_id= sl.link_entry_id AND d.link_id=sl.link_id and d.I=1
    ;
    

    .

    [{"mama@gmail_DOT_com": {"u_email": "mama@gmail_DOT_com", "private": "no"}},
          {"daughter@gmail_DOT_com": {"u_email": "daughter@gmail_DOT_com", "private": "no"}}, 
          {"son@gmail_DOT_com": {"u_email": "son@gmail_DOT_com", "private": "no"}}] 
    
    [{"mama@gmail_DOT_com": {"u_email": "mama@gmail_DOT_com", "private": "no"}}] 
    

    【讨论】:

    • 谢谢,但我避免使用 '$[N]' 索引,因为条目的顺序不是可预测的...第一封电子邮件可能是 son@gmail_DOT_com,第二封电子邮件可能是 grandpa@gmail_DOT_com,所以如果您删除基于在数组索引上,您可能会删除错误的条目,因为它们是随机插入的
    • 看起来不错,但是从PHP 我需要在MySql Query 中传递$email....知道如何使用此递归传递PHP $email variable MySql query?中的方法?
    • 我添加了EDIT2。另一种方法是创建一个Function,并让它处理 JSON 内容。
    • 感谢您的努力。您能否提供一个小提琴链接以进行测试?...再次感谢
    猜你喜欢
    • 2019-10-17
    • 2015-11-07
    • 2011-03-04
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 2019-02-01
    • 1970-01-01
    相关资源
    最近更新 更多