ampp
ampp•2mo ago

Looping over tables with normalizeId?

I've looked all over at posted examples of normalizeId and all related posts and i can't figure out if there is any other way to get a proper runtime tableName that isn't saved in the db. Is there any real downside to this, no performance hit right? When looping through say 10 tables for the one that might have the id. I'd like to be clear what all the options are. I know ents doesn't have ctx.db.get(id) but i havent seen that done either. Working code:
export const testString = sessionQuery({
args: { id: v.id('dataPool') },
handler: async (ctx, args) => {
const dataPool = await ctx.table('dataPool').get(args.id)

const test = await queryIdString(ctx, dataPool.idUnionFieldOrString as string)

return test
},
})

async function queryIdString(ctx: SessionQueryCtx, idString: string) {
const tableNames = ['users', 'members', 'events']

const tableResults = await Promise.all(
tableNames.map(async (tableName) => {
const test = ctx.table(tableName as any).normalizeId(idString)
return test ? { tableName, test } : null
})
)
const result = tableResults.filter((result) => result !== null)

if (result.length === 0) {
return null
}

return ctx.table(result[0].tableName as any).get(result[0].test)
}
export const testString = sessionQuery({
args: { id: v.id('dataPool') },
handler: async (ctx, args) => {
const dataPool = await ctx.table('dataPool').get(args.id)

const test = await queryIdString(ctx, dataPool.idUnionFieldOrString as string)

return test
},
})

async function queryIdString(ctx: SessionQueryCtx, idString: string) {
const tableNames = ['users', 'members', 'events']

const tableResults = await Promise.all(
tableNames.map(async (tableName) => {
const test = ctx.table(tableName as any).normalizeId(idString)
return test ? { tableName, test } : null
})
)
const result = tableResults.filter((result) => result !== null)

if (result.length === 0) {
return null
}

return ctx.table(result[0].tableName as any).get(result[0].test)
}
5 Replies
Convex Bot
Convex Bot•2mo 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!
ampp
amppOP•2mo ago
Bump. Just curious if this is a intended use case or point me at a better way. Thanks!
ballingt
ballingt•2mo ago
Could you give more context? It sounds like you have an id and you've lost track of what table it's in. You'd like to find out which one. You're wondering about what all the different ways to do this are? Yeah one way is to await ctx.db.get(id) and take a look at it. Agree that another way to do this is to try every table it might be with ctx.db.normalizeId.
Is there any real downside to this, no performance hit right? When looping through say 10 tables for the one that might have the id.
Looping through 10 tables will take 10 times longer than looping through 1, but yeah still very fast. If you know you'll be doing this kind of thing, I'd create a new ID that includes the table name in it. e.g. create a random ID like user-1a2b3c4d, and use that instead of the Convex ID. Then add an index on that ID.
ampp
amppOP•2mo ago
Yeah, part of it is just understanding that storing the tablename is always the best choice in all cases. Sometimes i just don't want to store more data especially if its low value data already and may never be called upon 🙃 , or i'm just not sure the table its from. And i cant recall seeing anywhere how you get the table name from a ctx.db.get(id) I would assume if the id sent to normalizeId didn't at least match the first 3 characters it wouldn't bother actually checking the _id index A group of our tables are going to have a neural network like design so a huge amount of cross referencing from within and external. I think its apparent we need some sort of custom URL like implementation for paths of custom ids. A minimum of 3.
lee
lee•2mo ago
Yeah we recommend always knowing the table name for an id, either stored separately like v.object({id: v.string(), table: v.string()}) or implied like v.id("userId") or contained in the string like Tom suggested with user-1a42f. You can use normalizeId, it will work and will be efficient, but it might not continue working as we evolve our id format. For example, if the ID came from a different component or a different deployment, you might get unexpected results. Our examples use normalizeId, but only because db.get doesn't take in a table name (another thing I would like to change).