oscklm
oscklm16mo ago

"expand" a field on a document, that is array of ids?

I'm trying to figure out if there is a easy way to go about this? My video table:
export const videoValidator = {
title: v.string(),
description: v.optional(v.string()),
tags: v.optional(v.string()),
category: v.optional(v.string()),
views: v.number(),
likesCount: v.number(),
likes: v.optional(v.array(v.id('likes'))),
visibility: v.string(),
tasks: v.optional(v.array(v.id('tasks'))),
muxAssetId: v.optional(v.string()),
muxMetaData: muxMetaDataValidator,
};
export const videoValidator = {
title: v.string(),
description: v.optional(v.string()),
tags: v.optional(v.string()),
category: v.optional(v.string()),
views: v.number(),
likesCount: v.number(),
likes: v.optional(v.array(v.id('likes'))),
visibility: v.string(),
tasks: v.optional(v.array(v.id('tasks'))),
muxAssetId: v.optional(v.string()),
muxMetaData: muxMetaDataValidator,
};
And i'm wondering how to best get the tasks, when i query a video that gets displayed in a detailed view in my app, where i then pass the tasks to a component that renders them in a list below the video. What i'm doing right now:
export const getOneVideoWithTasks = query({
args: { id: v.id('videos') },
handler: async (ctx, args) => {
const video = await ctx.db.get(args.id);
const tasks = await ctx.db
.query('tasks')
.withIndex('by_video', (q) => q.eq('videoId', args.id))
.order('desc')
.take(10);
return {
...video,
tasks,
};
},
});
export const getOneVideoWithTasks = query({
args: { id: v.id('videos') },
handler: async (ctx, args) => {
const video = await ctx.db.get(args.id);
const tasks = await ctx.db
.query('tasks')
.withIndex('by_video', (q) => q.eq('videoId', args.id))
.order('desc')
.take(10);
return {
...video,
tasks,
};
},
});
The relation and setup i'm after here: A video can have many tasks, but a task does not store a specific video id, like its doing right now. And when i then query a video i want to be able to 'expand' the tasks off the video and get their data and not only their ids
9 Replies
erquhart
erquhart16mo ago
I read somewhere from the Convex team (can't find at the moment) that they recommend limiting nesting only if you expect a small number of values, eg., 10 or so I think. Is there a reason you don't want to keep tasks and likes in their own tables and give each document a videoId?
oscklm
oscklmOP16mo ago
My tasks and likes is already stored in their own table. I think you might have misunderstood my post and the code snippets, or maybe i failed to make myself clear enough. I'm trying to figure out how i would best get the data from the related tasks to a video, when querying the video. In some ORM's u can expand a field that holds relations, so i was wondering if something like that was possible here. What i could do, is looping over the task ids i have on a video, and then querying them 1 by 1, pushing those that match the ids into an array, and then returning that with the video. But unsure whether there is a smarter way to do it
erquhart
erquhart16mo ago
That's exactly it, except you can do it concurrently and let Convex take care of how the concurrency is actually handled:
const relatedTasks = await Promise.all(taskIds.map(taskId => {
return await db.get(taskId)
}))
const relatedTasks = await Promise.all(taskIds.map(taskId => {
return await db.get(taskId)
}))
They have helpers for this too, but underneath I'm pretty sure it's just doing this
oscklm
oscklmOP16mo ago
Ohh that's interesting. Didn't think about that. Yeah i can see what you mean I'll try this out. Thanks!
erquhart
erquhart16mo ago
There's the helper you'd need, which actually does do something super obvious and simple - get all tasks by id, using an index on the id field of the task table I think that's where I'm confused, why do you have a list of task ids stored with each video rather than storing the video id on the task? Can one task be related to multiple videos?
oscklm
oscklmOP16mo ago
Ohh... yeah i see that is def obvious and simple hahah So as of right now, different tasks might be related to mutiple videos yeah
erquhart
erquhart16mo ago
okay, so then that helper won't work if you don't have videoId on the tasks table without knowing more, using Promise.all() would be my recommendation
oscklm
oscklmOP16mo ago
Yeah, that's what i will go with for now. Does the job

Did you find this page helpful?