雪花中的嵌套变体更新和删除
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_DELETE
和 OBJECT_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),但这会起作用。
当前正在将 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_DELETE
和 OBJECT_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,如前所述
我遇到过
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),但这会起作用。