jsonb_set: update or upsert default?

Started by Andrew Dunstanover 10 years ago4 messages
#1Andrew Dunstan
andrew@dunslane.net

The proposed flag for jsonb_set (the renamed jsonb_replace) in the patch
I recently published is set to false, meaning that the default behaviour
is to require all elements of the path including the last to be present.
What that does is effectively UPDATE for jsonb. If the flag is true,
then the last element can be absent, in which case it's created, so this
is basically UPSERT for jsonb. The question is which should be the
default. We got into the weeds on this with suggestions of throwing
errors on missing paths, but that's going nowhere, and I want to get
discussion back onto the topic of what should be the default.

cheers

andrew

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#2David E. Wheeler
david@justatheory.com
In reply to: Andrew Dunstan (#1)
1 attachment(s)
Re: jsonb_set: update or upsert default?

On May 22, 2015, at 7:22 PM, Andrew Dunstan <andrew@dunslane.net> wrote:

The proposed flag for jsonb_set (the renamed jsonb_replace) in the patch I recently published is set to false, meaning that the default behaviour is to require all elements of the path including the last to be present. What that does is effectively UPDATE for jsonb. If the flag is true, then the last element can be absent, in which case it's created, so this is basically UPSERT for jsonb. The question is which should be the default. We got into the weeds on this with suggestions of throwing errors on missing paths, but that's going nowhere, and I want to get discussion back onto the topic of what should be the default.

Here’s JavaScript in Chrome, FWIW:

var f = {}
f["foo"][0] = “bar"
Uncaught TypeError: Cannot set property '0' of undefined
at <anonymous>:2:13
at Object.InjectedScript._evaluateOn (<anonymous>:895:140)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:828:34)
at Object.InjectedScript.evaluate (<anonymous>:694:21)

Best,

David

Attachments:

smime.p7sapplication/pkcs7-signature; name=smime.p7sDownload
#3Petr Jelinek
petr@2ndquadrant.com
In reply to: David E. Wheeler (#2)
Re: jsonb_set: update or upsert default?

On 23/05/15 17:59, David E. Wheeler wrote:

On May 22, 2015, at 7:22 PM, Andrew Dunstan <andrew@dunslane.net> wrote:

The proposed flag for jsonb_set (the renamed jsonb_replace) in the patch I recently published is set to false, meaning that the default behaviour is to require all elements of the path including the last to be present. What that does is effectively UPDATE for jsonb. If the flag is true, then the last element can be absent, in which case it's created, so this is basically UPSERT for jsonb. The question is which should be the default. We got into the weeds on this with suggestions of throwing errors on missing paths, but that's going nowhere, and I want to get discussion back onto the topic of what should be the default.

Here’s JavaScript in Chrome, FWIW:

var f = {}
f["foo"][0] = “bar"
Uncaught TypeError: Cannot set property '0' of undefined
at <anonymous>:2:13
at Object.InjectedScript._evaluateOn (<anonymous>:895:140)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:828:34)
at Object.InjectedScript.evaluate (<anonymous>:694:21)

As I understand it, that's not really the same as what Andrew says. The
real example of that is

var f = {}
f["foo"] = “bar"
f

{ foo: 'bar' }

which works fine in JavaScript and most other dynamic languages like
Python or Perl. So my opinion is that default should be true here.

Another thing I noticed is that while following looks as expected:
# select jsonb_set('{"baz":1}'::jsonb, '{foo}', '"bar"', true);
jsonb_set
--------------------------
{"baz": 1, "foo": "bar"}
(1 row)

If I use empty jsonb object it does not work anymore:
# select jsonb_set('{}', '{foo}', '"bar"', true);
jsonb_set
-----------
{}
(1 row)

--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Andrew Dunstan
andrew@dunslane.net
In reply to: Petr Jelinek (#3)
Re: jsonb_set: update or upsert default?

On 05/23/2015 04:03 PM, Petr Jelinek wrote:

On 23/05/15 17:59, David E. Wheeler wrote:

On May 22, 2015, at 7:22 PM, Andrew Dunstan <andrew@dunslane.net> wrote:

The proposed flag for jsonb_set (the renamed jsonb_replace) in the
patch I recently published is set to false, meaning that the default
behaviour is to require all elements of the path including the last
to be present. What that does is effectively UPDATE for jsonb. If
the flag is true, then the last element can be absent, in which case
it's created, so this is basically UPSERT for jsonb. The question is
which should be the default. We got into the weeds on this with
suggestions of throwing errors on missing paths, but that's going
nowhere, and I want to get discussion back onto the topic of what
should be the default.

Here’s JavaScript in Chrome, FWIW:

var f = {}
f["foo"][0] = “bar"
Uncaught TypeError: Cannot set property '0' of undefined
at <anonymous>:2:13
at Object.InjectedScript._evaluateOn (<anonymous>:895:140)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:828:34)
at Object.InjectedScript.evaluate (<anonymous>:694:21)

As I understand it, that's not really the same as what Andrew says.
The real example of that is

var f = {}
f["foo"] = “bar"
f

{ foo: 'bar' }

Yeah, more or less.

which works fine in JavaScript and most other dynamic languages like
Python or Perl. So my opinion is that default should be true here.

OK, although Perl at least will autovivify the whole path:

[andrew@emma ~]$ perl -e 'my %x; $x{foo}{bar}{baz} = 1; use
Data::Dumper; print Dumper(\%x);'
$VAR1 = {
'foo' => {
'bar' => {
'baz' => 1
}
}
};

But since, as David's example shows, JS doesn't do that we seem to be on
solid ground not doing it either.

Another thing I noticed is that while following looks as expected:
# select jsonb_set('{"baz":1}'::jsonb, '{foo}', '"bar"', true);
jsonb_set
--------------------------
{"baz": 1, "foo": "bar"}
(1 row)

If I use empty jsonb object it does not work anymore:
# select jsonb_set('{}', '{foo}', '"bar"', true);
jsonb_set
-----------
{}
(1 row)

Oh, that looks like a bug. Will check. Thanks.

cheers

andrew

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers