根据其他字段的值在 JSONB 列中插入新项目 - postgres
Insert new item in JSONB column based on value of other field - postgres
我有以下 jsonb 结构,其中有很多条目
[
{
"name":"test",
"features":[
{
"name":"feature1",
"granted":false
},
{
"name":"feature2",
"granted":true
}
]
}...
]
当父 name
元素的值为“test”且 feature1
granted
为“false”时,我想在 features
数组中添加一个新条目".
想法是写一个flyway脚本来迁移我的数据。
我一直在与 jsonb_insert
作斗争,但我无法弄清楚它的路径部分,因为我可能在那里有很多元素,我不能只添加给定的下标。
最终结果应该是:
[
{
"name":"test",
"features":[
{
"name":"feature1",
"granted":false
},
{
"name":"feature2",
"granted":true
},
{
"name":"newFeature",
"granted":false
}
]
}
]
EDIT1
到目前为止我已经尝试过:
UPDATE my_table SET modules =
jsonb_insert(my_column, '{features, [0]}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column @> '{"features": [{"name":"feature1", "granted": false}]}';
语句执行但实际上没有更新。
EDIT2
我修改了查询只是为了测试
的路径
UPDATE my_table SET modules =
jsonb_insert(my_column, '{0, features, 0}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column @> '{"features": [{"name":"feature1", "granted": false}]}';
然而这只会更新数组中的第一个条目,我需要更新的对象不能保证总是在这个位置
这些信息应该足以完成查询:
让我们创建模拟数据
create table a (id serial primary key , b jsonb);
insert into a (b)
values ('[
{
"name": "test",
"features": [
{
"name": "feature1",
"granted": false
},
{
"name": "feature2",
"granted": true
}
]
},
{
"name": "another-name",
"features": [
{
"name": "feature1",
"granted": false
},
{
"name": "feature2",
"granted": true
}
]
}
]');
现在使用 jsonb_array_elements 和序数分解数组以获得索引和 属性
select first_level.id, position, feature_position, feature
from (select a.id, arr.*
from a,
jsonb_array_elements(a.b) with ordinality arr (elem, position)
where elem ->> 'name' = 'test') first_level,
jsonb_array_elements(first_level.elem -> 'features') with ordinality features (feature, feature_position);
本次查询结果为:
1,1,1,"{""name"": ""feature1"", ""granted"": false}"
1,1,2,"{""name"": ""feature2"", ""granted"": true}"
这里有获取所需子元素所需的必要信息,以及查询所需的所有索引。
现在,到了最后的编辑阶段,您已经有了想要的查询:
UPDATE my_table SET modules =
jsonb_insert(my_column, '{0, features, 0}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column @> '{"features": [{"name":"feature1", "granted": false}]}';
在您将使用 id 的地方,因为这些是您感兴趣的行,并且在您从查询中获得它们的索引中。所以:
UPDATE my_table SET modules =
jsonb_insert(my_column, '{' || exploded_info.position::string || ', features, ' || exploded_info.feature_position || '}', '{"name": "newFeature", "granted": false}') from (/* previous query */) as exploded_info
WHERE exploded_info.id = my_table.id and exploded_info.feature -> 'granted' = false;
如您所见,这很容易变得非常讨厌。
我建议使用更 sql 的方法,也就是说,在 table 中而不是在 json 中具有功能,fk 将其链接到您的 table...
如果你真的需要使用 json,例如,因为域真的很复杂并且在应用程序级别定义并且非常灵活。然后我建议在应用程序代码中进行更新
我有以下 jsonb 结构,其中有很多条目
[
{
"name":"test",
"features":[
{
"name":"feature1",
"granted":false
},
{
"name":"feature2",
"granted":true
}
]
}...
]
当父 name
元素的值为“test”且 feature1
granted
为“false”时,我想在 features
数组中添加一个新条目".
想法是写一个flyway脚本来迁移我的数据。
我一直在与 jsonb_insert
作斗争,但我无法弄清楚它的路径部分,因为我可能在那里有很多元素,我不能只添加给定的下标。
最终结果应该是:
[
{
"name":"test",
"features":[
{
"name":"feature1",
"granted":false
},
{
"name":"feature2",
"granted":true
},
{
"name":"newFeature",
"granted":false
}
]
}
]
EDIT1
到目前为止我已经尝试过:
UPDATE my_table SET modules =
jsonb_insert(my_column, '{features, [0]}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column @> '{"features": [{"name":"feature1", "granted": false}]}';
语句执行但实际上没有更新。
EDIT2
我修改了查询只是为了测试
的路径UPDATE my_table SET modules =
jsonb_insert(my_column, '{0, features, 0}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column @> '{"features": [{"name":"feature1", "granted": false}]}';
然而这只会更新数组中的第一个条目,我需要更新的对象不能保证总是在这个位置
这些信息应该足以完成查询:
让我们创建模拟数据
create table a (id serial primary key , b jsonb);
insert into a (b)
values ('[
{
"name": "test",
"features": [
{
"name": "feature1",
"granted": false
},
{
"name": "feature2",
"granted": true
}
]
},
{
"name": "another-name",
"features": [
{
"name": "feature1",
"granted": false
},
{
"name": "feature2",
"granted": true
}
]
}
]');
现在使用 jsonb_array_elements 和序数分解数组以获得索引和 属性
select first_level.id, position, feature_position, feature
from (select a.id, arr.*
from a,
jsonb_array_elements(a.b) with ordinality arr (elem, position)
where elem ->> 'name' = 'test') first_level,
jsonb_array_elements(first_level.elem -> 'features') with ordinality features (feature, feature_position);
本次查询结果为:
1,1,1,"{""name"": ""feature1"", ""granted"": false}"
1,1,2,"{""name"": ""feature2"", ""granted"": true}"
这里有获取所需子元素所需的必要信息,以及查询所需的所有索引。
现在,到了最后的编辑阶段,您已经有了想要的查询:
UPDATE my_table SET modules =
jsonb_insert(my_column, '{0, features, 0}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column @> '{"features": [{"name":"feature1", "granted": false}]}';
在您将使用 id 的地方,因为这些是您感兴趣的行,并且在您从查询中获得它们的索引中。所以:
UPDATE my_table SET modules =
jsonb_insert(my_column, '{' || exploded_info.position::string || ', features, ' || exploded_info.feature_position || '}', '{"name": "newFeature", "granted": false}') from (/* previous query */) as exploded_info
WHERE exploded_info.id = my_table.id and exploded_info.feature -> 'granted' = false;
如您所见,这很容易变得非常讨厌。
我建议使用更 sql 的方法,也就是说,在 table 中而不是在 json 中具有功能,fk 将其链接到您的 table... 如果你真的需要使用 json,例如,因为域真的很复杂并且在应用程序级别定义并且非常灵活。然后我建议在应用程序代码中进行更新