GithubHelp home page GithubHelp logo

aravindnc / mongoose-paginate-v2 Goto Github PK

View Code? Open in Web Editor NEW
492.0 3.0 91.0 1.18 MB

A custom pagination library for Mongoose with customizable labels.

Home Page: https://www.npmjs.com/package/mongoose-paginate-v2

License: MIT License

JavaScript 100.00%
pagination paginate paging next prev nextpage prevpage total paginator mongoose

mongoose-paginate-v2's Introduction

Banner

mongoose-paginate-v2

npm version Build Status contributions welcome Downloads FOSSA Status GitHub commit activity npms.io npms.io

A custom pagination library for Mongoose with customizable labels.

If you are looking for aggregate query pagination, use this one mongoose-aggregate-paginate-v2

NPM

Why This Plugin

mongoose-paginate-v2 is a pagination library having a page wrapper. The main usage of the plugin is you can alter the return value keys directly in the query itself so that you don't need any extra code for transformation. The initial idea of this plugin is loosely based on mongoose-paginate package by github.com/edwardhotchkiss/. So this can be considered as an upgraded version of mongoose-paginate with much more options.

The below documentation is not perfect. Feel free to contribute. :)

Installation

npm install mongoose-paginate-v2

Usage

Add plugin to a schema and then use model paginate method:

const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');

const mySchema = new mongoose.Schema({
  /* your schema definition */
});

mySchema.plugin(mongoosePaginate);

const myModel = mongoose.model('SampleModel', mySchema);

myModel.paginate().then({}); // Usage

Typescript

Prior to version 1.5.0, types need to be installed from DefinitelyTyped.

To declare a PaginateModel in your Typescript files:

import mongoose from 'mongoose';
import paginate from 'mongoose-paginate-v2';

// declare your schema
export const institutionSchema = new mongoose.Schema({ name: String });

// paginate with this plugin
institutionSchema.plugin(paginate);

// declare a mongoose document based on a Typescript interface representing your schema
interface InstitutionDocument extends mongoose.Document, InstitutionData {}

// create the paginated model
const model = mongoose.model<
  InstitutionDocument,
  mongoose.PaginateModel<InstitutionDocument>
>('Institutions', institutionSchema, 'institutions');

Model.paginate([query], [options], [callback])

Returns promise

Parameters

  • [query] {Object} - Query criteria. Documentation

  • [options] {Object}

    • [select] {Object | String} - Fields to return (by default returns all fields). Documentation
    • [collation] {Object} - Specify the collation Documentation
    • [sort] {Object | String} - Sort order. Documentation
    • [populate] {Array | Object | String} - Paths which should be populated with other documents. Documentation
    • [projection] {String | Object} - Get/set the query projection. Documentation
    • [lean=false] {Boolean} - Should return plain javascript objects instead of Mongoose documents? Documentation
    • [leanWithId=true] {Boolean} - If lean and leanWithId are true, adds id field with string representation of _id to every document
    • [offset=0] {Number} - Use offset or page to set skip position
    • [page=1] {Number}
    • [limit=10] {Number}
    • [customLabels] {Object} - Developers can provide custom labels for manipulating the response data.
    • [pagination] {Boolean} - If pagination is set to false, it will return all docs without adding limit condition. (Default: True)
    • [useEstimatedCount] {Boolean} - Enable estimatedDocumentCount for larger datasets. Does not count based on given query, so the count will match entire collection size. (Default: False)
    • [useCustomCountFn] {Boolean} - Enable custom function for count datasets. (Default: False)
    • [forceCountFn] {Boolean} - Set this to true, if you need to support $geo queries. (Default: False)
    • [customFind] {String} - Method name for the find method which called from Model object. This options can be used to change default behaviour for pagination in case of different use cases (like mongoose-soft-delete). (Default 'find')
    • [allowDiskUse] {Boolean} - Set this to true, which allows the MongoDB server to use more than 100 MB for query. This option can let you work around QueryExceededMemoryLimitNoDiskUseAllowed errors from the MongoDB server. (Default: False)
    • [read] {Object} - Determines the MongoDB nodes from which to read. Below are the available options.
      • [pref]: One of the listed preference options or aliases.
      • [tags]: Optional tags for this query. (Must be used with [pref])
    • [options] {Object} - Options passed to Mongoose's find() function. Documentation
  • [callback(err, result)] - If specified, the callback is called once pagination results are retrieved or when an error has occurred

Return value

Promise fulfilled with object having properties:

  • docs {Array} - Array of documents
  • totalDocs {Number} - Total number of documents in collection that match a query
  • limit {Number} - Limit that was used
  • hasPrevPage {Bool} - Availability of prev page.
  • hasNextPage {Bool} - Availability of next page.
  • page {Number} - Current page number
  • totalPages {Number} - Total number of pages.
  • offset {Number} - Only if specified or default page/offset values were used
  • prevPage {Number} - Previous page number if available or NULL
  • nextPage {Number} - Next page number if available or NULL
  • pagingCounter {Number} - The starting index/serial/chronological number of first document in current page. (Eg: if page=2 and limit=10, then pagingCounter will be 11)
  • meta {Object} - Object of pagination meta data (Default false).

Please note that the above properties can be renamed by setting customLabels attribute.

Sample Usage

Return first 10 documents from 100

const options = {
  page: 1,
  limit: 10,
  collation: {
    locale: 'en',
  },
};

Model.paginate({}, options, function (err, result) {
  // result.docs
  // result.totalDocs = 100
  // result.limit = 10
  // result.page = 1
  // result.totalPages = 10
  // result.hasNextPage = true
  // result.nextPage = 2
  // result.hasPrevPage = false
  // result.prevPage = null
  // result.pagingCounter = 1
});

With custom return labels

Now developers can specify the return field names if they want. Below are the list of attributes whose name can be changed.

  • totalDocs
  • docs
  • limit
  • page
  • nextPage
  • prevPage
  • hasNextPage
  • hasPrevPage
  • totalPages
  • pagingCounter
  • meta

You should pass the names of the properties you wish to changes using customLabels object in options. Set the property to false to remove it from the result. Same query with custom labels

const myCustomLabels = {
  totalDocs: 'itemCount',
  docs: 'itemsList',
  limit: 'perPage',
  page: 'currentPage',
  nextPage: 'next',
  prevPage: 'prev',
  totalPages: 'pageCount',
  pagingCounter: 'slNo',
  meta: 'paginator',
};

const options = {
  page: 1,
  limit: 10,
  customLabels: myCustomLabels,
};

Model.paginate({}, options, function (err, result) {
  // result.itemsList [here docs become itemsList]
  // result.paginator.itemCount = 100 [here totalDocs becomes itemCount]
  // result.paginator.perPage = 10 [here limit becomes perPage]
  // result.paginator.currentPage = 1 [here page becomes currentPage]
  // result.paginator.pageCount = 10 [here totalPages becomes pageCount]
  // result.paginator.next = 2 [here nextPage becomes next]
  // result.paginator.prev = null [here prevPage becomes prev]
  // result.paginator.slNo = 1 [here pagingCounter becomes slNo]
  // result.paginator.hasNextPage = true
  // result.paginator.hasPrevPage = false
});

Use helper-class for passing query object into Model.paginate()

For conveniently passing on all request query parameters into paginate(), without having to specify them all in the controller, you can use the PaginationParameters-class. The example below is with express.js code, but can be applied to any request, where the query string has been parsed into an object.

const { PaginationParameters } = require('mongoose-paginate-v2');

// req.query = {
//   page: 1,
//   limit: 10,
//   query: {"color": "blue", "published": true}
//   projection: {"color": 1}
// }

req.get('/route', (req, res) => {
  Model.paginate(...new PaginationParameters(req).get()).then((result) => {
    // process the paginated result.
  });

  console.log(new PaginationParameters(req).get()); // [{ color: "blue", published: true }, { page: 1, limit: 10, projection: { color: 1 } }]
});

Note: req.query.projection and req.query.query have to be valid JSON. The same goes for any option which is passed into Model.paginate() as an array or object.

Other Examples

Using offset and limit:

Model.paginate({}, { offset: 30, limit: 10 }, function (err, result) {
  // result.docs
  // result.totalPages
  // result.limit - 10
  // result.offset - 30
});

With promise:

Model.paginate({}, { offset: 30, limit: 10 }).then(function (result) {
  // ...
});

More advanced example

var query = {};
var options = {
  select: 'title date author',
  sort: { date: -1 },
  populate: 'author',
  lean: true,
  offset: 20,
  limit: 10,
};

Book.paginate(query, options).then(function (result) {
  // ...
});

Zero limit

You can use limit=0 to get only metadata:

Model.paginate({}, { limit: 0 }).then(function (result) {
  // result.docs - empty array
  // result.totalDocs
  // result.limit - 0
});

Set custom default options for all queries

config.js:

var mongoosePaginate = require('mongoose-paginate-v2');

mongoosePaginate.paginate.options = {
  lean: true,
  limit: 20,
};

controller.js:

Model.paginate().then(function (result) {
  // result.docs - array of plain javascript objects
  // result.limit - 20
});

Fetch all docs without pagination

If you need to fetch all the documents in the collection without applying a limit. Then set pagination as false,

const options = {
  pagination: false,
};

Model.paginate({}, options, function (err, result) {
  // result.docs
  // result.totalDocs = 100
  // result.limit = 100
  // result.page = 1
  // result.totalPages = 1
  // result.hasNextPage = false
  // result.nextPage = null
  // result.hasPrevPage = false
  // result.prevPage = null
  // result.pagingCounter = 1
});

Using custom count function

If you need to use your own custom count function, then set useCustomCountFn as your custom count function. Make sure the function is returning count as a promise.

const options = {
  useCustomCountFn: function () {
    return Promise.resolve(100);
  },
};

Model.paginate({}, options, function (err, result) {
  // result.docs
});

Setting read preference

Determines the MongoDB nodes from which to read.

const options = {
  lean: true,
  limit: 10,
  page: 1,
  read: {
    pref: 'secondary',
    tags: [
      {
        region: 'South',
      },
    ],
  },
};

Model.paginate({}, options, function (err, result) {
  // Result
});

Pagination for Sub-Documents

If you want to paginate your sub-documents, here is the method you can use.

var query = { name: 'John' };
var option = {
  select: 'name follower',
  pagingOptions: {
    // your populate option
    populate: {
      path: 'follower',
    },
    page: 2,
    limit: 10,
  },
};

// Only one document (which object key with name John) will be return
const result = await Book.paginateSubDocs(query, option);

AllowDiskUse for large datasets

Sets the allowDiskUse option, which allows the MongoDB server to use more than 100 MB for query. This option can let you work around QueryExceededMemoryLimitNoDiskUseAllowed errors from the MongoDB server.

Note that this option requires MongoDB server >= 4.4. Setting this option is a no-op for MongoDB 4.2 and earlier.

const options = {
  limit: 10,
  page: 1,
  allowDiskUse: true,
};

Model.paginate({}, options, function (err, result) {
  // Result
});

Below are some references to understand more about preferences,

Known Issues

For Mongoose < 6.0.0

There are few operators that this plugin does not support natively, below are the list and suggested replacements.

  • $where: $expr
  • $near: $geoWithin with $center
  • $nearSphere: $geoWithin with $centerSphere

But we have added another option. So if you need to use $near and $nearSphere please set forceCountFn as true and try running the query.

const options = {
  lean: true,
  limit: 10,
  page: 1,
  forceCountFn: true,
};

Model.paginate({}, options, function (err, result) {
  // Result
});

For Mongoose > 6.0.0

$geoNear, $near, and $nearSphere may not work (Untested). This will be updated in the future plugin versions.

Development

  • Ensure all tests pass before you commit by running npm run test. In order to run the tests, you need to have the Mongo Deamon running locally.
  • There are pre-commit hooks that run to ensure the files you've changed are formatted correctly.
  • Optionally you can manually run npm run lint && npm run prettier to lint and format every relevant file
  • If using VS Code, install eslint and prettier for easy editor integration.

Changelog

View Changelog

License

MIT

mongoose-paginate-v2's People

Contributors

a-jaouen avatar aravindnc avatar brianpham93 avatar chazepps avatar chdanielmueller avatar daniel-tucano avatar david2dia avatar dependabot[bot] avatar eronmmer avatar fdorantesm avatar fernandolguevara avatar fossabot avatar gabrielgasp avatar igor-lkm avatar jaysalvat avatar kerolloz avatar lau1944 avatar louisnow avatar mauriciohernancabrera avatar molcay avatar oltsupport-icp avatar orgads avatar orimdominic avatar ridvanaltun avatar seitk avatar skyatura avatar tomosterlund avatar vkarpov15 avatar vrufine avatar ypicard avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

mongoose-paginate-v2's Issues

Confused - is this cursor-based, or page-based?

Is there a succinct explanation of how this package works? It looks like this is a page-based wrapper around cursor pagination, but aside from the first line of the readme there is no mention of cursors. I'm just looking for a one-paragraph explanation about how this works and why it's better.

Typescript definition

First of all: thanks for your fork of the original plugin. Being able to change the returned key names is very handy indeed.

I also needed an extended typescript definition, so I've updated the original file (this one).

I'm not sure if I covererd everything though, and did not want to publish it without your approval anyway, so here's the modified file (or a patch if you like).

The returned object is a bit problematic since afaik there's no way to couple its key names to the custom labels, so I've changed it to allow any key to at least prevent compilation errors.

Filter on paginate doesn't return the correct pagination metadata

Describe the bug
In one project I'm using the version 1.0.13 and the pagination with filter works correctly (Return the correct pagination metadata). I installed the version 1.0.18 (latest one) and same query doesn't return the correct pagination metadata.

To Reproduce
Execute a simple pagination query:

Query:

// MongoProduct is an mongoose schema with pagination plugin
// filter => { name: /^.*p.*$/i, category: '5c17e07383774a001d7d6143' }

MongoProduct
                .paginate(filter, { 
                    page: page, 
                    limit: 20,
                    populate: [{
                        path: 'category',
                        select: 'name description categoryPath'
                    }]
                })
                .then(p => /* Do something */ )
                .catch(e => /* Do something */ )

Responses:

// V1.0.13
{
    "message": "Products retrieved",
    "data": {
        "docs": [...],
        "totalDocs": 12,
        "limit": 20,
        "hasPrevPage": false,
        "hasNextPage": false,
        "page": 1,
        "totalPages": 1,
        "prevPage": null,
        "nextPage": null
    }
}
// V1.0.18
{
    "message": "Products retrieved",
    "data": {
        "docs": [...],
        "totalDocs": 58,
        "limit": 20,
        "hasPrevPage": false,
        "hasNextPage": true,
        "page": 1,
        "totalPages": 3,
        "prevPage": null,
        "nextPage": 2
    }
}

Expected behavior
Version 1.0.18 should be response the same as 1.0.13 and the metadata should be the filtered summary not the database summary.

Desktop (please complete the following information):

  • OS: Mac os X Mojave
  • Browser: Safari

mongoosePaginate.paginate.options doesnt take effect when I use someModel.paginate()

Sorry for my english, but I'll try to explain this, Im new and this is my first report in my life :( :

Describe the bug
When I trying to set set custom default options for all queries and then use someModel.paginate() mongoose returns all data but the the default custom options doesnt not take effect, but when I set directly options to 'paginate()' params: example myModel.paginate({}, {someOptions}), the options works correctly.

To Reproduce
Steps to reproduce the behavior:

  1. Set custom options for all queries (in my case, I add the mongoosePaginate.paginate.options directly to 'user' controller however i've tried to add as config.js file and other ways but it doesnt work)
  2. Do a query with paginate without params, like myModel.paginate() (its supposed that paginate() method will get the default options that i did set)
  3. The method returns all data... Does not take the options that I did set

Expected behavior
The data filtered by the options

Screenshots

photo1

photo2

As you can see in the last image, the data have not the options that i did set.

Desktop (please complete the following information):

  • OS: Win 10
  • Browser: Postman
  • Version: Node v.10.15.1

Additional context
Hey, I've been trying with the first version of mongoose-paginate, and this problem doesn't appear, its so strange
but i dont want to use the first version.

Add paginator elements in an object

Is it possible to have an option to add all elements in a json object instead of placing them in the root of the result?

From this:

{
 docs: [...],
  totalDocs: 10,
  limit: 5,
  page: 1,
  totalPages: 2,
  pagingCounter: 11,
  hasPrevPage: true,
  hasNextPage: false,
  prevPage: 2,
  nextPage: null 
}

To this:

{
 docs: [...],
 paginator: {
   totalDocs: 10,
   limit: 5,
   page: 1,
   totalPages: 2,
   pagingCounter: 11,
   hasPrevPage: true,
   hasNextPage: false,
   prevPage: 2,
   nextPage: null 
 },
}

Thanks !

Page, pagingCounter, hasPrevPage, hasNextPage, prevPage and nextPage don't work when using offset

When I try to paginate by offset:

const result = await this.paginate({}, {
    offset: 0,
    limit: 10
  }).catch(err => console.error('Caught:', err.message));

It's don't calculated the page, consequently the result parameters: pagingCounter, hasPrevPage, hasNextPage, prevPage, nextPage doesn't work.

Result:

totalDocs: 5570,
offset: 0,
limit: 10,
totalPages: 557,
page: undefined,
pagingCounter: NaN,
hasPrevPage: false,
hasNextPage: false,
prevPage: null,
nextPage: null 

Solution:
src/index.js
add this line above line 151:

page = Math.ceil((offset + 1) / limit);

Patch:

--- src/index.js
+++ src/index.js
@@ -150,6 +151,7 @@ function paginate(query, options, callback) {
 
       if (typeof offset !== 'undefined') {
         meta.offset = offset;
+        page = Math.ceil((offset + 1) / limit);
       }
 
       const pages = (limit > 0) ? (Math.ceil(count / limit) || 1) : null;

Model.Paginate is extremely slow when collection size starts to grow (5000+)

Describe the bug
Calling await SomeModel.paginate({}, options) is awfully slower compared to using mongoose-paginate of even await MyModel.find().limit(n).sort({ property: n }). Started noticing the issue as my collection grew in size.

To Reproduce
Steps to reproduce the behavior:

  1. Create a time-base collection with a lot of documents (5000+)
  2. Add proper indexing
  3. Paginate n values, sorting by time in any order (asc or desc)
  4. See the time it takes
  5. Compare to using a combination of .limit(n).sort(obj)
  6. Conclude ~ 100% slower.

Expected behavior
I expected much much faster response containing results. Confirmed issue when using mongoDB's .limit + .skip / .limit + .sort. I got my expected behavior when using methods but different npm package (mongoose-paginate) instead.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: Win 10
  • Node 12.0.0
  • MongoDB v4.0.10

Collection.count deprecation warning

Do you plan to fix the deprecation warning for using the this.count?

DeprecationWarning: collection.count is deprecated, and will be removed in a future version. Use collection.countDocuments or collection.estimatedDocumentCount instead

I'm using version 1.0.19

Cast error on the "limit" option

Describe the bug
I'm not sure if it's wanted or not, but I will still report it. When submitting the mongoose request, if the limit option is a string (for example "10"), it's returning an error. In my case, I receive the option list from some query params and thus, they are in a String format event for integer.
It's happening only for the limit option (page is working fine with a string).

To Reproduce
Simply submit a mongoose paginate request follow the description above.

Expected behavior
Can the library do the integer cast for the limit option ?

How to set limit = infinite?

Is your feature request related to a problem? Please describe.

For certain specific situations I would like to be able to disable the limit, without needing to use find(). I did not see in the documentation if this was possible. I did try '-1' and 'undefined' as values, but neither worked.

Somewhere 'undefined' appears to be treated as zero, since the perPage values comes back as 0.

Describe the solution you'd like

Some method to disable the limit. Either via a value to the limit option or an explicit option.

Describe alternatives you've considered

  • Duplicating logic with find()

Additional context

Wrong output

Describe the bug
Output is false.
{
totalDocs: 5,
limit: 3,
hasPrevPage: false,
hasNextPage: false,
page: NaN,
totalPages: 2,
pagingCounter: NaN,
prevPage: null,
nextPage: null
}

The output doesn't even make sense.

To Reproduce
Steps to reproduce the behavior:
options: {
page: 1,
lean: true,
limit: 3,
collation: {
locale: 'en'
}
}

Expected behavior
{
totalDocs: 5,
limit: 3,
hasPrevPage: false,
hasNextPage: true,
page: 1,
totalPages: 2,
pagingCounter: 1,
prevPage: 1,
nextPage: 2
}

Is url crafted automatically?

Hello,

i have one more question.
Do i need to craft url or is crafted automatically?
For example with express-paginate i am able to do this.

{{#each pages}}
            <li class="paginator-item">
                <a href="{{this.url}}" class="paginator-itemLink">{{this.number}}</a>
            </li>
{{/each}}

which gaves me link
http://localhost:3000/users/show?page=2&limit=5

Thank in advance for reply.

TotalDocs returning 0 while there is result

    when trying to run this 

somthing.paginate(filters, options, (error, result) => {
if (error) {
errorHandler(res, error);
} else {
res.status(statuses("ok")).send({
result.docs,
result.totalDocs
});
}

option={ populate: [ 'images' ],
sort: { 'date.created': 'desc' },
limit: 100,
offset: 0 }

mongoose version
"mongoose": "~5.6.9",
"mongoose-paginate-v2": "^1.3.0",

Screen Shot 2019-08-13 at 3 36 38 PM

as you can see from the screen shot they are returning 2 result but the total docs 0

No limit on paginate request

I try to get all of my documents if I have a certain condition in my code. Can I make that or I must make another request (by duplicate my code) without pagination ?
Thank you ! :)

option select does not work correctly

Describe the bug
When i use a select in the option object like const options = {select: "label"} , this does not affect the result and i have the complete document and not only the label....

When i use the negate select , this work correctly ! For example if i use const options = {select: "-label"} , i have the document without the label.

My Code
`let { latitude, longitude, maxDistance } = req.query;

        // find  event
        maxDistance = maxDistance * 1000;
       
        const options = {
            limit: req.mongo.queryOptions['limit'] ? req.mongo.queryOptions['limit'] : 100,
            offset: req.mongo.queryOptions['skip'] ? req.mongo.queryOptions['skip'] : 0,
            //select: "-creator -registrations -cancelRegistrations -after -messages -session.sport -session.business",
            select: "label",
            sort: { 'session.startAt': 'asc' }

        };

        const isodate = new Date().toISOString();
        const events = await Events.paginate({
            "session.place.location": {
                $near: {
                    $geometry: {
                        type: "Point",
                        coordinates: [longitude, latitude]
                    },
                    $maxDistance: maxDistance,
                }
            },
            "session.startAt": { $gte: isodate },
        }, options);

`

  • Version 1.3.1 with mongoose 5.5.6

Slow query when perform heavy database

Describe the bug
The plugin take very long time when perform the database that have over 100.000 records, and each record having big data.

To Reproduce
Steps to reproduce the behavior:

  1. Configuration to get paging query for get 10 items in over 100.000 records
  2. Take a look how long to query process data and response

Actual result
Take more than 10s for the query

Expected behavior
Result in a second

Suggest solution
Take a look the source code from line 107 to line 117. I think you should not use 'this.find' query for count purpose. It may cause out of memory on heavy data and cause slow query issue.
Could you change it to 'this.count' and shouldn't need to perform populate action?

Thank you so much!

Paginate the subdocument of a schema

How to paginate the sub-document of a schema. The model has array of sub-document as of a book can have many authors and I want to paginate the authors.
How to achieve this.

Sort case insensitive option

Is your feature request related to a problem? Please describe.
MongoDB sorts case sensitive by default. Sorted results are returned in case-sensitive order, so capital 'Z' is ordered before lowercase 'a'. It would be great to have an option to sort alphabetically in case-insensitive order.

Describe the solution you'd like
Create an option to set the 'sort' to be case insensitive.

Aggregate functions usage

Hello sir,
I am trying to sort by new field that sum of two fields in the mongoose schema.
But how can i do that?

Here is my example code below:

let sort = {
            field: 'asc', 
            createdAt: -1
        };
        if(sortType == "MOST_RECENT"){
            sort = {
                field: 'asc', 
                createdAt: -1
            }
        }else if(sortType == "POPULAR"){
            sort = {
                field: 'asc', 
                popularity: -1
                //popularity: { $add: [ "$likeCount", "$commentCount" ] }
            }
        }
        let options = {
            offset: +offset || 0,
            limit: +limit || 5,
            sort: sort,
            populate: "postedBy"
        };
        let filter = {};
        if(searchText){
            filter = { 
                $or: [
                        {subject: { $regex: '.*' + searchText + '.*', $options: 'i' }}, 
                        {lecture: { $regex: '.*' + searchText + '.*', $options: 'i' }},
                        {examShortName: { $regex: '.*' + searchText + '.*', $options: 'i' }},
                        {content: { $regex: '.*' + searchText + '.*', $options: 'i' }}
                    ] 
            }
        }
        QuestionModel.paginate(filter, options).then((result)=>{
            result.docs = result.docs.map(item=>{
                item = item.toObject();
                item.questionId = item._id;
                delete item._id;
                delete item.__v;
                return item;
            });
            return resolve(result);
        }).catch((err)=>{
            return reject(err);
        });

I don't know how to sort by using sum of two fields.
I would be appreciated for any suggestion.
Thank you.

i don't understant how to use populate

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

MongoError: $where is not allowed in this context

When I'm trying to query whith $where operator I'm getting this error (from my logs):

2|web  | 2019-1-16 18:00:26 Query for DB: { '$where': 'this.following > this.followers / 2',
2|web  |   parsed: true,
2|web  |   taskIds: 5c33542194a60624baf2cf07 }
2|web  | { MongoError: $where is not allowed in this context
2|web  |     at queryCallback (/root/b/node_modules/mongodb-core/lib/cursor.js:248:25)
2|web  |     at /root/b/node_modules/mongodb-core/lib/connection/pool.js:532:18
2|web  |     at args.(anonymous function) (/usr/lib/node_modules/pm2/node_modules/event-loop-inspector/index.js:138:29)
2|web  |     at _combinedTickCallback (internal/process/next_tick.js:132:7)
2|web  |     at process._tickDomainCallback (internal/process/next_tick.js:219:9)
2|web  |   ok: 0,
2|web  |   errmsg: '$where is not allowed in this context',
2|web  |   code: 2,
2|web  |   codeName: 'BadValue',
2|web  |   name: 'MongoError',
2|web  |   [Symbol(mongoErrorContextSymbol)]: {} }

When I'm using $where with legacy package everything working fine.

customLabels

Describe the bug
using custom labels, if you want for example to do the following customLabels: { docs: 'posts' } this will result into discarding the other properties

To Reproduce
Steps to reproduce the behavior:

  1. const options = { customLabels: { docs: 'posts' } };

Expected behavior
all the properties should exist

Screenshots
image

Desktop (please complete the following information):

  • OS: linux
  • Postman

If page is more than totalDocs then empty array

Describe the bug
If I am sending higher page returns empty array.

To Reproduce
Data object is the result from query using paginate-v2. As you can see limit is fine asking for more data in the query, the issue only happens with page (per_page).

Expected behavior
Should return last page available, or validation error.

Screenshots
image

Desktop (please complete the following information):

  • OS: Windows Node NestJS

How to do search in datatable and showing related results only using this plugin

I am using paginate v2 plugin for getting data into data table from the MongoDB server. I am successfully getting the result into data table with server-side pagination. But with using this plugin, my search is not working . Its doing nothing when I do a search but in default search array, I am getting the value in the console .I also tried to populate but It's giving me Cannot read property 'count' of undefined error. Please help me with a searching option.
here is my nodejs code.

app.get('/gettable',(req,res)=>{
    console.log(req.query);
user.paginate({},{
        page:Math.ceil(req.query.start / req.query.length) + 1,
        limit:parseInt(req.query.length),
        populate:{
            match:{
                name:'Graiden Waller'
            }
        } 
    },function(err,result){
        /* console.log(result); */
        var mytable = {
            draw:req.query.draw, 
            recordsTotal:0,
            recordsFiltered:0,
            data:[],  
                   
        }
        if(err) {
            console.log(err);
            res.json(mytable);
        } else {
            if(result.totalDocs > 0) {
                mytable.recordsTotal = result.totalDocs;
                mytable.recordsFiltered = result.totalDocs;
              
                for(var key in result.docs) {
                    mytable.data.push([
                        result.docs[key]['name'],
                        result.docs[key]['lastname'],
                        result.docs[key]['email'],
                        result.docs[key]['pass'],
                        result.docs[key]['birthdate'],
                        result.docs[key]['zipcode'],
                        result.docs[key]['phonenumber'],
                    ]);
                }
              }
               res.json(mytable);
  }
       
 });

So as per populate,I should get the 'Graiden Waller' named row but in console it's giving me error of cannot read property 'count ' undefined.

How to use projection?

I want to use like this
const projection = { items: { $slice: -5 } } ProjectModel.model.find({}, projection);

Incorrect interaction with 'mongoose-delete'

Describe the bug
If I pass the Query object from findWithDeleted() method of dsanel/mongoose-delete: Mongoose Soft Delete Plugin to paginate I get a missmatch between the totalDocs and docs.

To Reproduce

  1. Check this gist: mongoose-paginate-v2 and mongoose-delete to reproduce.
  2. Save some documents, then soft-delete them.

From: console.log(await Kitten.findWithDeleted())

[ { deleted: false,
    _id: 5d35e342fb9f2304a3b6df13,
    name: 'Fluffy',
    __v: 0 },
  { deleted: false,
    _id: 5d35e3440489e404b23d8708,
    name: 'Fluffy',
    __v: 0 },
  { deleted: true,
    _id: 5d35e366fae0df04db3e80e1,
    name: 'Fluffy',
    __v: 0 },
  { deleted: true,
    _id: 5d35e36b99a4c304ec877ecb,
    name: 'Fluffy',
    __v: 0 },
  { deleted: true,
    _id: 5d35e389376a390514531488,
    name: 'Fluffy',
    __v: 0 },
  { deleted: true,
    _id: 5d35e3a0379d650536cd4053,
    name: 'Fluffy',
    __v: 0 } ]

From: console.log(await Kitten.paginate(Kitten.findWithDeleted()));

{ docs:
   [ { deleted: false,
       _id: 5d35e342fb9f2304a3b6df13,
       name: 'Fluffy',
       __v: 0 },
     { deleted: false,
       _id: 5d35e3440489e404b23d8708,
       name: 'Fluffy',
       __v: 0 } ],
  totalDocs: 6,
  limit: 10,
  offset: 0,
  hasPrevPage: false,
  hasNextPage: false,
  page: 1,
  totalPages: 1,
  pagingCounter: 1,
  prevPage: null,
  nextPage: null }

Expected behavior
I expect all documents from the Query to appear in docs array, also totalDocs and docs.length from paginate should always be the same.

Desktop (please complete the following information):

  • OS: Linux
  • Node: 11

Thanks

Edit: My bad, I'm overwriting Mongoose's Model.find() in mongoose-delete configuration object (overrideMethods: ["find"]), maybe add an option in mongoose-paginate-v2 so we can pass a custom find method to use in mongoose-paginate-v2/index.js#L107?

const mQuery = options.customFind(query, projection, findOptions);

Can't paginate queries using $geoNear, $near, and $nearSphere

Describe the bug
When I run a Model.paginate(query) where query needs to filter elements by a 2dsphere index using $geoNear (in my case), the response is an error with the message $geoNear, $near, and $nearSphere are not allowed in this context.

To Reproduce
Steps to reproduce the behavior:

  1. Create a collection
  2. Create a "2dsphere" index pointing to a model property.
  3. Run the model.paginate() querying the 2dsphere property index.
  4. See error $geoNear, $near, and $nearSphere are not allowed in this context

Expected behavior
Outputs documents in order of nearest to farthest from a specified point.

(check out the official documentation: https://docs.mongodb.com/manual/reference/operator/aggregation/geoNear/)

Desktop:

  • OS: MacOS
  • Browser Chrome 76
  • Version Mojave

Additional context
When using the model.find() method the query works fine.

Getting error, "this.countDocuments is not a function" in version 1.3.52

Error
I've been using this module of version 1.3.0. Till now it didn't give any errors. But when I updated this to latest version(1.3.52), it throwing an error like, "this.countDocuments is not a function".

My Code

    var options = {
        sort: { createdAt: -1 },
        lean: true,
        page: req.query.page,
        limit: req.query.pageSize
    };
    var query=(companyId!==null&&companyId!==false)? {company:companyId}:{};
    [err, respData]=await to(Template.paginate(query,options));
    if(err) {TE(err, true);}
    return (respData)? respData:false;


TypeError: this.countDocuments is not a function

Hello,

i am trying to make pagination with this but i am still getting error
TypeError: this.countDocuments is not a function

My model.

// User Schema
var UserSchema = mongoose.Schema({
  firstname: {
    type: String
  }
});

UserSchema.plugin(mongoosePaginate);
var User = (mongoose.model("User", UserSchema));
module.exports = User;

Rotues.js
// View users

router.get("/show", function (req, res, next) {

    const options = {
        page: 1,
        limit: 10
    };

    User.paginate({}, options, function (err, result) {
        result.docs
    });
});

Just dont know what is wrong.
Thank for any advice.

One document always lost

Sumary:
In first response (1 page, 4 items) i can see that total document count is 6, but when i sent second request (for 2nd page) it says that total count of douments is 5, and sent only one document in array. If i change items per page to 5 - secon request will sent empty array too. I don't understand why one documents always is lost

User.paginate({fullname: {$regex: search, $options: '-i'}}, {page: page, limit: limit, customLabels: myCustomLabels, select:'-email -password'}, async (err, result) => {
            res.json(result)

FYI
If I remove {$ regex: search, $ options: '-i'}, this will work correctly, but i need it for search

Thanks for help!

dist is in git ignore so module is not loaded.

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Pretty simple goof. The gitignore has dist ignored so when users get package . module is lost.

mongoose-paginate-v2 overrides mongoose types

Describe the bug

mongoose paginate overrides the types provided by mongoose.
mongoose paginate should only add its own types and leave mongoose types as it is.

To Reproduce

  • use TypeScript
  • in package.json
"dependencies": {
    "mongoose": "^5.6.11",
    "mongoose-paginate-v2": "^1.3.0"
  },
  "devDependencies": {
    "@types/mongoose": "^5.5.13",
    "@types/mongoose-paginate-v2": "^1.0.3"
  }

Expected behavior

This code should throw an error but becuase mongoose-paginate overrides types provided by mongoose this code works.

Code

hasPrevPage and hasNextPage configurable

Hello and thanks for sharing this lib :)

Why hasPrevPage and hasNextPage can't be changed?
Lot of APIs use a snake_case field naming as has_next_page / has_prev_page.

Thanks a lot.

$group

hi ,

can i use $group in this library.

if yes can u write an example in the documentation.

Thanks in advance

Retrieve all results

Is there currently a way I've missed/a planned change to allow this pagination library also to retrieve all results for a query. Or will this only ever return paged results?

I could use a default very large number to return all results, but it would be great to not have to.

Delay on retrieve items

Describe the bug
There is a problem on retrieve elements from mongodb, this take 45 seconds or more.
I'm working with big data 1 million documents.

this is my code:

const query = req.query;
const page = parseInt(query.page);
const limit = parseInt(query.limit);
const options = {
page: !isNaN(page) ? page : 1,
limit: !isNaN(limit) ? limit : 20,
sort: { createdAt: -1, updatedAt: -1 },
select: 'name email',
lean: true
};
const users = await usersModel.paginate({}, options);

I'm using some properties in your library. I've added index on mongodb collection.
when I'm using without your library the time of query is 0.004 seconds
when I'm using with your library the time of query is 45 seconds or more.

To Reproduce
Steps to reproduce the behavior:

  1. 500000 or more documents.
  2. Test with the library a simple request.
  3. See the delay

Expected behavior

  1. The query should be similar to native request or at least similar to
    mongoose-paginate, this take around 0.5 or 3 seconds in similar conditions

Add projection support.

Is your feature request related to a problem? Please describe.
Adding projection support to find().

TypeError: this.countDocuments is not a function

at Function.paginate (/app/node_modules/mongoose-paginate-v2/dist/index.js:104:27)

My Model

const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
const CustomersDraftSchema = new mongoose.Schema({
.........
});
CustomersDraftSchema.plugin(mongoosePaginate);
module.exports = mongoose.model('customers_draft', CustomersDraftSchema);

The hasNext paramter is always having false

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

sorry, At present there are related performance test data analysis plugin, please

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

At present there are related performance test data analysis plugin, please。
When I use paging plug-in data acquisition need each page 1 of article 1s time,if i use native mongoose to get total count and select list use 0.3s time,

Querying populated fields return empty array

Describe the bug
When you query a subdocument that has been populated, the query returns empty array.

To Reproduce
Steps to reproduce the behavior:
1.- Create a Schema with populated fields.

const ProjectSchema = new mongoose.Schema(
    {
        name: {
            en: {
                type: String,
                required: true,
            },
            es: {
                type: String,
                required: true,
            },
        },
        maker: { type: ObjectId, ref: 'Maker' }
}

2.- Create an endpoint to retrieve items from the new model using paginate with a filter using a populated field:

const getItemsFromDB = async (req, query) => {
const options = {
        sort: 'createdAt',
        lean: true,
        1,
        5,
         { path: 'maker', select: 'name' },
    }
    return new Promise((resolve, reject) => {
        model.paginate(query, options, (err, items) => {
            if (err) {
                reject(buildErrObject(422, err.message))
            }
            resolve(cleanPaginationID(items))
        })
    })
}

3.- Call the endpoint querying the populated field:

{{server}}/projects?filter={"maker.name":"Ocean Sentry"}&page=1&limit=2&sort=name&order=-1

4.- Get an empty array in the results:

{
    "docs": [],
    "totalDocs": 0,
    "limit": 2,
    "hasPrevPage": false,
    "hasNextPage": false,
    "page": 1,
    "totalPages": 1,
    "pagingCounter": 1,
    "prevPage": null,
    "nextPage": null
}

Expected behavior
An array containing the results. If you query for a field with subdocuments (not populated) it works correctly.

Select returned fields in paginate query

Hi,
I am using mongoose v5.7.8 and mongoose-paginate-v2 v1.3.3.
I want to know if is possible to make a paginate query selecting which fields will return.
i.e: User.findById(req.params.id, '_id name')
This will returns only _id and name fields from my User Model.

Thank you.

Provide Cursor itself

Is your feature request related to a problem? Please describe.
I'd like to resolve the paginated result in GraphQL. Therefor I need a Cursor.

Describe the solution you'd like
Providing the Cursor itself.

Describe alternatives you've considered
Using primary keys as cursors in order to resolve to edges in GraphQL, but that's considered problematic.

heap out of memory

When there is 200,000 data, the component will report an exception “heap out of memory”;

my sql:

db.getCollection('files').find({type: '0', status: '1000', category: { $in: ['0', '1', '2', '3'] }}).sort({ createdTime: -1 }).limit(100)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.