{"_id":"@bou-company/mongodb-pagination","_rev":"3-d5acd0f0ae074302cc78ca94c90a65fc","name":"@bou-company/mongodb-pagination","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"@bou-company/mongodb-pagination","version":"1.0.0","description":"Cursor-based pagination for MongoDB","license":"MIT","author":{"name":"bou-company"},"main":"dist/index.js","module":"dist/mongodb-cursor-pagination.esm.js","typings":"dist/index.d.ts","scripts":{"build":"tsdx build --tsconfig ./tsconfig.build.json","lint":"tsdx lint src test","lint:fix":"tsdx lint src test --fix","type-check":"tsc --noEmit","test":"jest --detectOpenHandles --config 'jest.json'"},"dependencies":{"base64-url":"2.3.3","bson":"4.7.0","lodash.get":"4.4.2","lodash.mapvalues":"4.6.0"},"peerDependencies":{"mongodb":"4.13.0"},"devDependencies":{"@commitlint/cli":"17.3.0","@commitlint/config-conventional":"17.3.0","@types/base64-url":"2.2.0","@types/fs-extra":"9.0.13","@types/jest":"29.2.4","@types/lodash.get":"4.4.7","@types/lodash.mapvalues":"4.6.7","fs-extra":"11.1.0","husky":"8.0.2","jest":"29.3.1","lint-staged":"13.1.0","mongodb":"4.13.0","mongodb-memory-server":"8.10.2","ts-jest":"29.0.3","tsdx":"0.14.1","tslib":"2.4.1","typescript":"4.9.4"},"gitHead":"1a42ecea879956c42999587a7faf6b5389a34636","_id":"@bou-company/mongodb-pagination@1.0.0","_nodeVersion":"16.16.0","_npmVersion":"8.11.0","dist":{"integrity":"sha512-X7ng7cMOqB95zPTjOd/v98TQpmoGVSX07eHb0kkhAp9ng4zWaChTKchcWlLJqE+qGwStE+m70Lbw2q0w0/BedA==","shasum":"9a4a2faa6e7cd89b1f54ee1d1c666953924cc513","tarball":"https://registry.npmjs.org/@bou-company/mongodb-pagination/-/mongodb-pagination-1.0.0.tgz","fileCount":23,"unpackedSize":153991,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCDMTgdtSKixi3Ysh4jBOsA0AqzAvlbvH0smj+tbFR1DAIhAMsCD2K/Vv0lJDzjIDv55YCQqO8MnPbPgKJautJy9SWy"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjvXzjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoMzw//ZEBGJvi8WSvcB5r/IHEAbiRqj/81n3so8w5FwxraTuzUL/cP\r\ni2J1Q/tC/mLuSsTlEuTuKd3PhZ5Tlol2wtL9VyndCctC2e7ZTyMEJfeDr94i\r\nZFSNdQtZvSKBtwAR0FldxyxSaitU9Gscxb1V/u9ymuES2hY/HWDsueBHbLx5\r\nv59TURuJ1VGsTVY9fd2NBSpFw753Q+P2KpOLoo7vmN6YJjGPUez5SAyhXkK6\r\nP8bif3dcF1FuMcVNonauH6zJ1LRtstuPVOgO0Y+DFhy/5YSxnuZYw/fWHTYa\r\nB+g3SXHfIPWIZQJv0W5ISsnMCkLPPZdmIAXF3tMoxpPxi7uiTfnH6rnZZ2VQ\r\nKnhZpbqriSR6dOj/+6fBnJYGFpLCJnegaYCb5UcJ4W+fNJqtMhjDQr17vPOi\r\nyuyVRZuv/CVX0yFcYwo8CJn77KynuP8X/J7eMm8c9dEK+mXJlQLEBYGNkQrl\r\nG91YEkq6MAkU8Z4hwh2D263vFBOvy7K5jMxlXqeOaOG+A9Yg7133fktjU/jf\r\n1qKC0sYwFP7xVt1i0SjoYPsyfcbrIlsg0MPvK3wVKnNqG2KfZrzp7pf2+QgG\r\nyX/UR7VQ1ELDZvmIKcD71inRGdplHnMwA7PLXHjGag2TVsiuDCRzRTBEnsiP\r\nKPAQhZkO0wOawcrN9yxdZth/sMgtw0WBp1s=\r\n=+YO5\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"dev_bou","email":"dev2@boucompany.com"},"directories":{},"maintainers":[{"name":"devbou","email":"dev@boucompany.com"},{"name":"dev_bou","email":"dev2@boucompany.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongodb-pagination_1.0.0_1673362659053_0.5488639331559229"},"_hasShrinkwrap":false},"1.0.1":{"name":"@bou-company/mongodb-pagination","version":"1.0.1","description":"Cursor-based pagination for MongoDB","license":"MIT","author":{"name":"bou-company"},"main":"dist/index.js","module":"dist/mongodb-cursor-pagination.esm.js","typings":"dist/index.d.ts","scripts":{"build":"tsdx build --tsconfig ./tsconfig.build.json","lint":"tsdx lint src test","lint:fix":"tsdx lint src test --fix","type-check":"tsc --noEmit","test":"jest --detectOpenHandles --config 'jest.json'"},"dependencies":{"base64-url":"2.3.3","bson":"4.7.0","lodash.get":"4.4.2","lodash.mapvalues":"4.6.0"},"peerDependencies":{"mongodb":"4.9.1"},"devDependencies":{"@commitlint/cli":"17.3.0","@commitlint/config-conventional":"17.3.0","@types/base64-url":"2.2.0","@types/fs-extra":"9.0.13","@types/jest":"29.2.4","@types/lodash.get":"4.4.7","@types/lodash.mapvalues":"4.6.7","fs-extra":"11.1.0","husky":"8.0.2","jest":"29.3.1","lint-staged":"13.1.0","mongodb":"4.9.1","mongodb-memory-server":"8.10.2","ts-jest":"29.0.3","tsdx":"0.14.1","tslib":"2.4.1","typescript":"4.9.4"},"gitHead":"f6dee32173e0029e856bcbf48af2fce6882098cb","_id":"@bou-company/mongodb-pagination@1.0.1","_nodeVersion":"16.16.0","_npmVersion":"8.11.0","dist":{"integrity":"sha512-VHcqc+9MIt18G6XxTdTB/wEOXFIoEveElj1cs4AfxC0xEuQIuqcX7jXqlANQKHuhExO798PDklXGFqXMF0O7vA==","shasum":"ab39fe33346046d1e00633f450d3bb62b5862a7e","tarball":"https://registry.npmjs.org/@bou-company/mongodb-pagination/-/mongodb-pagination-1.0.1.tgz","fileCount":23,"unpackedSize":153989,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTRWA5uupmlTGsEAJhAOi68Oe9oMybG+LWuQto+ysRPgIhAPmcadIwVpQKq2jxtCCFjP6L8MyIPH2aTDlk1/7jDs7c"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjvcxEACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpUFg/7BV6MlvatuXsTCJM+pKXJGGnzU1OHE8B6Yknk2jPx7UTny35l\r\n1FbyfP3TRnt5ADzS4wde+kI5KDv1Q/DCSKh/DS9Cdn4WM2RyFgVviULHmCid\r\nwctCE1MxCxyxP8dP6BJYOimktwy9s5ZaJwDG4b0M6pMW+oC6MgyGmo1JlvMW\r\nSxUG5mWaZF/3SmkkNjXp4AV2KBOBh8b2GPniXssBhrQJoc211xcBPEaVPVQo\r\nkQEXqp78KQgol+CtCiu5cO509QbkyyRngFvmTdYnWRzqMwtJdXQGrjHj6q/N\r\nS9gCynxfyv7QnHEXZvJZaZ59SBN8dI+JEvoBi4sU2mCO/2cjDzb3qICjOIGp\r\nkISDsFXk1azfsxstCVNzJQG5pXiAjLb1a97CV/A7612eigHJHHx7wtgnD7Kf\r\nGcQ1GSnOW1z0YdYBDpq5mr1P7gtYAmcPwONrP4rZB3/2KmA1jSRX77y4R7F7\r\nDhSj3Vc0gBvra2GyR41GUZj+0J5cvfgwhYJd+7sQV58wGSTe8XyPSMhB+Lnt\r\nIv4gg+0wGXedXPcFEL6K81qmyYe5VqxPc6W9qlHMpWh9Do2SE8gZNJooO0Sp\r\nklZxGmfgSEIDiRP1JJ+aelEAOzKL3NWFztUBTrBOhvg6BuMeA1Ubltx29wkr\r\ndi+C7KHXxr3MmP6V4sua75oxtS1HjSG8Li4=\r\n=qIu1\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"dev_bou","email":"dev2@boucompany.com"},"directories":{},"maintainers":[{"name":"devbou","email":"dev@boucompany.com"},{"name":"dev_bou","email":"dev2@boucompany.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongodb-pagination_1.0.1_1673382980460_0.3339688271994061"},"_hasShrinkwrap":false},"1.0.2":{"name":"@bou-company/mongodb-pagination","version":"1.0.2","description":"Cursor-based pagination for MongoDB","license":"MIT","author":{"name":"bou-company"},"main":"dist/index.js","module":"dist/mongodb-cursor-pagination.esm.js","typings":"dist/index.d.ts","scripts":{"build":"tsdx build --tsconfig ./tsconfig.build.json","lint":"tsdx lint src test","lint:fix":"tsdx lint src test --fix","type-check":"tsc --noEmit","test":"jest --detectOpenHandles --config 'jest.json'"},"dependencies":{"base64-url":"2.3.3","bson":"4.7.0","lodash.get":"4.4.2","lodash.mapvalues":"4.6.0"},"peerDependencies":{"mongodb":"4.9.1"},"devDependencies":{"@commitlint/cli":"17.3.0","@commitlint/config-conventional":"17.3.0","@types/base64-url":"2.2.0","@types/fs-extra":"9.0.13","@types/jest":"29.2.4","@types/lodash.get":"4.4.7","@types/lodash.mapvalues":"4.6.7","fs-extra":"11.1.0","husky":"8.0.2","jest":"29.3.1","lint-staged":"13.1.0","mongodb":"4.9.1","mongodb-memory-server":"8.10.2","ts-jest":"29.0.3","tsdx":"0.14.1","tslib":"2.4.1","typescript":"4.9.4"},"gitHead":"f6dee32173e0029e856bcbf48af2fce6882098cb","_id":"@bou-company/mongodb-pagination@1.0.2","_nodeVersion":"16.16.0","_npmVersion":"8.11.0","dist":{"integrity":"sha512-i+TQ8m7DrRYmnOXRlIuM6ua7HfctGfwb1CDwi3dh/Bd3AylIWD+t7kbxPUBVgiXrLE37/CM9F8mF1L/UrzxP7Q==","shasum":"c9f21cd9f8b75add0f9ff68bd89b793fe013df80","tarball":"https://registry.npmjs.org/@bou-company/mongodb-pagination/-/mongodb-pagination-1.0.2.tgz","fileCount":23,"unpackedSize":154070,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDeSGAZhjRB/b2mdsmhu6j7/GEl0G5ywKt/MyqcYIb3hAiEA4taX9FjmDarMXy8oXSy3QNAxh9wXe9PcKY6Yc3xOiv0="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjvdd2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqNZBAAiKKnbSQ+6Ah4Apgx+8GiJDd0AqDV/NWe6kb71NLanVck5yAo\r\nr0mi3rckgtHVpPyjH42VBa4fHuFzMOSSmHJgsjlzlLbutjGAUBoa93se3qDv\r\n2E2WC7TWxqbsSyGB49PgzjP8feo7X1A9q9HWDLkrOwJf4I39KotRBtgNjbTA\r\ntSK6N9k4aPk2yQlwVMEfmfU/vIS7nDVxMJiAGsFmiXzRwPCBR2b7Hd1hGv9M\r\nUW7RkBe3o4HHWRhbDP8v5rUgGaildovo9VvlsYVplfqJWgJ+x2hAWkrxk/Rn\r\nDp7WLzrbK+XyHcoUF01Qt3yvWtRECUQZLvZMJONyDk2yBXgnxZvGKw9CpLB5\r\nfKNd0pEoOI/iFbYG4sXhsTANA0RmkSynK3GLkWFL3xqa2KuDCGzLWk4aNQsh\r\nQgyqRUCIilT5JevEqM1A6R+eOZ1EaL2Hob/qWE/caWv73wSYWUHocknl7wd9\r\nO1Rj0J704KQ6aZPDrs8BCeWsPXzOstdpJyhkH4oThaZqBDS/mNgJT5tLY3Fa\r\nRTcOCUwt1mz/LeRMAWEaDSZ4KV+bz+38ZLbSW3Dt/kcpLczCWGxULayRPftL\r\nA/8dx0pRQ73bl0MADzP2Mv+iBBLO+jZBKz4vg36pfwgzdjaOrxJuivibFZq0\r\n6harc12RY7gOL+/BlNhjUC/76H1wP34YPAQ=\r\n=/omw\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"dev_bou","email":"dev2@boucompany.com"},"directories":{},"maintainers":[{"name":"devbou","email":"dev@boucompany.com"},{"name":"dev_bou","email":"dev2@boucompany.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/mongodb-pagination_1.0.2_1673385846666_0.17120396462140897"},"_hasShrinkwrap":false}},"time":{"created":"2023-01-10T14:57:38.961Z","1.0.0":"2023-01-10T14:57:39.222Z","modified":"2023-03-21T20:49:24.990Z","1.0.1":"2023-01-10T20:36:20.707Z","1.0.2":"2023-01-10T21:24:06.887Z"},"maintainers":[{"email":"dev4@boucompany.com","name":"diego10z"},{"email":"dev@boucompany.com","name":"devbou"},{"email":"dev2@boucompany.com","name":"dev_bou"}],"description":"Cursor-based pagination for MongoDB","author":{"name":"bou-company"},"license":"MIT","readme":"# [mongodb-cursor-pagination](<https://github.com/murshidazher/mongodb-cursor-pagination>) [![npm](https://img.shields.io/npm/v/mongodb-cursor-pagination.svg?label=&color=0080FF)](https://github.com/murshidazher/mongodb-cursor-pagination/releases/latest)\n\n![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/murshidazher/mongodb-cursor-pagination/release.yml?branch=master&style=flat-square)\n![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)\n\n> Cursor-based pagination for MongoDB.\n\nBased on [mongo-cursor-pagination](https://github.com/mixmaxhq/mongo-cursor-pagination) but written from scratch in TypeScript with an API that resembles the [cursor connection spec from Relay](https://facebook.github.io/relay/graphql/connections.htm).\n\n<!-- toc -->\n\n- [mongodb-cursor-pagination](#mongodb-cursor-pagination-)\n  - [The problem](#the-problem)\n  - [The solution](#the-solution)\n  - [Installation](#installation)\n  - [Usage](#usage)\n  - [API](#api)\n    - [`findPaginated`](#findpaginated)\n      - [Arguments](#arguments)\n      - [Returns](#returns)\n    - [`aggregatePaginated`](#aggregatepaginated)\n      - [Arguments](#arguments-1)\n      - [Returns](#returns-1)\n  - [License](#license)\n\n<!-- tocstop -->\n\n## The problem\n\nBy default, MongoDB allows us to paginate results with `limit` and `skip`. That's known as offset-based pagination. It's definitely the simplest way to paginate, but in some situations it's not very **stable**.\n\nImagine you have a restaurant software showing a list of orders paginated with `limit: 3` and `skip: 0`:\n\n- `{ _id: ObjectId, number: 53 }`\n- `{ _id: ObjectId, number: 52 }`\n- `{ _id: ObjectId, number: 51 }`\n\nNice, so far so good. Now, when you click the button to see the next page, here's what you'd expect to see (`limit: 3`, `skip: 3`):\n\n- `{ _id: ObjectId, number: 50 }`\n- `{ _id: ObjectId, number: 49 }`\n- `{ _id: ObjectId, number: 48 }`\n\nPretty reasonable, right? By using `skip: 3` we're basically telling MongoDB `hey, I want to skip orders #53, #52 and #51`.\n\n**But imagine a new order (#54) arrived while we were staring at the 1st page**. In that case, querying with `skip: 3` would actually give us:\n\n- `{ _id: ObjectId, number: 51 }`\n- `{ _id: ObjectId, number: 50 }`\n- `{ _id: ObjectId, number: 49 }`\n\nThat's because in this new scenario we're actually telling MongoDB `hey, I want to skip orders #54, #53 and #52`.\n\nIf you have any trouble to fully comprehend what's happening here, try to imagine the following scenario yourself:\n\n- You've queried the 1st page with `limit: 3` and `skip: 0`.\n- While you are looking at the 1st page, 200 new orders arrive.\n- What will you see when you try to query the 2nd page with `limit: 3` and `skip: 3`?\n\n## The solution\n\n**So how can we make sure that the 2nd page always start from the order #50** no matter how many orders have been received in the meantime? Well, a naive approach would be like:\n\n```ts\ncollection\n  .find({ number: { $lt: 51 } }\n  .sort({ number: -1 })\n  .toArray()\n```\n\nAnd that's somewhat what this lib does but in a much more robust way.\n\nFor a more thorough explanation I highly recommend reading the excellent [blog post from Mixmax](https://engineering.mixmax.com/blog/api-paging-built-the-right-way). You can also read the source code — I tried to add helpful comments.\n\n## Installation\n\n```sh\nnpm i mongodb-cursor-pagination\n```\n\n```sh\nyarn add mongodb-cursor-pagination\n```\n\n## Usage\n\n```ts\nimport { MongoClient } from 'mongodb'\nimport { findPaginated } from 'mongodb-cursor-pagination'\n\nconst client = await MongoClient.connect(uri)\nconst db = client.db()\nconst collection = db.collection('users')\n\nlet skipFirst20\n\n// Get third page\nskipFirst20 = await findPaginated(collection, {\n  first: 10,\n  skip: 20\n})\n\n\nlet result\n\n// Get first page\nresult = await findPaginated(collection, {\n  first: 10\n})\n\n// Go to second page\nresult = await findPaginated(collection, {\n  first: 10,\n  after: result.pageInfo.endCursor,\n})\n\n// Back to first page\nresult = await findPaginated(collection, {\n  last: 10,\n  before: result.pageInfo.startCursor,\n})\n```\n\n## API\n\n### `findPaginated`\n\nRuns a paginated query on top of `Collection#find`.\n\n#### Arguments\n\n- `collection`: The MongoDB collection.\n- `params`:\n  - Properties:\n    - `first`: How many documents to get (forwards pagination).\n    - `after`: The cursor (forwards pagination).\n    - `last`: How many documents to get (backwards pagination).\n    - `before`: The cursor (backwards pagination).\n    - `query`: The query to be passed to `Collection#find`.\n    - `sort`: The sort to be passed to `Collection#find`.\n    - `projection`: The projection to be passed to `Collection#find`.\n\n#### Returns\n\n- `edges`: An array with the contents of the page.\n  - Properties:\n    - `node`: The document.\n    - `cursor`: An opaque string pointing to this document in the context of this query. It can be passed to parameters `after` or `before` to get a page starting after or before this document.\n- `pageInfo`:\n  - Properties\n    - `startCursor`: The cursor of the first document in this page.\n    - `endCursor`: The cursor of the last document in this page.\n    - `hasPreviouPage`: Whether there's another page before this one.\n    - `hasNextPage`: Whether there's another page after this one.\n\n### `aggregatePaginated`\n\nRuns a paginated aggregation on top of `Collection#aggregate`.\n\n#### Arguments\n\n- `collection`: The MongoDB collection.\n- `params`:\n  - Properties:\n    - `first`: How many documents to get (forwards pagination).\n    - `after`: The cursor (forwards pagination).\n    - `last`: How many documents to get (backwards pagination).\n    - `before`: The cursor (backwards pagination).\n    - `pipeline`: The pipeline array to be passed to `Collection#aggregate`.\n    - `sort`: The sort to be passed to `Collection#aggregate`.\n\n#### Returns\n\n- `edges`: An array with the contents of the page.\n  - Properties:\n    - `node`: The document.\n    - `cursor`: An opaque string pointing to this document in the context of this query. It can be passed to parameters `after` or `before` to get a page starting after or before this document.\n- `pageInfo`:\n  - Properties\n    - `count`: The number of nodes fetched for current page.\n    - `totalCount`: The number of nodes available based on query.\n    - `startCursor`: The cursor of the first document in this page.\n    - `endCursor`: The cursor of the last document in this page.\n    - `hasPreviouPage`: Whether there's another page before this one.\n    - `hasNextPage`: Whether there's another page after this one.\n\n## License\n\nReleased under the [MIT License](./LICENSE.md).\n","readmeFilename":"README.md"}