-
-
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
Support proper bulk update via PATCH #1959
Comments
The reason is that you are not doing a bulk update at all. You are doing an
Related: #1945. |
Thanks for the clarification, makes perfect sense. Is a |
Since we already have a Q&A item for that topic, I'd keep this issue. It highlights why |
This is currently an idea only. I can see the benefits of being able to do a bulk Maybe a query could somehow look like: UPDATE table
SET column = pgrst_body.column
FROM (SELECT * FROM json_populate_recordset(NULL::table, $1)) AS pgrst_body
WHERE table.pk_column = pgrst_body.pk_column |
Actually... Do we currently support
|
An array is accepted, but only the first element is taken into account for the UPDATE. There was also another option for the query with an UPDATE..FROM, mentioned on #1816 (Not sure which query would be best atm) |
Ah, thanks for linking that other issue, too. I think the queries are basically the same, except for when the json body is parsed. The proposal in #1816 looks like this would be done in haskell, while the one here is doing it on the database side. I think we generally prefer the latter and try to avoid the former, right? |
This could work as a first iteration of this feature. If a different payload column is desired as the filter, perhaps we could reuse the |
Our query already mostly works for this, it's only a matter of when to apply the payload fields as filters. WITH
pgrst_payload AS ( SELECT '[{"id": 4, "name": "xxx"}, {"id":5, "name": "yyy"}]'::json AS json_data),
pgrst_body AS ( SELECT CASE WHEN json_typeof(json_data) = 'array' THEN json_data ELSE json_build_array(json_data) END AS val FROM pgrst_payload)
UPDATE "test"."projects" SET "name" = x."name" FROM (SELECT * FROM json_populate_recordset (null::"test"."projects" , (SELECT val FROM pgrst_body) )) x
WHERE "test"."projects"."id" = x.id RETURNING "test"."projects".*;
id | name | client_id
----+------+-----------
4 | xxx | 2
5 | yyy |
We could add filters( WITH
pgrst_payload AS ( SELECT '[{"id": 4, "name": "xxx"}, {"id":5, "name": "yyy"}]'::json AS json_data),
pgrst_body AS ( SELECT CASE WHEN json_typeof(json_data) = 'array' THEN json_data ELSE json_build_array(json_data) END AS val FROM pgrst_payload)
UPDATE "test"."projects" SET "name" = x."name" FROM (SELECT * FROM json_populate_recordset (null::"test"."projects" , (SELECT val FROM pgrst_body) )) x
WHERE "test"."projects"."id" = x.id AND "test"."projects"."id" > 4 RETURNING "test"."projects".*;
id | name | client_id
----+------+-----------
5 | yyy | But it doesn't help for knowing when to apply the payload filters. I mean we cannot always apply that condition. If we did it, it could cause confusing situations like: -- the payload body has no id
WITH
pgrst_payload AS ( SELECT '[{"name": "xxx"}, {"name": "yyy"}]'::json AS json_data),
pgrst_body AS ( SELECT CASE WHEN json_typeof(json_data) = 'array' THEN json_data ELSE json_build_array(json_data) END AS val FROM pgrst_payload)
UPDATE "test"."projects" SET "name" = x."name" FROM (SELECT * FROM json_populate_recordset (null::"test"."projects" , (SELECT val FROM pgrst_body) )) x
WHERE "test"."projects"."id" = x.id AND "test"."projects"."id" > 4 RETURNING "test"."projects".*;
id | name | client_id
----+------+-----------
(0 rows)
-- Nothing gets updated That would also break existing PATCH requests. I think we should apply the payload filter whenever there are no query param filters. So: PATCH /projects
[
{"id": 5, "name": "xxx"},
{"id": 6, "name": "yyy"}
] Would generate the query with the id filter applied. This would break the ability to PATCH the whole table in one request(deliberately or accidentaly), I'd argue that was always unwanted behavior(ref). So this: PATCH /projects
{"name": "xxx"} Will always result in 0 updates done(with no error from the db) and a 404 will be returned, same as doing an To make that operation possible, we can enforce a PATCH /projects?limit=10&order=id
{"name": "xxx"} Only 10 updates will happen. |
This comment was marked as outdated.
This comment was marked as outdated.
Reopened, now that is #2424 is merged. |
This comment was marked as outdated.
This comment was marked as outdated.
Reusing the syntax from the discussion on #465 (comment), I think this feature should be implemented in the following way. Having: GET /items?id=lte.3
[
{ "id": 1, "name": "Item 1" }
, { "id": 2, "name": "Item 2" }
, { "id": 3, "name": "Item 3" }
] Doing: PATCH /items?id=lte.3&name=set.$body->name
Prefer: return=representation
[
{ "id": 1, "name": "Updated Item 1" }
, { "id": 2, "name": "Updated Item 2" }
, { "id": 3, "name": "Updated Item 3" }
] Will result on: [
{ "id": 1, "name": "Updated Item 1" }
, { "id": 2, "name": "Updated Item 2" }
, { "id": 3, "name": "Updated Item 3" }
] After this, #465 should be easier to implement too. |
@steve-chavez @laurenceisla POST /items
Prefer: return=representation, resolution=merge-duplicates
[
{ "id": 1, "name": "Updated Item 1" }
, { "id": 2, "name": "Updated Item 2" }
, { "id": 3, "name": "Updated Item 3" }
] HTTP/1.1 200 OK
[
{ "id": 1, "name": "Updated Item 1" }
, { "id": 2, "name": "Updated Item 2" }
, { "id": 3, "name": "Updated Item 3" }
] |
Environment
Description of issue
Schema:
Postgrest usage:
Bulk update on partial set of columns triggers the
NOT NULL
constraint of the rest of the columns which are set asNOT NULL
. Currently we relaxed the constraints in our database to fix that, and looked at doing this via a stored procedure, however it would be nice to have an official suggestion / fix for this.The text was updated successfully, but these errors were encountered: