Reputation: 1139
Assume I have the following key-value object:
[{"Gin" : "Au"}, {"Beer": "US"}]
Now, I would like to perform the following queries:
UPDATE product SET location = "AU" WHERE name = "Gin";
UPDATE product SET location = "Beer" WHERE name = "US";
Is it possible to send a key-value object to postgres so it will do the mapping on its own? I want to wrap everything in one request to the database.
Upvotes: 0
Views: 807
Reputation:
You essentially need to convert the JSON array you have into a set of rows that you can join to the product
table:
Doing this is a bit complicated - at least I couldn't find a better way to do it:
with elements (name, map) as (
select json_object_keys(map::json) as name, map::json
from json_array_elements_text('[{"Gin" : "Au"}, {"Beer": "US"}]') as map
)
select name, trim(both '"' from (map -> name)::text) as location
from elements;
I have the feeling there should be a more elegant solution to turn the JSON into a relational set, but I can't figure it out right now.
This will return this:
name | location
-----+---------
Gin | Au
Beer | US
Now this result can be used to update the product table:
with elements (name, map) as (
select json_object_keys(map::json) as name, map::json
from json_array_elements_text('[{"Gin" : "Au"}, {"Beer": "US"}]') as map
)
update product
set location = r.location
from (
select name, trim(both '"' from (map -> name)::text) as location
from elements
) as r (name, location)
where product.name = r.name;
As you are going to do this a lot, I suggest to write a function that turns your JSON into a proper relational result:
create function get_products(p_mapping text)
returns table (name text, location text)
as
$$
with elements (name, map) as (
select json_object_keys(map::json) as name, map::json
from json_array_elements_text(p_mapping::json) as map
)
select name, trim(both '"' from (map -> name)::text) as location
from elements;
$$
language sql;
Then the update looks quite simple:
update product
set location = r.location
from get_products('[{"Gin" : "Au"}, {"Beer": "US"}]') r
where product.name = r.name;
Upvotes: 1