【问题标题】:Nested variant updating and deleting in snowflake雪花中的嵌套变体更新和删除
【发布时间】:2021-06-04 09:05:32
【问题描述】:

目前正在将变更数据捕获事件从 MongoDB 流式传输到雪花中,希望将它们应用于已经存在的原始数据。

假设我有一张这样的桌子:

+---------------------+-----------------+-----------+
|         key         |      value      | document  |
+---------------------+-----------------+-----------+
| foo.bar             | "changed value" | <variant> |
| foo.stuff.anArray.1 | 1000            | <variant> |
| ...                 | ...             | ...       |
+---------------------+-----------------+-----------+

variant 包含一个非常嵌套的 JSON ex:

{
    "foo": {
        "bar": "Some info",
        "baz": "Other info",
        "stuff": {
            "anArray": [1, 2, 3],
            "things": "More nested info"
        }
    }
}

我想使用OBJECT_DELETEOBJECT_INSERT 函数来更新雪花中的嵌套变体数据。

尝试制作 js UDF 但不支持eval()

其他方法,例如编写一个执行 key.split(".") 的 UDF,然后递归地遍历结构并更新字段似乎需要很长时间,并且在某些情况下会以 JavaScript out of memory error: UDF thread memory limit exceeded 失败。

寻找更有效的方法来解决这个问题。

【问题讨论】:

  • 您能否更具体/举例说明如何更新对象(就数据而言)?
  • @FelipeHoffa 当然,表中提到的键是 json 中的路径。在第一行中,“foo.bar”会将 json 中的“Some info”值更新为“changed value”,在第二行中,“anArray”中的预期值将是 [1, 1000, 3]。我的想法是让它与OBJECT_INSERT 功能相同,但能够更深入地了解 json。
  • 你的意思是,有人可以编写雪花 SQL 来处理这个问题吗:docs.mongodb.com/manual/reference/change-events/…
  • 我真的很想帮忙解决这个问题 - 我只是无法准确理解您想要什么。
  • @SimeonPilgrim 是的,确实这个想法是将来自更改流中的更改应用于已经在仓库中的数据。 variant 是现有数据,key, value 是来自 mongodb CDC 的解析信息。

标签: snowflake-cloud-data-platform variant


【解决方案1】:

我遇到过similar problem 并使用通用 UDF 来解决它。下面是一个 UDF 实现示例,可以解决您的需求:

create or replace function edit_nested_entity("variant_object" variant, "path" string, "value" string)
returns variant
language javascript
as
$$
// https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-and-arrays-by-string-path?page=1&tab=votes#tab-top
    Object.byString = function(o, s) {
        s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
        s = s.replace(/^\./, '');           // strip a leading dot
        var a = s.split('.');
        for (var i = 0, n = a.length; i < n; ++i) {
            var k = a[i];
            if (k in o) {
                o = o[k];
            } else {
                return;
            }
        }
        return o;
   }
   // get the entity base
   nested_entity = Object.byString(variant_object, path)
   // update the value
   nested_entity = value
   return variant_object;
$$;

现在您需要运行以下 SQL 命令来实现您所需要的:

UPDATE t1
SET document = edit_nested_entity(document, key, value) 

您可能会对此 UDF 进行一些微调,使其更通用(或为不同的数据类型使用不同的 UDF),但这会奏效。

【讨论】:

    【解决方案2】:

    有一种使用 OBJECT_INSERT 的方法,但它并不漂亮。不幸的是,我看不到在单个 OBJECT_INSERT 中指定嵌套键的方法。 所以:

    create or replace table test2 (document variant);
    insert into test2 select object_construct('foo',object_construct('bar','Some info', 'baz', 'Other info','stuff', object_construct('anArray', array_construct(1, 2, 3), 'things', 'More nested info')));
    select * from test2;
    

    我明白了:

    {
          "foo": {
                    "bar": "Some info",
                    "baz": "Other info",
                    "stuff": {
                              "anArray": [1,2,3],
                              "things": "More nested info"
                    }
          }
    

    }

    现在,我想用“更改的信息”更新 foo.bar,这样我就可以做到(记得将标志设置为 TRUE,这样您才能获得更新而不是插入):

    update test2 set document = OBJECT_INSERT(document, 'foo', OBJECT_INSERT(document:foo::VARIANT, 'bar', 'Changed value', TRUE), TRUE) WHERE document:foo.bar::VARCHAR = 'Some info';
    

    我回来了:

    {
              "foo": {
                        "bar": "Changed value",
                        "baz": "Other info",
                        "stuff": {
                                  "anArray": [1,2,3],
                                  "things": "More nested info"
                        }
              }
    }
    

    您也可以使用 here 中提到的 Javascript UDF。

    【讨论】:

    • 是的,当我们有特定的键要更新时,这很有效,但不幸的是,键是动态的,值和变体也是。
    • 如果键是动态的,你不能使用 Javascript 存储过程并在这样的 UPDATE 语句中注入键吗?我想您不想每次都重写 UPDATE 语句。我看到的唯一挑战确实是嵌套 JSON 有多深,因为您需要每个级别的 OBJECT_INSERT,这也不是很好。
    • 是的,这就是问题所在,我有一个 JS UDF,但有时它会因JavaScript out of memory error: UDF thread memory limit exceeded 而失败,因此执行不一致
    • 您能否发布一个您的 JS UDF 示例,看看我们是否可以提出任何改进建议?
    • 我添加了一个使用 another concept 实现动态嵌套变体更新的 UDF 示例,这就是我们在系统中实际使用的,因此您可以让它为您工作。
    猜你喜欢
    • 1970-01-01
    • 2021-07-17
    • 2020-05-26
    • 2021-08-13
    • 1970-01-01
    • 1970-01-01
    • 2022-06-19
    • 2021-06-18
    • 2022-07-06
    相关资源
    最近更新 更多