summaryrefslogtreecommitdiff
path: root/src/_posts/2020-12-15-merging-json-in-postgresql.md
diff options
context:
space:
mode:
authorPatrick Spek <p.spek@tyil.nl>2021-04-01 07:55:09 +0200
committerPatrick Spek <p.spek@tyil.nl>2021-04-01 07:55:09 +0200
commit224b7c7a557b6060535fe127de7be29d5142d568 (patch)
treead1e112f6d3d054c519af7d25a831204523df739 /src/_posts/2020-12-15-merging-json-in-postgresql.md
parent67a16b1cde665f986fc99626035e23efcee32920 (diff)
Two posts, lost forever on my old desktop
rip sessifet.tyil.net
Diffstat (limited to 'src/_posts/2020-12-15-merging-json-in-postgresql.md')
-rw-r--r--src/_posts/2020-12-15-merging-json-in-postgresql.md50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/_posts/2020-12-15-merging-json-in-postgresql.md b/src/_posts/2020-12-15-merging-json-in-postgresql.md
new file mode 100644
index 0000000..0d7e087
--- /dev/null
+++ b/src/_posts/2020-12-15-merging-json-in-postgresql.md
@@ -0,0 +1,50 @@
+---
+layout: post
+tags: PostgreSQL Programming JSON
+social:
+ email: mailto:~tyil/public-inbox@lists.sr.ht&subject=Merging JSON objects in PostgreSQL
+description: >
+ Left unsatisfied trying to find a nice way to merge two JSON objects in
+ PostgreSQL, I whipped up my own. This small post shows off my glorious
+ concoction for future generations."
+---
+
+At my `$day-job` we have a lot of `jsonb` in our database. From time to time, I
+have to manually run a query to fix something in there. This week was one of
+those times.
+
+While you can pretty much do everything you need with regards to JSON editing
+with `jsonb_se`t, I thought it might be nice if I were able to *merge* a given
+JSON object into an existing object. This might be cleaner in some situations,
+but mostly it is fun to figure it out. And who doesn’t like spending time with
+`plpgsql`?
+
+The way I wanted to have it work is like this:
+
+{% highlight sql %}
+UPDATE user SET properties = jsonb_merge(properties, '{"notifications": {"new_case": false, "new_document": true}}');
+{% endhighlight %}
+
+And this is the eventual function I produced to do it:
+
+{% highlight sql %}
+CREATE OR REPLACE FUNCTION jsonb_merge(original jsonb, delta jsonb) RETURNS jsonb AS $$
+ DECLARE result jsonb;
+ BEGIN
+ SELECT
+ json_object_agg(
+ COALESCE(original_key, delta_key),
+ CASE
+ WHEN original_value IS NULL THEN delta_value
+ WHEN delta_value IS NULL THEN original_value
+ WHEN (jsonb_typeof(original_value) <> 'object' OR jsonb_typeof(delta_value) <> 'object') THEN delta_value
+ ELSE jsonb_merge(original_value, delta_value)
+ END
+ )
+ INTO result
+ FROM jsonb_each(original) e1(original_key, original_value)
+ FULL JOIN jsonb_each(delta) e2(delta_key, delta_value) ON original_key = delta_key;
+ RETURN result;
+END
+$$ LANGUAGE plpgsql;
+{% endhighlight %}