如何解决雪花中的嵌套变体更新和删除
目前正在将变更数据捕获事件从 MongoDB 流式传输到雪花中,希望将它们应用于已经存在的原始数据。
假设我有一张这样的桌子:
+---------------------+-----------------+-----------+
| 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
函数来更新雪花中的这个嵌套变体数据。
尝试制作 js UDF,但不支持 eval()
。
其他方法,例如编写执行 key.split(".")
的 UDF,然后递归遍历结构并更新字段似乎需要很长时间,并且在某些情况下会以 JavaScript out of memory error: UDF thread memory limit exceeded
失败。
解决方法
我遇到了 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),但这会起作用。
,有一种使用 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,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","stuff": {
"anArray": [1,"things": "More nested info"
}
}
}
您也可以使用前面提到的 Javascript UDF here。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。