# @andrew_l/mongoose-cursor-paginator

> Pagination plugin for mongoose >= 6.x

Latest version **2.0.3** (published 2025-06-10) · ISC license · 0 weekly downloads

## Install

```sh
npm install @andrew_l/mongoose-cursor-paginator
pnpm add @andrew_l/mongoose-cursor-paginator
yarn add @andrew_l/mongoose-cursor-paginator
bun add @andrew_l/mongoose-cursor-paginator
```

## Health

**Score 40/100 (D)** — status: maintenance-mode.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

Negative: stale; low maintenance score.

## Facts

| | |
|---|---|
| Version | 2.0.3 |
| Published | 2025-06-10 |
| First published | 2020-10-22 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 3 |
| Unpacked size | 118.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 0 |
| Author | Andrew L. |
| Maintainers | andrew_l |

## Links

- npm: https://www.npmjs.com/package/@andrew_l/mongoose-cursor-paginator
- Repository: https://github.com/men232/mongoose-cursor-paginator
- Homepage: https://github.com/men232/mongoose-cursor-paginator#readme
- Issues: https://github.com/men232/mongoose-cursor-paginator/issues
- npm.io page: https://npm.io/package/@andrew_l/mongoose-cursor-paginator

## Dependencies (3)

- [crc](https://npm.io/package/crc.md) ^4.3.2
- [debug](https://npm.io/package/debug.md) ^4.1.1
- [clone-deep](https://npm.io/package/clone-deep.md) ^4.0.1

## Recent versions

- 2.0.3 (latest) — 2025-06-10
- 2.0.2 — 2024-08-30
- 2.0.1 — 2023-07-24
- 2.0.0 — 2023-07-24
- 1.0.3 — 2021-01-28
- 1.0.2 — 2021-01-27
- 1.0.1 — 2020-10-28
- 1.0.0 — 2020-10-22

## README

# Pagination plugin for mongoose >= 6.x <!-- omit in toc -->

![license](https://img.shields.io/npm/l/%40andrew_l%2Fmongoose-cursor-paginator) ![npm version](https://img.shields.io/npm/v/%40andrew_l%2Fmongoose-cursor-paginator)

## Installation

`npm i @andrew_l/mongoose-cursor-paginator`

```js
import mongoose from 'mongoose';
import { setupPlugin } from '@andrew_l/mongoose-cursor-paginator';

setupPlugin(mongoose);
```

## Usage examples

Simple search with catching filter & sort options of original mongoose query.

```js
// Fetch the first page
const firstPage = await Users.find({ role: 'admin' })
  .limit(10)
  .sort({ createdAt: -1 })
  .lean()
  .paginator();

console.log(firstPage);
/* {
  "metadata": {
    "hasNext": true,
    "next": "ldkkZjBhZTViZTQtNzRkNC00YzY2LWI2MWItYjMzYjE0NzQwODI4pFVzZXKBo19pZP-Bo19pZNkkZjBhZTViZTQtNzRkNC00YzY2LWI2MWItYjMzYjE0NzQwODI4gA"
  },
  "items": [
    { doc_1 },
    { doc_n },
    ...
    { doc_10 },
  ]
} */

const secondPage = await Users.find({ role: 'admin' })
  .limit(10)
  // sort can be overwrited by next token
  .sort({ createdAt: -1 })
  .lean()
  .paginator({ next: firstPage.metadata.next });

console.log(secondPage);
/* {
  "metadata": {
    "hasNext": false,
    "next": null
  },
  "items": [
    { doc_1 },
    { doc_2 },
    { doc_3 }
  ]
} */
```

## Advanced usage

```js
// Make query with some criteria
const firstPage = await searchUsers({
  role: 'admin',
});

// Now we can use only next token and keep the role filter from previous query
const secondPage = await searchUsers({
  next: firstPage.metadata.next,
});

function searchUsers(search) {
  const savedSearch = {};

  const paign = User.find()
    .lean()
    .sort({ status: 1, createdAt: -1, _id: 1 })
    .limit(50)
    .paginator({
      next: search.next,
      // Exclude `status` from pagination cursor.
      paginationFields: ['createdAt', '_id'],

      // Save search params into token payload
      preQuery() {
        this.nextToken.payload = savedSearch;
      },
    });

  // Use token payload as search params
  if (paign.previousToken?.payload) {
    search = paign.previousToken?.payload;
  }

  const filter = {};

  if (typeof search.role === 'string' && search.role) {
    // Save role for next query
    savedSearch.role = search.role;

    // Use role as filter condition
    filter.role = search.role;
  }

  // Update query filter
  paign.getQuery().setQuery(filter);

  return paign.exec();
}
```

## Stream example

```js
const query = await Users.find({ role: 'admin' });

const dbStream = await query.paginator.stream();

stream.on('data', console.log);
stream.on('end', () => {
  const metadata = query.paginator().getMetadata();

  console.log({ metadata });

  /* {
      "metadata": {
    	"hasNext": true,
    	"next": "ldkkZjBhZTViZTQtNzRkNC00YzY2LWI2MWItYjMzYjE0NzQwODI4pFVzZXKBo19pZP-Bo19pZNkkZjBhZTViZTQtNzRkNC00YzY2LWI2MWItYjMzYjE0NzQwODI4gA"
      }
    */
});
```

### Tips
- The last sorting key **must be uniq** & sortable (Number, ObjectId is perfect)

---
_Source: https://npm.io/package/@andrew_l/mongoose-cursor-paginator · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
