雪花中的嵌套变体更新和删除

Nested variant updating and deleting in snowflake

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

假设我有这样一个 table:

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

其中变体包含嵌套非常多的 JSON 例如:

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

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

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

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

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

有一种使用 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"
                    }
          }
}

您还可以使用 Javascript UDF,如前所述

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

create or replace function edit_nested_entity("variant_object" variant, "path" string, "value" string)
returns variant
language javascript
as
$$
// 
    Object.byString = function(o, s) {
        s = s.replace(/\[(\w+)\]/g, '.'); // 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),但这会起作用。