Thread: jsonb_set array append hack?

jsonb_set array append hack?

From
Thom Brown
Date:
Hi,

I've noticed that if you use a string for an element key in jsonb_set with create_missing set to true, you can use it to append to an array:

postgres=# SELECT jsonb_set(
'{"name": "Joe", "vehicle_types": ["car","van"]}'::jsonb,
           '{vehicle_types,nonsense}',
           '"motorcycle"', true);
                           jsonb_set                           
----------------------------------------------------------------
 {"name": "Joe", "vehicle_types": ["car", "van", "motorcycle"]}
(1 row)

What this really should match is a nested element inside "vehicle_types" called "nonsense".  But this seems to be a hack to get an element added to an array.  To do it properly currently requires specifying an arbitrary number in the hope that it will exceed the number of elements you have in the array.

e.g.

postgres=# SELECT jsonb_set(
           '{"name": "Joe", "vehicle_types": ["car","van"]}'::jsonb,
           '{vehicle_types,100000}',
           '"motorcycle"', true);
                           jsonb_set                           
----------------------------------------------------------------
 {"name": "Joe", "vehicle_types": ["car", "van", "motorcycle"]}
(1 row)

But I'm guessing people shouldn't be relying on the hack in the first example.  Isn't this a bug?  If so, wouldn't this also be a bug?:

postgres=# SELECT jsonb_set(
           '{"name": "Joe", "vehicle_types": ["car","van"]}'::jsonb,
           array['vehicle_types',NULL],
           '"motorcycle"', true);

Thom

Re: jsonb_set array append hack?

From
Andrew Dunstan
Date:

On 09/14/2015 01:29 PM, Thom Brown wrote:
> Hi,
>
> I've noticed that if you use a string for an element key in jsonb_set 
> with create_missing set to true, you can use it to append to an array:
>
> postgres=# SELECT jsonb_set(
> '{"name": "Joe", "vehicle_types": ["car","van"]}'::jsonb,
>            '{vehicle_types,nonsense}',
>            '"motorcycle"', true);
> jsonb_set
> ----------------------------------------------------------------
>  {"name": "Joe", "vehicle_types": ["car", "van", "motorcycle"]}
> (1 row)
>
> What this really should match is a nested element inside 
> "vehicle_types" called "nonsense".  But this seems to be a hack to get 
> an element added to an array.  To do it properly currently requires 
> specifying an arbitrary number in the hope that it will exceed the 
> number of elements you have in the array.


That's a bug and we should fix it.


>
> e.g.
>
> postgres=# SELECT jsonb_set(
>            '{"name": "Joe", "vehicle_types": ["car","van"]}'::jsonb,
>            '{vehicle_types,100000}',
>            '"motorcycle"', true);
> jsonb_set
> ----------------------------------------------------------------
>  {"name": "Joe", "vehicle_types": ["car", "van", "motorcycle"]}
> (1 row)
>
> But I'm guessing people shouldn't be relying on the hack in the first 
> example.  Isn't this a bug?  If so, wouldn't this also be a bug?:
>
> postgres=# SELECT jsonb_set(
>            '{"name": "Joe", "vehicle_types": ["car","van"]}'::jsonb,
>            array['vehicle_types',NULL],
>            '"motorcycle"', true);
>
>

I think that's a bug too.

cheers

andrew




Re: jsonb_set array append hack?

From
Dmitry Dolgov
Date:
I'm sorry, but I'm not sure, what behavior is expected in this case?
Right now the following logic was implemented:
    "we trying to set an element inside an array, but we've got a non-integer path item
    ("nonsense" in this particular case), so we're going to add a new element at the end of array by default"

If it's wrong, should we refuse to perform such kind of operations, or should we replace
    "vehicle_type": ["car", "van"]
to
    "vehicle_type: {"nonsense": "motorcycle"}
?

On 15 September 2015 at 01:59, Andrew Dunstan <andrew@dunslane.net> wrote:


On 09/14/2015 01:29 PM, Thom Brown wrote:
Hi,

I've noticed that if you use a string for an element key in jsonb_set with create_missing set to true, you can use it to append to an array:

postgres=# SELECT jsonb_set(
'{"name": "Joe", "vehicle_types": ["car","van"]}'::jsonb,
           '{vehicle_types,nonsense}',
           '"motorcycle"', true);
jsonb_set
----------------------------------------------------------------
 {"name": "Joe", "vehicle_types": ["car", "van", "motorcycle"]}
(1 row)

What this really should match is a nested element inside "vehicle_types" called "nonsense".  But this seems to be a hack to get an element added to an array.  To do it properly currently requires specifying an arbitrary number in the hope that it will exceed the number of elements you have in the array.


That's a bug and we should fix it.



e.g.

postgres=# SELECT jsonb_set(
           '{"name": "Joe", "vehicle_types": ["car","van"]}'::jsonb,
           '{vehicle_types,100000}',
           '"motorcycle"', true);
jsonb_set
----------------------------------------------------------------
 {"name": "Joe", "vehicle_types": ["car", "van", "motorcycle"]}
(1 row)

But I'm guessing people shouldn't be relying on the hack in the first example.  Isn't this a bug?  If so, wouldn't this also be a bug?:

postgres=# SELECT jsonb_set(
           '{"name": "Joe", "vehicle_types": ["car","van"]}'::jsonb,
           array['vehicle_types',NULL],
           '"motorcycle"', true);



I think that's a bug too.

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

Re: jsonb_set array append hack?

From
Thom Brown
Date:
On 20 September 2015 at 16:17, Dmitry Dolgov <9erthalion6@gmail.com> wrote:
I'm sorry, but I'm not sure, what behavior is expected in this case?
Right now the following logic was implemented:
    "we trying to set an element inside an array, but we've got a non-integer path item
    ("nonsense" in this particular case), so we're going to add a new element at the end of array by default"

If it's wrong, should we refuse to perform such kind of operations, or should we replace
    "vehicle_type": ["car", "van"]
to
    "vehicle_type: {"nonsense": "motorcycle"}
?

(please bottom-post)

I would expect some kind of error.  We're trying to address a position in an array, and we're instead passing a key.  If it completes successfully, the chances are it isn't what the user intended.

Thom

Re: jsonb_set array append hack?

From
Dmitry Dolgov
Date:
I would expect some kind of error.  We're trying to address a position in an array, and we're instead passing a key.  If it completes successfully, the chances are it isn't what the user intended.

Thanks for the explanation. So, basically, it should be like this, am I right?

postgres=# SELECT jsonb_set(
    '{"name": "Joe", "vehicle_types": ["car", "van"]}'::jsonb,
    '{vehicle_types, nonsense}',
    '"motorcycle"', true);
ERROR:  path element at the position 2 is not an integer

On 20 September 2015 at 23:50, Thom Brown <thom@linux.com> wrote:
On 20 September 2015 at 16:17, Dmitry Dolgov <9erthalion6@gmail.com> wrote:
I'm sorry, but I'm not sure, what behavior is expected in this case?
Right now the following logic was implemented:
    "we trying to set an element inside an array, but we've got a non-integer path item
    ("nonsense" in this particular case), so we're going to add a new element at the end of array by default"

If it's wrong, should we refuse to perform such kind of operations, or should we replace
    "vehicle_type": ["car", "van"]
to
    "vehicle_type: {"nonsense": "motorcycle"}
?

(please bottom-post)

I would expect some kind of error.  We're trying to address a position in an array, and we're instead passing a key.  If it completes successfully, the chances are it isn't what the user intended.

Thom

Attachment

Re: jsonb_set array append hack?

From
Andrew Dunstan
Date:

On 09/21/2015 12:13 PM, Dmitry Dolgov wrote:
> > I would expect some kind of error.  We're trying to address a 
> position in an array, and we're instead passing a key.  If it 
> completes successfully, the chances are it isn't what the user intended.
>
> Thanks for the explanation. So, basically, it should be like this, am 
> I right?
>
> postgres=# SELECT jsonb_set(
>     '{"name": "Joe", "vehicle_types": ["car", "van"]}'::jsonb,
>     '{vehicle_types, nonsense}',
>     '"motorcycle"', true);
> ERROR:  path element at the position 2 is not an integer


That seems reasonable. For that matter, we should probably disallow NULL 
path elements also, shouldn't we?

cheers

andrew



Re: jsonb_set array append hack?

From
Thom Brown
Date:
On 21 September 2015 at 22:21, Andrew Dunstan <andrew@dunslane.net> wrote:


On 09/21/2015 12:13 PM, Dmitry Dolgov wrote:
> I would expect some kind of error.  We're trying to address a position in an array, and we're instead passing a key.  If it completes successfully, the chances are it isn't what the user intended.

Thanks for the explanation. So, basically, it should be like this, am I right?

postgres=# SELECT jsonb_set(
    '{"name": "Joe", "vehicle_types": ["car", "van"]}'::jsonb,
    '{vehicle_types, nonsense}',
    '"motorcycle"', true);
ERROR:  path element at the position 2 is not an integer


That seems reasonable. For that matter, we should probably disallow NULL path elements also, shouldn't we?

I'd say yes.  If someone really wants to name a field "null", they'll just have to quote it in the path. (e.g. '{contact,"null"}')

--
Thom

Re: jsonb_set array append hack?

From
Dmitry Dolgov
Date:
>> For that matter, we should probably disallow NULL path elements also, shouldn't we?
I'd say yes. 

Well, here is the new `setPath` function with this modification. Is it what did you mean?
Attachment

Re: jsonb_set array append hack?

From
Peter Geoghegan
Date:
On Mon, Sep 21, 2015 at 2:21 PM, Andrew Dunstan <andrew@dunslane.net> wrote:
>> Thanks for the explanation. So, basically, it should be like this, am I
>> right?
>>
>> postgres=# SELECT jsonb_set(
>>     '{"name": "Joe", "vehicle_types": ["car", "van"]}'::jsonb,
>>     '{vehicle_types, nonsense}',
>>     '"motorcycle"', true);
>> ERROR:  path element at the position 2 is not an integer
>
> That seems reasonable. For that matter, we should probably disallow NULL
> path elements also, shouldn't we?

Are you planning on getting this in by Monday, Andrew? It would be
nice to have this fixed going into beta.

-- 
Peter Geoghegan



Re: jsonb_set array append hack?

From
Andrew Dunstan
Date:

On 10/03/2015 04:49 PM, Peter Geoghegan wrote:
> On Mon, Sep 21, 2015 at 2:21 PM, Andrew Dunstan <andrew@dunslane.net> wrote:
>>> Thanks for the explanation. So, basically, it should be like this, am I
>>> right?
>>>
>>> postgres=# SELECT jsonb_set(
>>>      '{"name": "Joe", "vehicle_types": ["car", "van"]}'::jsonb,
>>>      '{vehicle_types, nonsense}',
>>>      '"motorcycle"', true);
>>> ERROR:  path element at the position 2 is not an integer
>> That seems reasonable. For that matter, we should probably disallow NULL
>> path elements also, shouldn't we?
> Are you planning on getting this in by Monday, Andrew? It would be
> nice to have this fixed going into beta.
>


Yeah, will look at it tonight or tomorrow.

cheers

andrew