DEV Community

Cover image for Multiple fields sorting with a time saving function for server side developer (api pagination)
Nurul Islam Rimon
Nurul Islam Rimon

Posted on

Multiple fields sorting with a time saving function for server side developer (api pagination)

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, }; }; 
Enter fullscreen mode Exit fullscreen mode

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; 
Enter fullscreen mode Exit fullscreen mode

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 }, } */ 
Enter fullscreen mode Exit fullscreen mode

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)