From 224b7c7a557b6060535fe127de7be29d5142d568 Mon Sep 17 00:00:00 2001
From: Patrick Spek
Date: Thu, 1 Apr 2021 07:55:09 +0200
Subject: Two posts, lost forever on my old desktop
rip sessifet.tyil.net
---
.../2020-12-15-merging-json-in-postgresql.md | 50 ++++++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 src/_posts/2020-12-15-merging-json-in-postgresql.md
(limited to 'src/_posts/2020-12-15-merging-json-in-postgresql.md')
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 %}
--
cgit v1.1