How to connect rows in a many-to-many (implicit join table) relation efficiently? #29170
Replies: 4 comments 3 replies
|
You’re right that you can’t use createMany with relations, so the recommended workaround is to loop create calls and run them together in a $transaction. Something like this: type PostInput = {
title: string
categoryNames: string[]
}
async function createPostsWithCategories(postsData: PostInput[]) {
// Build an array of create() calls
const createOperations = postsData.map((post) =>
prisma.post.create({
data: {
title: post.title,
categories: {
connect: post.categoryNames.map((name) => ({ name })),
},
},
})
)
// Run all creates in a single transaction
return prisma.$transaction(createOperations)
}
async function main() {
const postsData: PostInput[] = [
{
title: 'Post 1',
categoryNames: ['Category1', 'Category2'],
},
{
title: 'Post 2',
categoryNames: ['Category2', 'Category3'],
},
// ...more posts
]
const createdPosts = await createPostsWithCategories(postsData)
console.log(`Created ${createdPosts.length} posts`)
}
main()
.catch((e) => {
console.error(e)
process.exit(1)
})
.finally(async () => {
await prisma.$disconnect()
}) |
|
tio el problema es que prisma nombra las tablas implicitas con un guion bajo delante, tipo si tienes ModelA y ModelB la tabla se llama _ModelAToModelB (en orden alfabetico). puedes usar executeRaw directamente sobre esa tabla: await prisma.$executeRaw`
INSERT INTO _ModelAToModelB (A, B)
SELECT a.id, b.id FROM tableA a, tableB b
WHERE -- tu condicion
ON CONFLICT DO NOTHING
`si no sabes el nombre exacto de la tabla mira en tu base de datos directamente, suelen estar ordenadas alfabeticamente los dos modelos. con esto te ahorras el bucle y lo haces en una sola query, que para miles de filas es lo unico que tiene sentido |
|
Prisma's implicit join table naming convention is So for this schema: model Post {
tags Tag[]
}
model Tag {
posts Post[]
}The table is You can verify with: SELECT table_name FROM information_schema.tables WHERE table_name LIKE _%;For the bulk insert, I'd go with const postIds = pairs.map((p) => p.postId);
const tagIds = pairs.map((p) => p.tagId);
await prisma.$executeRawUnsafe(
`INSERT INTO "_PostToTag" ("A", "B")
SELECT * FROM unnest($1::int[], $2::int[])
ON CONFLICT DO NOTHING`,
postIds,
tagIds
);If you want something simpler (and the dataset is not huge), string interpolation works too: const values = pairs
.map((p) => `(${p.postId}, ${p.tagId})`)
.join(", ");
await prisma.$executeRawUnsafe(
`INSERT INTO "_PostToTag" ("A", "B") VALUES ${values} ON CONFLICT DO NOTHING`
);Honestly, if you are going to do a lot of raw SQL against join tables, consider switching to an explicit join model: model PostTag {
postId Int
tagId Int
post Post @relation(fields: [postId], references: [id])
tag Tag @relation(fields: [tagId], references: [id])
@@id([postId, tagId])
}Then you get |
|
Hi, As we have not heard back from you, we are closing this discussion to keep our discussions organized. Feel free to start a new discussion if this remains relevant. Thank you for being part of the community! |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Question
I am trying to connect rows for two tables that have a many-to-many relation. Both tables will have thousands of rows that need to be joined together. It would be incredibly inefficient to loop over one table to do a createOrConnect with the other. It is not possible to access relations in a createMany, so that is out of the options. I tried to use an executeRawUnsafe to directly create rows in the implicit join table, but that gives me an error saying that the table does not exist.
Is there a way to directly write to an implicit join table? This would solve my issue. I don't need to worry about SQL injections, as all input values are coming from the database. I do not want to create an explicit join table, because my system uses a lot of introspection to provide accurate data to the frontend, and this join table should not be a part of that introspection.
All reactions