Can't add (correct) item in array in jsonb column - postgresql-9.5

meta - column type jsonb
Json before update:
{
"state": "order.cart_finalization",
"comments": [{
"first_item": "hello"
}]
}
I need to add new item to array (comments).
New array item is:
{ "second_item": "hello2"}
I try this:
UPDATE copy_shop_order SET meta = (
CASE
WHEN meta #>>'{comments}' IS NULL THEN jsonb_set(meta, '{comments}', '[{ "first_item": "hello"}]')
ELSE meta #>'{comments}' || '{ "second_item": "hello2"}'
END
) WHERE id = 100;
But result is:
[
{
"first_item": "hello"
},
{
"second_item": "hello2"
}
]
But I need this:
{
"state": "order.cart_finalization",
"comments": [{
"first_item": "hello"
}, {
"second_item": "hello2"
}]
}

You need to use jsonb_set()
update copy_shop_order
SET meta = case
when meta ? 'comments' then jsonb_set(meta, '{comments}', meta -> 'comments' || '{"second_item": "hello2"}')
else jsonb_set(meta, '{comments}', '[{ "first_item": "hello"}]')
end;

Related

How to update multiple occurrence a specific value of a object present in array of object within Postgres JSON Field

Here is my JSON field where has multiple users with the same name. I want to update all users whose name is Devang to Dev
JSON
{
"user": [
{
"user_name": "Devang",
"user_weight": 0.7676846955248864
},
{
"user_name": "Meet",
"user_weight": 0.07447325861051013
},
{
"user_name": "Devang",
"user_weight": 0.056163873153859706
}
],
"address": [
{
"address_name": "India"
}
]
}
After Update The JSON would be
{
"user": [
{
"user_name": "Dev",
"user_weight": 0.7676846955248864
},
{
"user_name": "Meet",
"user_weight": 0.07447325861051013
},
{
"user_name": "Dev",
"user_weight": 0.056163873153859706
}
],
"address": [
{
"address_name": "India"
}
]
}
Here I have tried this query but update only the first occurrence due to subquery.
with cte as (
select id, ('{user,'||index-1||',user_name}')::text[] as json_path
from user_table, jsonb_array_elements(json_field->'user')
with ordinality arr(vals,index) where arr.vals->>'user_name' ='Devang'
)
update user_table
set json_field = jsonb_set(json_field,cte.json_path,'"Dev"',false)
from cte where user_table.id=cte.id;
Please also look at this DEMO
Any answer will be appreciated
You may use string function REPLACE:
UPDATE user_table
SET json_field = REPLACE(json_field :: TEXT, '"user_name": "Devang"', '"user_name": "Dev"') :: JSONB;
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=fa36275977f85a1233bcbec150ada266

Postgres/JSON Updating nested array elements

Given the input JSON from the 'table' under a column named '_value'. I would like to replace the field "sc" as text from object to value of name under sc.
The json before updating looks like this.
{
"iProps": [
{
"value": {
"rules": [
{
"ao": {
"sc": {
"web_link": "abc.com",
"name": "name"
}
}
},
{
"ao": {
"sc": ""
}
}
]
}
}
]
}
The json after updating should look like this.
{
"iProps": [
{
"value": {
"rules": [
{
"ao": {
"sc": "name"
}
},
{
"ao": {
"sc": ""
}
}
]
}
}
]
}
I tried the below query to get to 'rules' array but having difficulty to proceed further in parsing and updating.
WITH values AS (
SELECT iprop -> 'value' -> 'rules' AS value FROM
table t,jsonb_array_elements(t._value->'iProps') AS
iprop )
SELECT *
from values, jsonb_array_elements(values.ao)
throws following error
ERROR: column values.ao does not exist
LINE 26: from values, jsonb_array_elements(values.ao)
^
SQL state: 42703
Character: 1396
You can try below mentioned query considering your structure is constant and the data type of your column is JSONB.
with cte as (
select
vals2->'ao'->'sc'->'name' as namevalue,
('{iProps,'||index1-1||',value,rules,'||index2-1||',ao,sc}')::text[] as json_path
from
table_,
jsonb_array_elements(value_->'iProps')
with ordinality arr1(vals1,index1),
jsonb_array_elements(vals1->'value'->'rules')
with ordinality arr2(vals2,index2)
)
update table_
set value_ = jsonb_set(value_,cte.json_path,cte.namevalue,false)
from cte
WHERE cte.namevalue IS NOT NULL
DEMO

How to update value in nested json Postgres

I have following JSON stored in "Info" column
{
"customConfig": {
"isCustomGoods": 1
},
"new_addfields": {
"data": [
{
"val": {
"items": [
{
"Code": "calorie",
"Value": "365.76"
},
{
"Code": "protein",
"Value": "29.02"
},
{
"Code": "fat",
"Value": "23.55"
},
{
"Code": "carbohydrate",
"Value": "6.02"
},
{
"Code": "spirit",
"Value": "1.95"
}
],
"storageConditions": "",
"outQuantity": "100"
},
"parameterType": "Nutrition",
"name": "00000000-0000-0000-0000-000000000001",
"label": "1"
},
{
"name": "b4589168-5235-4ec5-bcc7-07d4431d14d6_Для ресторанов",
"val": "true"
}
]
}
}
I want to update value of nested json
{
"name": "b4589168-5235-4ec5-bcc7-07d4431d14d6_Для ресторанов",
"val": "true"
}
and set "val"to "Yes" str so the result should be like
{
"name": "b4589168-5235-4ec5-bcc7-07d4431d14d6_Для ресторанов",
"val": "Yes"
}
How can i do that ? Assuming that i need to update this value in json for many records in database
Considering you have a constant JSON Structure and a primary key in your table. Idea is to get the exact path of element val having value true (which can be at any index in the array) then replace it with desired value. So you can write your query like below:
with cte as (
select
id,
('{new_addfields,data,'||index-1||',val}')::text[] as json_path
from
test,
jsonb_array_elements(info->'new_addfields'->'data')
with ordinality arr(vals,index)
where
arr.vals->>'val' ilike 'true'
)
update test
set info = jsonb_set(info,cte.json_path,'"Yes"',false)
from cte
where test.id=cte.id;
DEMO
We can use jsonb_set() which is available from Postgres 9.5+
From Docs:
jsonb_set(target jsonb, path text[], new_value jsonb [, create_missing boolean])
Query to update the nested object:
UPDATE temp t
SET info = jsonb_set(t.info,'{new_addfields,data,1,val}', jsonb '"Yes"')
where id = 1;
It can also be used in select query:
SELECT
jsonb_set(t.info,'{new_addfields,data,1,val}', jsonb '"Yes"')
FROM temp t
LIMIT 1;

React Native -- Loop through array of objects to return value

Data:
{
"contextTag": {
"value": "Bittersweet",
"valueLabel": "Bittersweet"
},
"tags": [
{
"name": "tag",
"value": "Creamy"
},
{
"name": "tag",
"value": "Colorful"
},
{
"name": "tag",
"value": "Bright"
}
],
"rating": 5,
"userNickName": "HelloGames",
"userLocation": "UK",
"title": "Great!",
"reviewText": "Yada yada yada yada",
"submissionTime": "30 Nov 16"
},
I currently have this working for getting contextTag valueLabels:
this.props.reviewData.reviews.map(
(o) => {
return o.contextTag && o.contextTag.valueLabel ? o.contextTag.valueLabel.trim() : '';
}
)
And this for tags:
this.props.reviewData.reviews.map(
(o) => {
return o.tags && o.tags.value ? o.tags.value.trim() : '';
}
)
But it's coming back empty. How do I loop through tags to grab each of the values?
You can cache the tags, then map over it to get the values. Like below:
const tags = this.props.reviewData.reviews.tags;
const tags_values = ( tags ? tags.map((tag) => (tag.value ? tag.value : '' ) : []); // this an array of the tags values.
Your code does not return what you want because the tags attributes is an array of objects, so to get the tag values you have to map over it as I did above.
Hope this helped.

Using $or selector, There is no index available for this selector

I'd like to retrieve
document with _id of 1
OR
document with value === 13 AND anotherValue === 56
Error:
There is no index available for this selector.
This is my query:
{
"selector": {
"$or": [
{
"_id": "1"
},
{
"value": "13",
"anotherValue": "56"
}
]
}
}
Indexes setup:
Your available Indexes:
special: _id
json: value, anotherValue
json: _id, value, anotherValue
For this query you need to add a selector to get all the IDs like so:
{
"selector": {
"_id": {"$gt":null},
"$or": [
{
"_id": "1"
},
{
"value": "13",
"anotherValue": "56"
}
]
}
}
You can learn more here:
https://cloudant.com/blog/mango-json-vs-text-indexes/
And this SO post:
index and query items in an array with mango query for cloudant and couchdb 2.0
Alternatively, you can add a text index on all fields:
{
"index": {},
"type": "text"
}
And then your original selector should work.