kstulgys
kstulgys2mo ago

Should I avoid this ent query?

This is an example from ents docs:
export const listTeamInvites = query({
args: { teamId: v.id("teams") },
async handler(ctx, { teamId }) {
return await ctx
.table("teams")
.getX(teamId)
.edge("invites")
.map(async (invite) => ({
_id: invite._id,
email: invite.email,
role: (await invite.edge("role")).name,
})); // `{ _id: Id<"invites">, email: string, role: string }[]`
},
});
export const listTeamInvites = query({
args: { teamId: v.id("teams") },
async handler(ctx, { teamId }) {
return await ctx
.table("teams")
.getX(teamId)
.edge("invites")
.map(async (invite) => ({
_id: invite._id,
email: invite.email,
role: (await invite.edge("role")).name,
})); // `{ _id: Id<"invites">, email: string, role: string }[]`
},
});
It's likely there are just a few roles so I guess it's fine but let's say there are many roles or let's say it's ever growing collection i.e "posts". Should I try to avoid this kind of query and doing i.e title: (await invite.edge("posts")).title My example might be silly with "posts" but just want to make a point and to understand if this is ok for larger collections then just "roles".
7 Replies
Convex Bot
Convex Bot2mo ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
kstulgys
kstulgysOP2mo ago
ok here is more concrete example that I'm working on:
export const remove = authMutation({
args: {},
handler: async (ctx, args) => {
// Get user account
const account = await ctx.table("accounts").getX(ctx.user.currentAccountId);

// Find unpaid receipts
const unpaidBillingReceipts = await account
.edge("billings")
.map(async (b) => {
const billingReceipt = await b.edge("billingReceipt").doc();
// This is unpaid billing because no billingReceipt record with data property
if (!billingReceipt?.data) return true;
})
.filter(Boolean);

// Do not delete account that has unpaid billing
if (unpaidBillingReceipts.length > 0) return { unpaid: true };

// Delete account ...
export const remove = authMutation({
args: {},
handler: async (ctx, args) => {
// Get user account
const account = await ctx.table("accounts").getX(ctx.user.currentAccountId);

// Find unpaid receipts
const unpaidBillingReceipts = await account
.edge("billings")
.map(async (b) => {
const billingReceipt = await b.edge("billingReceipt").doc();
// This is unpaid billing because no billingReceipt record with data property
if (!billingReceipt?.data) return true;
})
.filter(Boolean);

// Do not delete account that has unpaid billing
if (unpaidBillingReceipts.length > 0) return { unpaid: true };

// Delete account ...
This is my ents database relations:
billings: defineEnt({
// fields ...
})
.edge("account")
.edge("billingReceipt", { ref: true })
.edge("feeTier"),

billingReceipts: defineEnt({
// fields ...
}).edge("billing"),
billings: defineEnt({
// fields ...
})
.edge("account")
.edge("billingReceipt", { ref: true })
.edge("feeTier"),

billingReceipts: defineEnt({
// fields ...
}).edge("billing"),
I'm trying to understand if there is a better way todo this query or this is completely fine.
ballingt
ballingt2mo ago
What's your concern here, why might this not be fine?
kstulgys
kstulgysOP2mo ago
That "map" function that could potentially go through many records. I guess it's a special ".map" in convex right?
ballingt
ballingt2mo ago
Like Array.map, this really will run your callback function which fetches the billing receipt. But what's the concern with that? Even though these functions run in the database, fetching a document is always going to be slower than running a function like this. Backing up, what are you worried about here generally? The query being too slow? Going through many records is exactly what this code does, in order to return those records aka documents to the client. Adding a map isn't bad.
kstulgys
kstulgysOP2mo ago
Thanks for the response. I'm just generally thinking whether this is good/bad/can be better
erquhart
erquhart5w ago
Mapping over relations this way is best practice, whether using ents or not. The only concern would be if you anticipate returning too many documents within a single query, in which case you'll need to limit through something like .take() or .paginate(). I'm not certain whether ents .map() works in parallel, so maybe a performance improvement opportunity there. Not sure.

Did you find this page helpful?