stevanfreeborn
stevanfreeborn17mo ago

Select or Project Method

Does convex have any built in for doing some sort of select statement or project method when querying? I see how I can make a query, collect the documents, and return them after mapping over the documents. But that doesn't really work if you want to use a paginated query. It seems like in this case you'd have to implement your own pagination in the query.
4 Replies
ballingt
ballingt17mo ago
You can modify, even filter pagination results before returning them! just unpack the results, replace the page, and return the expected type.
stevanfreeborn
stevanfreebornOP17mo ago
Oh I didn't know that. I'll explore that some. @ballingt how do you go about replacing the page though? The page is typed to the documents I queryed. If I want to map over them and just return a subset of fields and then replace the page with this array of objects it won't statisfy the expected type of the page.
export const getUsersPostById = query({
args: { userId: v.id('users'), paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
const posts = await ctx.db
.query('posts')
.withIndex('by_user_id', q => q.eq('userId', args.userId))
.order('desc')
.paginate(args.paginationOpts);

posts.page = posts.page.map(({ _id }) => _id);
return posts;
},
});
export const getUsersPostById = query({
args: { userId: v.id('users'), paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
const posts = await ctx.db
.query('posts')
.withIndex('by_user_id', q => q.eq('userId', args.userId))
.order('desc')
.paginate(args.paginationOpts);

posts.page = posts.page.map(({ _id }) => _id);
return posts;
},
});
Or do you just type the page like this?
const posts: PaginationResult<{ _creationTime: number}> = await ctx.db
.query('posts')
.withIndex('by_user_id', q => q.eq('userId', args.userId))
.order('desc')
.paginate(args.paginationOpts);

posts.page = posts.page.map(({ _creationTime }) => ({ _creationTime }));
return posts;
const posts: PaginationResult<{ _creationTime: number}> = await ctx.db
.query('posts')
.withIndex('by_user_id', q => q.eq('userId', args.userId))
.order('desc')
.paginate(args.paginationOpts);

posts.page = posts.page.map(({ _creationTime }) => ({ _creationTime }));
return posts;
Michal Srb
Michal Srb17mo ago
I personally prefer immutable style, it types better (and has other advantages):
export const getUsersPostById = query({
args: { userId: v.id('users'), paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
const posts = await ctx.db
.query('posts')
.withIndex('by_user_id', q => q.eq('userId', args.userId))
.order('desc')
.paginate(args.paginationOpts);
return {...posts, page: posts.page.map(({ _id }) => _id)};
},
});
export const getUsersPostById = query({
args: { userId: v.id('users'), paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
const posts = await ctx.db
.query('posts')
.withIndex('by_user_id', q => q.eq('userId', args.userId))
.order('desc')
.paginate(args.paginationOpts);
return {...posts, page: posts.page.map(({ _id }) => _id)};
},
});
We are lacking this example in the pagination docs, it's on our list to fix
stevanfreeborn
stevanfreebornOP17mo ago
Oh that is way cleaner. Okay perfect. Thank you both so much!

Did you find this page helpful?