Use case:
Sort by asc or desc
https://your-url?sort[first_name]=desc&sort[last_name]=asc
or, Sort by ascending / descending
https://your-url?sort[first_name]=ascending&sort[last_name]=descending
or, Sort by 1 / -1
https://your-url?sort[first_name]=1&sort[last_name]=-1
This function will help you to sort by using sortBy and sortOrder fields also.
https://your-url?sortOrder=desc&sortBy=last_name
Code for Typescript:
type ISortOrder = "asc" | "desc" | "ascending" | "descending" | 1 | -1;
export interface IPaginationFields {
page?: number;
limit?: number;
sortBy?: string;
sortOrder?: ISortOrder;
sort?: Record<string, ISortOrder>;
}
export interface IFormatedPagination {
skip: number;
page: number;
limit: number;
sort: { [key: string]: 1 | -1 };
}
export const formatPagination = (
pagination: IPaginationFields
): IFormatedPagination => {
const { limit = 10, page = 1, sortBy, sortOrder, sort } = pagination;
const formattedSort: { [key: string]: 1 | -1 } = {};
const formatOrder = (value: string | number) => {
const numValue = Number(value);
const isString = Number.isNaN(numValue);
if (!isString && (numValue === 1 || numValue === -1)) {
return numValue;
} else {
return value === "asc" || value === "ascending" ? 1 : -1;
}
};
if (sortBy) {
const sortByArr = Array.isArray(sortBy) ? sortBy : [sortBy];
const sortOrderArr = Array.isArray(sortOrder) ? sortOrder : [sortOrder];
sortByArr.forEach((field, index) => {
formattedSort[field] = formatOrder(sortOrderArr[index]);
});
}
if (!Array.isArray(sort) && typeof sort === "object") {
Object.keys(sort).forEach((field) => {
formattedSort[field] = formatOrder(sort[field]);
});
}
if (!formattedSort.createdAt) {
formattedSort.createdAt = -1;
}
return {
skip: (page - 1) * limit,
limit: Number(limit),
page: Number(page),
sort: formattedSort,
};
};
Code for javascript:
const formatPagination = (pagination) => {
const { limit = 10, page = 1, sortBy, sortOrder, sort } = pagination;
const formattedSort = {};
const formatOrder = (value) => {
const numValue = Number(value);
const isString = Number.isNaN(numValue);
if (!isString && (numValue === 1 || numValue === -1)) {
return numValue;
} else {
return value === "asc" || value === "ascending" ? 1 : -1;
}
};
if (sortBy) {
const sortByArr = Array.isArray(sortBy) ? sortBy : [sortBy];
const sortOrderArr = Array.isArray(sortOrder) ? sortOrder : [sortOrder];
sortByArr.forEach((field, index) => {
formattedSort[field] = formatOrder(sortOrderArr[index]);
});
}
if (!Array.isArray(sort) && typeof sort === "object") {
Object.keys(sort).forEach((field) => {
formattedSort[field] = formatOrder(sort[field]);
});
}
if (!formattedSort.createdAt) {
formattedSort.createdAt = -1;
}
return {
skip: (page - 1) * limit,
limit: Number(limit),
page: Number(page),
sort: formattedSort,
};
};
return formatPagination;
Overview
The code defines an interface for pagination and sorting fields, as well as a utility function to format these fields into a structure suitable for database queries or other pagination use cases. This utility helps in standardizing the pagination and sorting process.
Code Explanation
Interfaces
ISortOrder
- Represents the possible values for sorting order:
- Strings: "asc", "desc", "ascending", "descending" - Numbers: 1 (ascending), -1 (descending)
IPaginationFields
Describes the input structure for pagination and sorting:
page (optional): The current page number (default: 1).
limit (optional): The number of items per page (default: 10).
sortBy (optional): A field name (or an array of field names) to sort by.
sortOrder (optional): The sorting order(s) corresponding to sortBy.
sort (optional): An object where keys are field names and values are sort orders.
IFormatedPagination
Describes the output structure for formatted pagination:
skip: The number of items to skip (calculated as (page - 1) * limit).
page: The current page number.
limit: The number of items per page.
sort: A key-value pair of field names and their corresponding sort orders (1 or -1).
formatPagination Function
This function processes the input pagination object and converts it into a standardized format.
Parameters
- pagination: An object implementing the IPaginationFields interface.
Steps
Defaults
Destructures the pagination input and assigns default values to limit (10) and page (1).
Initializes an empty object formattedSort for storing the formatted sort fields.
Helper Function: formatOrder
Converts the given sorting order (value) into a numeric format (1 or -1):
If value is a number (1 or -1), it returns the number.
If value is a string (asc or ascending), it returns 1.
For desc or descending, it returns -1.
Process sortBy and sortOrder
Handles the case where sortBy and sortOrder are arrays or single values:
Converts them to arrays (if not already).
Iterates over the fields in sortBy and assigns their corresponding orders
from sortOrder (using formatOrder) to formattedSort.
Process sort Object
If sort is an object (and not an array), iterates over its keys:
Converts each key's value into a numeric order using formatOrder and adds it to formattedSort.
Default Sort Field
- If formattedSort does not include the createdAt field, adds it with a descending order (-1).
Return the Result
Returns an object with the following properties:
skip: Number of items to skip, calculated as (page - 1) * limit.
limit: The number of items per page.
page: The current page number.
sort: The processed sorting object.
const pagination: IPaginationFields = {
page: 2,
limit: 20,
sortBy: ['name', 'date'],
sortOrder: ['asc', 'desc'],
sort: { age: 1, score: -1 },
};
const formatted = formatPagination(pagination);
console.log(formatted);
/*
{
skip: 20,
limit: 20,
page: 2,
sort: {
name: 1,
date: -1,
age: 1,
score: -1,
createdAt: -1, // Default sort field
},
}
*/
Key Features
- Flexible Input: Handles single and array values for sortBy and sortOrder.
- Default Values: Ensures pagination works even with incomplete input.
- Default Sorting: Adds a fallback sort field (createdAt).
- Custom Sorting: Supports a sort object for complex sorting scenarios. This utility is ideal for applications that require standardized pagination and sorting, such as REST APIs or database queries
Top comments (0)