8000 [Feature request] Batch queries · Issue #504 · romeerez/orchid-orm · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[Feature request] Batch queries #504

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

Open
mordechaim opened this issue May 2, 2025 · 2 comments
Open

[Feature request] Batch queries #504

mordechaim opened this issue May 2, 2025 · 2 comments
Labels
enhancement New feature or request

Comments

@mordechaim
Copy link
mordechaim commented May 2, 2025

There are many times in my code where I need to update multiple records at once. Since we can't update multiple records when they have different values I need to use many queries and await them all at once using Promise.all.

It would really be nice if we could have a similar db.$batch function that combines all queries into a single multi-statement query. This will result in a single round trip.

Like Promise.all, the return type should be a tuple with results in the same order as the passed queries.

@NelsonMK
Copy link
NelsonMK commented May 2, 2025

Had the same issue so I took inspiration from this article on drizzle

Here is my implementation, it is not pretty but works

let orderCase = 'CASE\n';
let stepIdCase = 'CASE\n';
const ids: string[] = [];

const orderParams: Record<string, any> = {};
const stepParams: Record<string, any> = {};

//input is an array of values sent from my frontend app
input.forEach((match, index) => {
 const idParam = `id${index}`;
 const orderParam = `new_order_value${index}`;
 const stepParam = `new_step_value${index}`;

 orderParams[idParam] = match.id;
 orderParams[orderParam] = match.newOrder;

 stepParams[idParam] = match.id;
 stepParams[stepParam] = match.newStepId;

 orderCase += `  WHEN id = $${idParam} THEN $${orderParam}\n`;
 stepIdCase += `  WHEN id = $${idParam} THEN $${stepParam}\n`;
 ids.push(match.id);
});

orderCase += '  ELSE "order"\nEND';
stepIdCase += '  ELSE "step_id"\nEND';

await db.talentMatch.whereIn('id', ids).update({
 order: () => sql({ raw: orderCase, values: orderParams }),
 stepId: () => sql({ raw: stepIdCase, values: stepParams }),
});

This generates:

UPDATE "talent_matches" SET "order" = CASE
  WHEN id = $1 THEN $2
  ELSE "order"
END, "step_id" = CASE
  WHEN id = $3 THEN $4
  ELSE "step_id"
END, "updated_at" = now() WHERE "talent_matches"."id" IN ($5)

@romeerez romeerez added the enhancement New feature or request label May 25, 2025
@romeerez
Copy link
Owner
romeerez commented May 25, 2025

That's a good feature, I'll work on it later.

You probably don't want 9 updates to succeed and 1 of them to fail. So the new batch method should use a transaction.

Once I was doing a batch insert and encountered that partial success case, had to wrap it in a transaction and expected it to become slower. But, in contrary, I learned that transaction actually makes batch inserts/updates faster, because db can do its persisting job just once for all records rather than many times. So it's even faster in a transaction.

I expect the way suggested by Drizzle to be much less efficient, it will be interesting to compare.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants
0