Nested joins / where on relation

Hey guys! I have a question regarding filtering a query. Basically, I need to filter the query by order relation - order.date is the field I want to filter by. However, I've noticed that filtering by relations is not yet supported. How do I write the query with joins? I can't figure out how to created nested joins (subOrders -> order and subOrders -> product -> kitchens -> kitchen etc.) This is my query:
const suborders = await db.query.subOrders.findMany({
where: and(isNull(subOrders.kitchenId)),
columns: {
id: true,
quantity: true,
},
with: {
order: true,
product: {
columns: {
id: true,
performancePoints: true,
prepTime: true,
},
with: {
kitchens: {
with: {
kitchen: {
columns: {
id: true,
performancePoints: true,
},
},
},
},
kitchenDependentProperties: {
columns: {
kitchenId: true,
productionPrice: true,
purchasePrice: true,
},
},
},
},
},
});
const suborders = await db.query.subOrders.findMany({
where: and(isNull(subOrders.kitchenId)),
columns: {
id: true,
quantity: true,
},
with: {
order: true,
product: {
columns: {
id: true,
performancePoints: true,
prepTime: true,
},
with: {
kitchens: {
with: {
kitchen: {
columns: {
id: true,
performancePoints: true,
},
},
},
},
kitchenDependentProperties: {
columns: {
kitchenId: true,
productionPrice: true,
purchasePrice: true,
},
},
},
},
},
});
46 Replies
Piotrek
PiotrekOP17mo ago
I tried with something like
const suborders = await db
.select({
id: subOrders.id,
quantity: subOrders.quantity,
})
.from(subOrders)
.leftJoin(orders, and(eq(subOrders.orderId, orders.id)))
.leftJoin(products, eq(subOrders.productId, products.id))
// how do I add nested join to product?
.where(and(isNull(subOrders.kitchenId), sql`<GET_ORDER_DATE_SOMEHOW> = ${tommorrow}`));
const suborders = await db
.select({
id: subOrders.id,
quantity: subOrders.quantity,
})
.from(subOrders)
.leftJoin(orders, and(eq(subOrders.orderId, orders.id)))
.leftJoin(products, eq(subOrders.productId, products.id))
// how do I add nested join to product?
.where(and(isNull(subOrders.kitchenId), sql`<GET_ORDER_DATE_SOMEHOW> = ${tommorrow}`));
Asseater Peter
Asseater Peter17mo ago
Jesus Christ That's a block Give me a sec Wait what? filtering by relations should work, no? Yeah, it definitely does...
Piotrek
PiotrekOP17mo ago
It does? I want to be able to do something that works like that:
where: and(
isNull(subOrders.kitchenId),
eq(subOrders.order.date, tommorrow)
),
where: and(
isNull(subOrders.kitchenId),
eq(subOrders.order.date, tommorrow)
),
of course this thing does not work ^ and I don't know how to implement it also, there's no where on the with.order object - it's a parent-child relation in one-to-many, not the reverse
Mendy
Mendy17mo ago
Previously with RQB you could filter by a relation one level deep. If I’m not mistaken, this feature was removed in the latest update - to help with typescript performance. AFAIK this is achievable with the regular query builder, I suggest you search for other similar questions here.
Piotrek
PiotrekOP17mo ago
Thanks for help! could you send me a link to the thread? I cannot find it... Also, if I would be able to filter with the regular qb - how to create nested joins? As you can see I have to have a lot of layers of relations and I can't find an example using the same with the .select() api
Mendy
Mendy17mo ago
Well tbh I almost never touched the regular qb for select ops. As for the thread, search for comments posted by me you’ll find it in no time.
Piotrek
PiotrekOP17mo ago
ok thanks 🙂
Asseater Peter
Asseater Peter17mo ago
You can definitely filter within relations in 28.1 (Which I think is latest) @peterpkp123 From the docs:
await db.query.posts.findMany({
where: (posts, { eq }) => (eq(posts.id, 1)),
with: {
comments: {
where: (comments, { lt }) => lt(comments.createdAt, new Date()),
},
},
});
await db.query.posts.findMany({
where: (posts, { eq }) => (eq(posts.id, 1)),
with: {
comments: {
where: (comments, { lt }) => lt(comments.createdAt, new Date()),
},
},
});
Asseater Peter
Asseater Peter17mo ago
I have used it today tho, it definitely works...
Piotrek
PiotrekOP17mo ago
It works in a very wierd way - if the with object contains many children it works, if it's a parent in one-to-many relation it does not
Asseater Peter
Asseater Peter17mo ago
Just verified. it works Well, if it's a one-to-one the parent has an "assigned" relation so I can see why it wouldn't
Piotrek
PiotrekOP17mo ago
Piotrek
PiotrekOP17mo ago
it's a one-to-many though not one-to-one
Asseater Peter
Asseater Peter17mo ago
Yeah, but you wrote the or incorrectly
Piotrek
PiotrekOP17mo ago
it's order, just covered by the error message haha
Asseater Peter
Asseater Peter17mo ago
Oh kekw Could you show me the code without the error message?
Piotrek
PiotrekOP17mo ago
Here you go, the entire block once again:
const suborders = await db.query.subOrders.findMany({
where: and(
isNull(subOrders.kitchenId),
),
columns: {
id: true,
quantity: true,
},
with: {
order: {
where: (table, { eq }) => eq(table.date, tommorrow),
},
product: {
columns: {
id: true,
performancePoints: true,
prepTime: true,
},
with: {
kitchens: {
with: {
kitchen: {
columns: {
id: true,
performancePoints: true,
},
},
},
},
kitchenDependentProperties: {
columns: {
kitchenId: true,
productionPrice: true,
purchasePrice: true,
},
},
},
},
},
});
const suborders = await db.query.subOrders.findMany({
where: and(
isNull(subOrders.kitchenId),
),
columns: {
id: true,
quantity: true,
},
with: {
order: {
where: (table, { eq }) => eq(table.date, tommorrow),
},
product: {
columns: {
id: true,
performancePoints: true,
prepTime: true,
},
with: {
kitchens: {
with: {
kitchen: {
columns: {
id: true,
performancePoints: true,
},
},
},
},
kitchenDependentProperties: {
columns: {
kitchenId: true,
productionPrice: true,
purchasePrice: true,
},
},
},
},
},
});
Mendy
Mendy17mo ago
Ok that’s weird. Are you sure you’re on the latest version? Maybe I misinterpreted the release note 🤷‍♂️
Asseater Peter
Asseater Peter17mo ago
Really weird that that errors out for you, as this code is currently working for me with no problems:
db.query.UserTable.findMany({
with: {
sent: {
where: (message, { eq }) => eq(message.id, 4),
orderBy: (message, { desc }) => desc(message.timestamp),
limit: 1,
},
received: {
where: (message, { eq }) => eq(message.id, 4),
orderBy: (message, { desc }) => desc(message.timestamp),
limit: 1,
},
},
})
db.query.UserTable.findMany({
with: {
sent: {
where: (message, { eq }) => eq(message.id, 4),
orderBy: (message, { desc }) => desc(message.timestamp),
limit: 1,
},
received: {
where: (message, { eq }) => eq(message.id, 4),
orderBy: (message, { desc }) => desc(message.timestamp),
limit: 1,
},
},
})
Oh, can you even add order where you did? Could you try doing order: true and see if it still yells at you? I think it's potentially a schema/relations issue
mr_pablo
mr_pablo17mo ago
shouldnt
order: {
where: (table, { eq }) => eq(table.date, tommorrow),
},
order: {
where: (table, { eq }) => eq(table.date, tommorrow),
},
be
order: {
where: (order, { eq }) => eq(order.date, tommorrow),
},
order: {
where: (order, { eq }) => eq(order.date, tommorrow),
},
you need the correct table name
Piotrek
PiotrekOP17mo ago
this works, and your example also works for me - sent and received are arrays and not single objects
mr_pablo
mr_pablo17mo ago
im filtering by a nested relation too, in 0.28.1
Piotrek
PiotrekOP17mo ago
nah it also fails, it's just a function arg if the relation is an entity not entity[] it does not have filters i think
mr_pablo
mr_pablo17mo ago
i think the notes are on about the top level where using a related table column maybe?
Asseater Peter
Asseater Peter17mo ago
My package.json:
"dependencies": {
"@planetscale/database": "^1.10.0",
"@t3-oss/env-core": "^0.6.0",
"dotenv": "^16.3.1",
"drizzle-orm": "^0.28.1",
"mysql2": "^3.6.0",
"zod": "^3.21.4"
}
"dependencies": {
"@planetscale/database": "^1.10.0",
"@t3-oss/env-core": "^0.6.0",
"dotenv": "^16.3.1",
"drizzle-orm": "^0.28.1",
"mysql2": "^3.6.0",
"zod": "^3.21.4"
}
So, are you sure you're using a one-to-many?
Piotrek
PiotrekOP17mo ago
yep i'm sure, it works without the filtering as expected
Asseater Peter
Asseater Peter17mo ago
So what's this about single objects, I'm kinda confused When you use order: true, does it return an object or an array of objects? Because if it's an array it shouldn't be a problem... Could you maybe show me the relation setup?
Piotrek
PiotrekOP17mo ago
an object and that's the problem cause it looks like you can filter by arrays but not objects
Asseater Peter
Asseater Peter17mo ago
Yeah Because a "where" goes over shit, and when you only have one object there's not much to go over. Just add a line checking it after you get everything from the db\
Piotrek
PiotrekOP17mo ago
like technically it works, i have it like that, but it means i basically have to download much more stuff from the db than i would normally do even on my test dev db i'm getting 20 entities instead of4 for now it's not THAT important but would be nice to have some sort of filtering
Asseater Peter
Asseater Peter17mo ago
Wait what, it seems like order is its own thing no? Like, products and shit aren't in order so it shouldn't matter that much
Piotrek
PiotrekOP17mo ago
i have orders and suborders, basically meaning that one suborder - one type of product order is a group of suborders for a selected day and i want to get only suborders that would be part of an order for JUST the next day so yeah, it means a lot actually actually i can do it in a really stupid way thinking about it
Asseater Peter
Asseater Peter17mo ago
So I guess what I'm ordering is why this would be structured this way? You could 100% Just query for orders where the date is the next day and then just go from there
Piotrek
PiotrekOP17mo ago
i can make a query to orders table instead and merge the array afterwards
Asseater Peter
Asseater Peter17mo ago
Like, why are you querying from suborders when you could query from orders
Piotrek
PiotrekOP17mo ago
yeah just realised lmao
Asseater Peter
Asseater Peter17mo ago
Yeah, that other way is just... wrong
Piotrek
PiotrekOP17mo ago
i just need suborders as the result but i can do it in code
Asseater Peter
Asseater Peter17mo ago
Well, that's a different issue Also, the initial way would mean if you had 2 orders for the next day you'd only get 1 at most.... Like, there's a good reason why where doesn't work from the one side. There's just always a better way...
Piotrek
PiotrekOP17mo ago
well i had it in prisma written exactly like that and it worked... maybe something weird under the hood tho not sure thanks for help though!
Asseater Peter
Asseater Peter17mo ago
Definitely something weird under the hood! Since suborder.order could only refer to one order, in theory you should only be querying that one for the day Anytime!
Piotrek
PiotrekOP17mo ago
This is my Prisma code if you're interested 😉
const suborders = await prisma.subOrder.findMany({
where: {
kitchenId: null,
order: {
date: tommorrow,
},
},
select: {
quantity: true,
product: {
select: {
id: true,
kitchens: {
select: {
id: true,
performancePoints: true,
},
},
kitchenDependentProperties: {
select: {
kitchenId: true,
productionPrice: true,
purchasePrice: true,
},
},
performancePoints: true,
prepTime: true,
},
},
},
});
const suborders = await prisma.subOrder.findMany({
where: {
kitchenId: null,
order: {
date: tommorrow,
},
},
select: {
quantity: true,
product: {
select: {
id: true,
kitchens: {
select: {
id: true,
performancePoints: true,
},
},
kitchenDependentProperties: {
select: {
kitchenId: true,
productionPrice: true,
purchasePrice: true,
},
},
performancePoints: true,
prepTime: true,
},
},
},
});
Mendy
Mendy17mo ago
@yuval59 there’s something off with your setup. Drizzle has indeed deprecated this feature. You’re welcome to see for yourself: https://codesandbox.io/p/sandbox/beautiful-tharp-8z4s98?file=%2Flib%2Fdrizzle.ts%3A14%2C4
beautiful-tharp-8z4s98
CodeSandbox brings instant cloud development environments that keep you in flow.
Mendy
Mendy17mo ago
.
mr_pablo
mr_pablo17mo ago
@mendy.l odd, i am able to do this in 0.28.1
db.query.competitions.findMany({
with: {
matches: {
where: between(
schema.matches.kickOffUTC,
placeholder('startOfToday'),
placeholder('endOfToday'),
),
orderBy: asc(schema.matches.kickOffUTC),
limit: 1,
},
},
})
db.query.competitions.findMany({
with: {
matches: {
where: between(
schema.matches.kickOffUTC,
placeholder('startOfToday'),
placeholder('endOfToday'),
),
orderBy: asc(schema.matches.kickOffUTC),
limit: 1,
},
},
})
this 100% works with mysql that is The change states this code won't work
const usersWithPosts = await db.query.users.findMany({
where: (table, { sql }) => (sql`json_array_length(${table.posts}) > 0`),
with: {
posts: true,
},
});
const usersWithPosts = await db.query.users.findMany({
where: (table, { sql }) => (sql`json_array_length(${table.posts}) > 0`),
with: {
posts: true,
},
});
its the top level "where" using a related table column value that shouldn't work, nothing about "where" clauses in the nested table joins
Want results from more Discord servers?
Add your server