-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Accept patch format for JSONB - set.
filter for PATCH
#465
Comments
👍 |
I can see how it's annoying to replace a big json object entirely just to change one part of it. We can think of ways to allow such a patch, and in the meantime there are two workarounds
|
On the same note of array patching proposed in #488 Given a table with a jsonb column, and a tuple with primary key 'x'
Would affect the row as follows:
|
Both #488 and this issue are special cases of the general ability to manipulate JSONB in a patch request. If we're going to extend the behavior of PATCH it probably makes sense to choose a well-known patch format, such as RFC6902. Here is how it specifies adding an array element: https://tools.ietf.org/html/rfc6902#page-12 I'm closing the other issue as a dup and we can continue conversation here. This seems like a nontrivial amount of work! |
wait, in what issue are we following up on this? |
If I'm understanding correctly 488 is a special case of this issue, so let's track JSONB patching here. |
After reviewing this, I'm not sure how common the need is. It is also achievable with a stored procedure (documentation about how to call them is here). So I'm closing this issue. |
+1, this is definitely a useful feature. I could extract out the datum into it's own column, or perform this behavior in an RPC, but I would strongly prefer to have a baked-in interface for performing |
This seems really useful. Implementing that RFC seems unnecessarily complicated(also slower because of the parsing) considering we already have the pg function that does all the work for us. A simpler approach would be to define our own content type(could be For anyone interested in this being implemented, you can sponsor development on our Patreon or you could also contact me directly(email in profile) so we can arrange development on a fee basis. |
The upcoming jsonb subscripting syntax could help here. We could do: PATCH /tbl?columns=jsonb_column[key]
{"jsonb_column": "value"} brackets([]) need to be url-encoded though. |
An advantage of adopting RFC6902 is that it could also serve us to increment a value(common operation):
Taken from json-api/json-api#214 (comment) Also a json path lib already available https://github.com/GallagherCommaJack/Haskell-JSON-Patch It would also serve to update a column based on another column: PATCH /employees?id=eq.1
Content-Type: application/json-patch+json
{ "op": "copy", "from": "/first_name", "path": "/middle_name" } |
I realize implementing RFC 6902 would be more complex than just using Postgres' built-in functionality, but it would allow developers to use existing JSON diff & patch solutions instead of having to roll their own, for instance:
As someone writing apps, I'd much rather use a battle-tested patching solution at the front-end and API layers, even if it's marginally more expensive at the database layer. To be fair, I'm out of my depth on the exact technical tradeoffs here and could be missing something. I think especially for libraries like this one (and companies like Supabase) that are building on PostgreSQL with developer ergonomics front and center, compatibility with the broader ecosystem matters and will spur adoption. |
Some observations about implementing JSON patch
Drawbacks
Will propose an alternative that doesn't have the drawbacks and it's more flexible. |
AlternativeIntroduce a new
This would cover all the UPDATE use cases we've been asked until now. Use casesReplace a column based on another one: PATCH /tbl?col1=set.(col2)&id=eq.1
(Body is unecessary here)
UPDATE tbl SET col1 = col2 WHERE id = 1 Incrementing a counter by a value: PATCH /tbl?counter=set.(counter,plus,body->value)&id=eq.1
{"value": 5}
UPDATE tbl SET counter = counter + 5 WHERE id = 1 PATCH /tbl?col_arr=set.(col_arr,concat,body->value)&id=eq.1
{"value": [1,2,3]}
update tbl set col_arr = col_arr || [1,2,3] JSON Patch replace(add is more or less the same): PATCH /tbl?jsonb_col->key=set.(body->value)&id=eq.1
{"value": {"another" 3}}
# whenever an arrow(`->` ) is used, we assume `jsonb_set`
update tbl set jsonb_col = jsonb_set(jsonb_col, '{key}', '{"another" 3}') where id = 1 JSON Patch copy: PATCH /tbl?jsonb_other->a=set.(jsonb_col->b)&id=eq.1
(Body is optional here)
update tbl set jsonb_other = jsonb_set(jsonb_other, '{a}', jsonb_col->b) where id = 1 JSON Patch move(same as copy above plus nullifying): PATCH /tbl?jsonb_other->a=set.(jsonb_col->b)&jsonb_col->b=set.(null)&id=eq.1
(Body is unecessary here)
update tbl set
jsonb_other = jsonb_set(jsonb_other, '{a}', jsonb_col->b),
jsonb_col = jsonb_set(jsonb_col, '{b}', null)
where id = 1 JSON Patch remove should be just nullifying. JSON Patch test is unneeded in our case. Advantages
Backwards compatRight now it can be assumed that all the json keys in the body are used in PATCH /people?age=lt.13 HTTP/1.1
{ "category": "child", "eye_color": "brown" } Implicitly is: PATCH /people?age=lt.13&category=set.(body->category)&eye_color=set.(body->eye_color) HTTP/1.1
{ "category": "child", "eye_color": "brown" } And they can be combined as: PATCH /people?age=lt.13&age=set.(age,plus,body->age_increment) HTTP/1.1
{ "category": "child", "age_increment": "2" }
# it would translate to
UPDATE people SET category = 'child', age = age + 2 WHERE age < 13 The parentheses inside the set value are to maintain consistency with |
I suppose a slightly different syntax, which is a tiny bit better to read: PATCH /people?age=lt.13&age=set.age+plus+body->age_increment HTTP/1.1
{ "category": "child", "age_increment": "2" } Because in your client-app you can most likely write that as This would also keep parentheses and commas for row constructors, to be able to set custom types: PATCH /coordinates?point=set.(body->x,body-y) HTTP/1.1
{ "x": 1, "y": 2 } would translate to UPDATE coordinates SET point = ROW(1,2) |
This comment was marked as off-topic.
This comment was marked as off-topic.
set.
filter for PATCH
This comment was marked as outdated.
This comment was marked as outdated.
Just one improvement that could make parsing easier, use PATCH /people?age=lt.13&age=set.age+plus+$body->age_increment HTTP/1.1
{ "category": "child", "age_increment": "2" } It would also make more clear that this key has a special meaning. |
Hi, I am a novice end-user. I found this while looking for a way to do the append to an array use case, as in #465 (comment): In my case jsonb is not relevant; I have a bigint[] and I'd like to pass something like:
An RPC was suggested in #488, and while that would work it seems unnecessarily specific. Could the built-in PostgreSQL Array-append function be called from postgrest? That (seems like) would cover many use cases, not require custom RPCs, and allow postgres errors to propogate through end-user http requests as I can attest I am already used to. |
We already have an select query parameter with which we can directly access an value inside of a json (example: What I had in mind
(deletes the confusion key inside of effect)
|
Hey folks, chiming in here to ask where we stand with this? It would be extremely helpful to have such patch functionality for JSON objects, and I see the discussion about this dates 7 years :) |
What would it take to make this happen considering there's this little thing called jsonb_set `been around now :) |
I'd like to add a field in a jsonb field (a la jsonb_set, ref. http://www.postgresql.org/docs/9.5/static/functions-json.html).
Ideally this would happen similarly to when you update part of the columns of a row with the PATCH verb.
Is this in the roadmap?
The text was updated successfully, but these errors were encountered: