Reputation: 244
So I have a model Item
that has a huge postgresql JSON field called properties
. Most of the time this field does not need to be queried on or changed, however we store price
in this field.
I'm currently writing a script that updates this price
, but there's only a few unique prices
and thousands of Items
so in order to save time I have a list of Items
for each unique price
and I'm attempting to do an update all:
Item.where(id: items).update_all("properties->>'price' = #{unique_price}")
But this gives me:
syntax error at or near "->>"
Is there a way to use update all to update a field in a postgres JSON field?
Upvotes: 12
Views: 8951
Reputation: 31467
What I came up with based on @Philidor's suggestion is very similar but with dynamic bindings:
assignment = ["field = jsonb_set(field, '{ name_of_the_key }', ?)", value.to_json]
scope.update_all(scope.model.sanitize_sql_for_assignment(assignment))
Upvotes: 0
Reputation: 198
You can also do this
Item.where(id: items).each do |item|
properties = item.properties
item.update(properties: properties.merge({
price: unique_price
}))
end
The keyword merge
will override the value of the key provided with the new value ie unique_price
Merge documentation is here
Upvotes: 0
Reputation: 44370
You need to use jsonb_set()
function, here is an example:
Item.where(id: items).
update_all(
"properties = jsonb_set(properties, '{price}', to_json(#{unique_price}::int)::jsonb)"
)
This would preserve all values and update only one key.
Read documentation
Upvotes: 34