From 4a25bdb415a0c164c7adf2c6a882498ca156b0b6 Mon Sep 17 00:00:00 2001 From: Akalanka Perera Date: Tue, 23 Jul 2024 05:43:32 +0000 Subject: [PATCH] fix(#63): sorting with strings and arrays --- lib/mongoose-aggregate-paginate.js | 19 +++++--- lib/util/index.js | 3 ++ lib/util/sort.js | 35 +++++++++++++++ package-lock.json | 4 +- package.json | 2 +- tests/index.js | 72 ++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 lib/util/index.js create mode 100644 lib/util/sort.js diff --git a/lib/mongoose-aggregate-paginate.js b/lib/mongoose-aggregate-paginate.js index 5f35de3..5334126 100644 --- a/lib/mongoose-aggregate-paginate.js +++ b/lib/mongoose-aggregate-paginate.js @@ -6,6 +6,8 @@ * @returns {Promise} */ +const { parseSort } = require("./util"); + const defaultOptions = { customLabels: { totalDocs: "totalDocs", @@ -86,6 +88,7 @@ function aggregatePaginate(query, options, callback) { } const sort = options.sort; + const allowDiskUse = options.allowDiskUse || false; const isPaginationEnabled = options.pagination === false ? false : true; @@ -98,11 +101,13 @@ function aggregatePaginate(query, options, callback) { } if (sort) { - pipeline.push({ $sort: sort }); + pipeline.push({ $sort: parseSort(sort) }); } function constructPipelines() { - let cleanedPipeline = pipeline.filter((stage) => stage !== PREPAGINATION_PLACEHOLDER); + let cleanedPipeline = pipeline.filter( + (stage) => stage !== PREPAGINATION_PLACEHOLDER + ); const countPipeline = [...cleanedPipeline, { $count: "count" }]; @@ -122,7 +127,6 @@ function aggregatePaginate(query, options, callback) { return [cleanedPipeline, countPipeline]; } - let promise; if (options.useFacet && !options.countQuery) { let [pipeline, countPipeline] = constructPipelines(); @@ -135,14 +139,15 @@ function aggregatePaginate(query, options, callback) { promise = q .facet({ docs: pipeline, - count: countPipeline + count: countPipeline, }) .then(([{ docs, count }]) => [docs, count]); } else { - const [pipeline] = constructPipelines(); - const countQuery = options.countQuery ? options.countQuery : this.aggregate(pipeline); + const countQuery = options.countQuery + ? options.countQuery + : this.aggregate(pipeline); if (allowDiskUse) { countQuery.allowDiskUse(true); @@ -236,4 +241,4 @@ function aggregatePaginate(query, options, callback) { module.exports = aggregatePaginate; -module.exports.PREPAGINATION_PLACEHOLDER = PREPAGINATION_PLACEHOLDER; \ No newline at end of file +module.exports.PREPAGINATION_PLACEHOLDER = PREPAGINATION_PLACEHOLDER; diff --git a/lib/util/index.js b/lib/util/index.js new file mode 100644 index 0000000..b86a8bf --- /dev/null +++ b/lib/util/index.js @@ -0,0 +1,3 @@ +module.exports = { + ...require("./sort"), +}; diff --git a/lib/util/sort.js b/lib/util/sort.js new file mode 100644 index 0000000..a81a504 --- /dev/null +++ b/lib/util/sort.js @@ -0,0 +1,35 @@ +function convertSortStringToObject(str) { + const sortObject = {}; + str.split(" ").forEach((field) => { + if (field.startsWith("-")) { + sortObject[field.substring(1)] = -1; + } else { + sortObject[field] = 1; + } + }); + return sortObject; +} + +function convertSortArrayToObject(arr) { + const sortObject = {}; + arr.forEach(([field, direction]) => { + sortObject[field] = direction === "asc" || direction === 1 ? 1 : -1; + }); + return sortObject; +} + +function parseSort(sort) { + if (typeof sort === "string") { + return convertSortStringToObject(sort); + } + if (Array.isArray(sort)) { + return convertSortArrayToObject(sort); + } + const sortObject = {}; + for (const [field, direction] of Object.entries(sort)) { + sortObject[field] = direction === "asc" || direction === 1 ? 1 : -1; + } + return sortObject; +} + +exports.parseSort = parseSort; diff --git a/package-lock.json b/package-lock.json index 1382a88..4b30951 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mongoose-aggregate-paginate-v2", - "version": "1.1.0", + "version": "1.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mongoose-aggregate-paginate-v2", - "version": "1.1.0", + "version": "1.1.2", "license": "MIT", "devDependencies": { "@babel/cli": "^7.12.1", diff --git a/package.json b/package.json index 2f41724..8dea343 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mongoose-aggregate-paginate-v2", - "version": "1.1.1", + "version": "1.1.2", "description": "A cursor based custom aggregate pagination library for Mongoose with customizable labels.", "main": "index.js", "types": "types/index.d.ts", diff --git a/tests/index.js b/tests/index.js index 02b9776..81e0746 100644 --- a/tests/index.js +++ b/tests/index.js @@ -269,6 +269,78 @@ describe("mongoose-paginate", function () { }); }); + describe("sorting", function () { + var aggregate = Book.aggregate([ + { + $match: { + title: { + $in: [/Book/i], + }, + }, + }, + ]); + it("with object ascending", function () { + return Book.aggregatePaginate(aggregate, { + sort: { date: "asc" }, + limit: 40, + }).then((result) => { + expect(result.docs).to.have.length(40); + expect(result.docs[0].title).to.equal("Book #1"); + expect(result.docs[result.docs.length - 1].title).to.equal("Book #40"); + }); + }); + it("with object descending", function () { + return Book.aggregatePaginate(aggregate, { + sort: { date: -1 }, + limit: 50, + }).then((result) => { + expect(result.docs).to.have.length(50); + expect(result.docs[0].title).to.equal("Book #100"); + expect(result.docs[result.docs.length - 1].title).to.equal("Book #51"); + }); + }); + it("with string ascending", function () { + return Book.aggregatePaginate(aggregate, { + sort: "date", + limit: 10, + }).then((result) => { + expect(result.docs).to.have.length(10); + expect(result.docs[0].title).to.equal("Book #1"); + expect(result.docs[result.docs.length - 1].title).to.equal("Book #10"); + }); + }); + it("with string descending", function () { + return Book.aggregatePaginate(aggregate, { + sort: "-date", + limit: 10, + }).then((result) => { + expect(result.docs).to.have.length(10); + expect(result.docs[0].title).to.equal("Book #100"); + expect(result.docs[result.docs.length - 1].title).to.equal("Book #91"); + }); + }); + it("with array ascending", function () { + return Book.aggregatePaginate(aggregate, { + sort: [["date", "asc"]], + limit: 10, + }).then((result) => { + expect(result.docs).to.have.length(10); + expect(result.docs[0].title).to.equal("Book #1"); + expect(result.docs[result.docs.length - 1].title).to.equal("Book #10"); + }); + }); + it("with array descending", function () { + return Book.aggregatePaginate(aggregate, { + sort: [["date", "desc"]], + limit: 10, + }).then((result) => { + expect(result.docs).to.have.length(10); + expect(result.docs[0].title).to.equal("Book #100"); + expect(result.docs[result.docs.length - 1].title).to.equal("Book #91"); + }); + }); + }); + after(async function () { await mongoose.connection.db.dropDatabase(); });