Sara
Sara•4w ago

while using pagination, I'm failing to sort the elements in the right order of creation

while using the pagination function with a bunch of messgaes, I'm giving them order("desc") so we can get the last numItems that have been added to the array, when I do so, after the second load, the element are re-ordered bottom up, how can I fix this in the best way possible with convex? I tried sorting with .sort((a,b)=>a._creationTime -b.creationTime) but that resorts them on the second load, (the loadMore function runs at the top of the page when the user scrolls all the way up, and I want to it to act like first 25 elements, second 25 elemnts, in order 🥲 )
5 Replies
Convex Bot
Convex Bot•4w 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!
ballingt
ballingt•4w ago
Could you show the code for this?
while using the pagination function with a bunch of messgaes, I'm giving them order("desc") so we can get the last numItems that have been added to the array, when I do so, after the second load, the element are re-ordered bottom up, how can I fix this in the best way possible with convex?
What's the second load, after calling loadMore a second time? Or when refreshing?
ballingt
ballingt•4w ago
You might be running into .sort() being something that modifies arrayes in place in JavaScript, if you want to sort without the side effect you'll want to make a copy of the array or use toSorted() on the client https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted
MDN Web Docs
Array.prototype.toSorted() - JavaScript | MDN
The toSorted() method of Array instances is the copying version of the sort() method. It returns a new array with the elements sorted in ascending order.
Sara
SaraOP•4w ago
of course, so My initial code looked something like this:
const results = await ctx.db
.query('directMessages')
.withIndex('by_directMessageChannelId', (q) =>
q.eq('directMessageChannelId', args.channelId),
)
.order("desc")
.paginate(args.paginationOpts)

// on my client after making a copy of the array
const sortMessages = [...messages].sort((a,b) => a._creationTime-b._creationTime)
const results = await ctx.db
.query('directMessages')
.withIndex('by_directMessageChannelId', (q) =>
q.eq('directMessageChannelId', args.channelId),
)
.order("desc")
.paginate(args.paginationOpts)

// on my client after making a copy of the array
const sortMessages = [...messages].sort((a,b) => a._creationTime-b._creationTime)
and I am passing in the paginated query on my client InitialNumberOfItems, I guess it was indeed the use of .sort immediately here, cause after I copied the array it seems to be correct, because now after the second load I don't see the messages in a reversed order. but, is there a way to make this work in my convex query? something like this maybe? https://stack.convex.dev/pagination#jump-to-a-location-and-scroll-up
Take Control of Pagination
Convex offers robust control over pagination with a powerful function, getPage, enabling complex edge cases. In this article, we go over how to use th...
sonandmjy
sonandmjy•3w ago
I'm did something similar before and it worked for me, mostly trusted convex to do the ordering for me but i did do some grouping in client side. This is my code if it helps
// client side
export function groupMessagesByDate(messages: TMessage[]) {
const groupMessages = messages.reduce(
(acc, message) => {
const date = dayjs(message._creationTime).format("YYYY-MM-DD");
if (!acc[date]) {
acc[date] = [];
}
acc[date].push(message);
return acc;
},
{} as Record<string, TMessage[]>,
);

const flattenedMessages = [];
const stickyIndexes = new Set<number>();
let currentIndex = 0;

for (const [date, msgs] of Object.entries(groupMessages).reverse()) {
stickyIndexes.add(currentIndex);
flattenedMessages.push(date);
currentIndex += 1;
flattenedMessages.push(...msgs.reverse());
currentIndex += msgs.length;
}

return { flattenedMessages, stickyIndexes };
}

function MyComponent() {
const { results, status, loadMore } = usePaginatedQuery(
api.messages.getMessagesByDestinationAndChannelId,
{
destinationId,
channelId,
order: "desc",
},
{
initialNumItems: 20,
},
);

const groupedMessages = useMemo(() => {
return results ? groupMessagesByDate(results) : undefined;
}, [results]);
...
}



// convex
...
ctx.db
.query("messages")
.withIndex("by_organizationId", (q) =>
q.eq("organizationId", ctx.user.defaultOrganizationId!),
)
.filter((q) => {
return q.and(
q.or(
...args.destinationIds.map((d) =>
q.eq(q.field("destinationId"), d),
),
),
q.neq(q.field("status.statusId"), messageStatusIds.scheduled),
);
})
.order(order)
.paginate(args.paginationOpts)
...
// client side
export function groupMessagesByDate(messages: TMessage[]) {
const groupMessages = messages.reduce(
(acc, message) => {
const date = dayjs(message._creationTime).format("YYYY-MM-DD");
if (!acc[date]) {
acc[date] = [];
}
acc[date].push(message);
return acc;
},
{} as Record<string, TMessage[]>,
);

const flattenedMessages = [];
const stickyIndexes = new Set<number>();
let currentIndex = 0;

for (const [date, msgs] of Object.entries(groupMessages).reverse()) {
stickyIndexes.add(currentIndex);
flattenedMessages.push(date);
currentIndex += 1;
flattenedMessages.push(...msgs.reverse());
currentIndex += msgs.length;
}

return { flattenedMessages, stickyIndexes };
}

function MyComponent() {
const { results, status, loadMore } = usePaginatedQuery(
api.messages.getMessagesByDestinationAndChannelId,
{
destinationId,
channelId,
order: "desc",
},
{
initialNumItems: 20,
},
);

const groupedMessages = useMemo(() => {
return results ? groupMessagesByDate(results) : undefined;
}, [results]);
...
}



// convex
...
ctx.db
.query("messages")
.withIndex("by_organizationId", (q) =>
q.eq("organizationId", ctx.user.defaultOrganizationId!),
)
.filter((q) => {
return q.and(
q.or(
...args.destinationIds.map((d) =>
q.eq(q.field("destinationId"), d),
),
),
q.neq(q.field("status.statusId"), messageStatusIds.scheduled),
);
})
.order(order)
.paginate(args.paginationOpts)
...

Did you find this page helpful?