Rune Darkfire
Rune Darkfire5mo ago

How to return a custom list with extra key-value pair(s)?

I am trying to return list from my table "riskAssessments" but with an extra key-value pair on each element to add in the value of a subquery :
export const listWithVendorNames = query({
handler: async (ctx) => {
const assessments = await ctx.db.query("riskAssessments").collect()
let assessmentsWithVendorNames = []

assessments.forEach(async (assessment) => {
assessmentsWithVendorNames.push({ ...assessment, vendorName: await getVendorName(ctx, assessment.vendorId ?? null) })
})
return assessmentsWithVendorNames
},
})

...

async function getVendorName(ctx: QueryCtx, vendorId: Id<"vendors"> | null) {
if (vendorId === null) {
return null
}
return (await ctx.db.get(vendorId))?.name;
}
export const listWithVendorNames = query({
handler: async (ctx) => {
const assessments = await ctx.db.query("riskAssessments").collect()
let assessmentsWithVendorNames = []

assessments.forEach(async (assessment) => {
assessmentsWithVendorNames.push({ ...assessment, vendorName: await getVendorName(ctx, assessment.vendorId ?? null) })
})
return assessmentsWithVendorNames
},
})

...

async function getVendorName(ctx: QueryCtx, vendorId: Id<"vendors"> | null) {
if (vendorId === null) {
return null
}
return (await ctx.db.get(vendorId))?.name;
}
I know that the subquery works because I use it in my getById query which returns a single entry. The basic list query I've defined also returns the correct result. Because there's no way (seemingly?) to step through the .ts file code on my browser dev-tools, I have no idea where it is going wrong, but it is simply returning an empty array instead of what I want. I'm sorry if this is the wrong place to put this question - this is the only place I've been able to find. Thanks for reading! EDIT : I had to add the --typecheck=disable flag to get convex to run, as I'm using TS.
2 Replies
alixi
alixi5mo ago
It looks like the listWithVendorNames handler might be returning assessmentsWithVendorNames before any of the async functions execute You can rewrite the forEach as
await Promise.all(assessments.map(async (assessment) => {
assessmentsWithVendorNames.push({ ...assessment, vendorName: await getVendorName(ctx, assessment.vendorId ?? null) })
}))
await Promise.all(assessments.map(async (assessment) => {
assessmentsWithVendorNames.push({ ...assessment, vendorName: await getVendorName(ctx, assessment.vendorId ?? null) })
}))
which will wait for all the subqueries to finish executing You can also write it as a for loop (which I slightly prefer since it's more legible):
for (const assessment of assessments) {
assessmentsWithVendorNames.push({ ...assessment, vendorName: await getVendorName(ctx, assessment.vendorId ?? null) });
}
for (const assessment of assessments) {
assessmentsWithVendorNames.push({ ...assessment, vendorName: await getVendorName(ctx, assessment.vendorId ?? null) });
}
Rune Darkfire
Rune DarkfireOP5mo ago
@alixi thanks so much, I was going crazy trying to figure out what was up.

Did you find this page helpful?