[HACKERS] Proposal about a "deep" versions for some jsonb functions

Поиск
Список
Период
Сортировка
От Dmitry Dolgov
Тема [HACKERS] Proposal about a "deep" versions for some jsonb functions
Дата
Msg-id CA+q6zcU+gy1+dxQD09MSz8Zwqq+sPPfS-6GYKmyNqGVQDFeQbg@mail.gmail.com
обсуждение исходный текст
Список pgsql-hackers
Hi

As far as I know, since 9.5 we're missing some convenient features, namely a
deepversion of `jsonb_concat` and `jsonb_minus`. There are already few feature
requests about `jsonb_minus` (see [1], [2]) and a lot of confusion and requests
about a deep version of `jsonb_concat`. From my point of view they're pretty
much related, so I want to propose the following description for this
functionality and eventually implement it.

# jsonb_minus

```
jsonb_minus(jsonb, jsonb, deep=False)
```

Looks like we have to abandon "-" operator for that purpose (see a concern
about that in this thread [2]).

In general this functionality is something like the relative complement for two
jsonb objects. Basically we're taking all the paths inside all jsonb objects
and remove duplicated paths from the left one. Of course an actual
implementation may be different, but I think it's a nice way of thinking about
this logic.

Here are few examples, where "->" is an operation to get an actual value,
".->" - an operation to get a next key, "#->" an operation to get a value from
an array ("-" operator is just for the sake of readability):

------------------------------------------------------------------------------

{"a": 1} - {"a": 1}
=> null

paths:
 a -> 1

 a -> 1

------------------------------------------------------------------------------

{"a": 1} - {"a": 2}
=> {"a": 1}

paths:
 a -> 1

 a -> 2

------------------------------------------------------------------------------

{"a": 1} - {"a": {"b": 1}}
=> {"a": 1}

paths:
 a ->

 a -> .b -> 1

------------------------------------------------------------------------------

{"a": 1, "b": {"c": 2}} - {"b": 1, "b": {"c": 3}}
=> {"b": {"c": 2}}

paths:
 a -> 1
 b .-> c -> 2

 b -> 1
 b .-> c -> 3

------------------------------------------------------------------------------

{"a": {"b": 1}} - {"a": {"b": 1}}
=> null

paths:
 a .-> b -> 1

 a .-> b -> 1

------------------------------------------------------------------------------

{"a": {"b": 1, "c": 2}} - {"a": {"b": 1}}
=> {"a": {"b": 1}}

paths:
 a .-> b -> 1
 a .-> c -> 2

 a .-> b -> 1

------------------------------------------------------------------------------

{"a": {
    "b": {"b1": 1},
    "c": {"c2": 2}
}}

-

{"a": {
    "b": {"b1": 1},
    "c": {"c2": 3}
}}
=> {"a": {"c": {"c2": 2}}

paths:
 a .-> b .-> b1 -> 1
 a .-> c .-> c2 -> 2

 a .-> b .-> b1 -> 1
 a .-> c .-> c2 -> 3

------------------------------------------------------------------------------

{"a": [1, 2, 3]} - {"a": [1, 2]}
=> {"a": [3]}

paths:
 a #-> 1
 a #-> 2
 a #-> 3

 a #-> 1
 a #-> 2

------------------------------------------------------------------------------

{"a": [{"b": 1}, {"c": 2}]} - {"a": [{"b": 1}, {"c": 3}]}
=> {"a": [{"c": 3}]}

paths:
 a #-> b -> 1
 a #-> c -> 2

 a #-> b -> 1
 a #-> c -> 3


But judging from the previous discussions, there is a demand for a bit
different behavior, when `jsonb_minus` is operating only on the top level of
jsonb objects. For that purpose I suggest introducing a flag `deep`, that
should be false by default (as for `jsonb_concat`), that will allow to enable a
"deep logic" (a.k.a relative complement) I described above. With `deep=False`
this function will behave similar to `hstore`:

{"a": 1, "b": {"c": 2}} - {"a": 1, "b": {"c": 3}}
=> {"a": 1}

# jsonb_concat

We already have this function implemented, but a "deep" mode is missing.

```
jsonb_concat(jsonb, jsonb, deep=False)
```

Basically we're taking all the paths inside all jsonb objects and override
duplicated paths in the left one, then add all unique paths from right one to
the result.

Here are few examples for deep mode ("||" operator is just for the sake of
readability):

------------------------------------------------------------------------------

{"a": 1, "b": {"c": 2}} || {"a": 1, "b": {"d": 3}}
=> {"a": 1, "b": {"c": 2, "d": 3}}

paths:
 a -> 1
 b .-> c -> 2

 a -> 1
 b .-> d -> 3

------------------------------------------------------------------------------

{"a": 1, "b": {"c": 2}} || {"a": 1, "b": {"c": 3}}
=> {"a": 1, "b": {"c": 3}}

paths:
 a -> 1
 b .-> c -> 2

 a -> 1
 b .-> c -> 3

------------------------------------------------------------------------------

{"a": [1, 2, 3]} || {"a": [3, 4]}
=> {"a": [1, 2, 3, 4]}

paths:
 a #-> 1
 a #-> 2
 a #-> 3

 a #-> 3
 a #-> 4


What do you think about that?

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Fabien COELHO
Дата:
Сообщение: Re: [HACKERS] Adding -E switch to pg_dumpall
Следующее
От: Thomas Munro
Дата:
Сообщение: Re: [HACKERS] Causal reads take II