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

1

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)

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay