Skip to content

Commit

Permalink
perf(core): improve backward pagination (#4653)
Browse files Browse the repository at this point in the history
* perf(core): improve backward pagination

* fix: last item removal in backward pagination
  • Loading branch information
dolcalmi authored Nov 8, 2024
1 parent 9ee29e6 commit f62641f
Showing 1 changed file with 34 additions and 27 deletions.
61 changes: 34 additions & 27 deletions core/api/src/services/ledger/paginated-ledger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { Types } from "mongoose"
import { parseFilterQuery } from "medici/build/helper/parse/parseFilterQuery"

import { MainBook } from "./books"

import { translateToLedgerTx } from "./translate"

import { Transaction } from "@/services/ledger/schema"
Expand All @@ -33,19 +32,8 @@ export const paginatedLedger = async ({
paginationArgs: PaginatedQueryArgs
}): Promise<Error | PaginatedQueryResult<LedgerTransaction<WalletCurrency>>> => {
const filterQuery = parseFilterQuery(filters.mediciFilters, MainBook)

const { first, last, before, after } = paginationArgs

filterQuery["_id"] = { $exists: true }

if (after) {
filterQuery["_id"] = { $lt: new Types.ObjectId(after) }
}

if (before) {
filterQuery["_id"] = { $gt: new Types.ObjectId(before) }
}

if (filters.username) {
filterQuery["username"] = filters.username
}
Expand All @@ -54,35 +42,54 @@ export const paginatedLedger = async ({
filterQuery["payee_addresses"] = { $in: filters.addresses }
}

const documentCount = await Transaction.countDocuments(filterQuery)

// hasPreviousPage and hasNextPage can default to false for the opposite pagination direction per the Connection spec
let hasPreviousPage = false
let hasNextPage = false
let hasPreviousPage = false
let transactionRecords: ILedgerTransaction[] = []

// Optimize for forward pagination (first/after)
if (first !== undefined) {
if (documentCount > first) {
hasNextPage = true
const query = { ...filterQuery }
if (after) {
query["_id"] = { $lt: new Types.ObjectId(after) }
}

// Fetch one extra record to determine if there are more pages
transactionRecords = await Transaction.collection
.find<ILedgerTransaction>(filterQuery)
.find<ILedgerTransaction>(query)
.sort({ _id: -1 })
.limit(first)
.limit(first + 1)
.toArray()
} else {
let skipAmount = 0
if (documentCount > last) {
hasPreviousPage = true
skipAmount = documentCount - last

if (transactionRecords.length > first) {
hasNextPage = true
transactionRecords = transactionRecords.slice(0, first)
}
}
// Optimize for backward pagination (last/before)
else if (last !== undefined) {
const query = { ...filterQuery }
if (before) {
query["_id"] = { $gt: new Types.ObjectId(before) }
}

// For backward pagination, we:
// 1. Sort in ascending order to get the oldest records first
// 2. Limit to last + 1 to check for previous page
// 3. Reverse the results to maintain consistent ordering
transactionRecords = await Transaction.collection
.find<ILedgerTransaction>(filterQuery)
.sort({ _id: -1 })
.skip(skipAmount)
.find<ILedgerTransaction>(query)
.sort({ _id: 1 })
.limit(last + 1)
.toArray()

if (transactionRecords.length > last) {
hasPreviousPage = true
transactionRecords = transactionRecords.slice(0, last) // Remove the extra record
}

// Reverse the results to maintain consistent ordering (newest first)
transactionRecords = transactionRecords.reverse()
}

const txs = transactionRecords.map((tx) => translateToLedgerTx(tx))
Expand Down

0 comments on commit f62641f

Please sign in to comment.