leodinas-hao / mongoose-query-parser

Convert url query string to MongooseJs friendly query object including advanced filtering, sorting, population, string template, type casting and many more...
MIT License
68 stars 17 forks source link

mongoose-query-parser

NPM version Downloads

Convert url query string to MongooseJs friendly query object including advanced filtering, sorting, population, string template, type casting and many more...

The library is built highly inspired by api-query-params

Features

Installation

npm install mongoose-query-parser --save

Usage

API

import { MongooseQueryParser } from 'mongoose-query-parser';

const parser = new MongooseQueryParser(options?: ParserOptions)
parser.parse(query: string, predefined: any) : QueryOptions
Arguments

Returns

Example

import { MongooseQueryParser } from 'mongoose-query-parser';

const parser = new MongooseQueryParser();
const predefined = {
  vip: { name: { $in: ['Google', 'Microsoft', 'NodeJs'] } },
  sentStatus: 'sent'
};
const parsed = parser.parse('${vip}&status=${sentStatus}&timestamp>2017-10-01&author.firstName=/john/i&limit=100&skip=50&sort=-timestamp&select=name&populate=children.firstName,children.lastName', predefined);
// {
//   select: { name : 1 },
//   populate: [{ path: 'children', select: 'firstName lastName' }],
//   sort: { timestamp: -1 },
//   skip: 50,
//   limit: 100,
//   filter: {
//     name: {{ $in: ['Google', 'Microsoft', 'NodeJs'] }},
//     status: 'sent',
//     timestamp: { '$gt': 2017-09-30T14:00:00.000Z },
//     'author.firstName': /john/i
//   }
// }

Supported features

Filtering operators

MongoDB URI Example Result
$eq key=val type=public {filter: {type: 'public'}}
$gt key>val count>5 {filter: {count: {$gt: 5}}}
$gte key>=val rating>=9.5 {filter: {rating: {$gte: 9.5}}}
$lt key<val createdAt<2017-10-01 {filter: {createdAt: {$lt: 2017-09-30T14:00:00.000Z}}}
$lte key<=val score<=-5 {filter: {score: {$lte: -5}}}
$ne key!=val status!=success {filter: {status: {$ne: 'success'}}}
$in key=val1,val2 country=GB,US {filter: {country: {$in: ['GB', 'US']}}}
$nin key!=val1,val2 lang!=fr,en {filter: {lang: {$nin: ['fr', 'en']}}}
$exists key phone {filter: {phone: {$exists: true}}}
$exists !key !email {filter: {email: {$exists: false}}}
$regex key=/value/<opts> email=/@gmail\.com$/i {filter: {email: /@gmail.com$/i}}
$regex key!=/value/<opts> phone!=/^06/ {filter: {phone: { $not: /^06/}}}

For more advanced usage ($or, $type, $elemMatch, etc.), pass any MongoDB query filter object as JSON string in the filter query parameter, ie:

parser.parse('filter={"$or":[{"key1":"value1"},{"key2":"value2"}]}&name=Telstra');
// {
//   filter: {
//     $or: [
//       { key1: 'value1' },
//       { key2: 'value2' }
//     ],
//     name: 'Telstra'
//   },
// }

Populate operators

parser.parse('populate=createdBy:friends.name,createdBy.name,likedBy.name');
// {
//   populate: [{
//     path: 'createdBy',
//     select: 'name',
//     populate: {
//       path: 'friends',
//       select: 'name',
//     }
//   }, {
//     path: 'likedBy',
//     select: 'name',
//   }]
// }

Skip / Limit operators

parser.parse('skip=5&limit=10');
// {
//   skip: 5,
//   limit: 10
// }

Select operator

parser.parse('select=id,url');
// {
//   select: { id: 1, url: 1}
// }
parser.parse('select=-_id,-email');
// {
//   select: { _id: 0, email: 0 }
// }

Sort operator

parser.parse('sort=-points,createdAt');
//  {
//    sort: { points: -1, createdAt: 1 }
//  }

Keys with multiple values

Any operators which process a list of fields ($in, $nin, sort and projection) can accept a comma-separated string or multiple pairs of key/value:

Embedded documents using . notation

Any operators can be applied on deep properties using . notation:

parser.parse('followers[0].id=123&sort=-metadata.created_at');
// {
//   filter: {
//     'followers[0].id': 123,
//   },
//   sort: { 'metadata.created_at': -1 }
// }

Automatic type casting

The following types are automatically casted: Number, RegExp, Date, Boolean and null string is also casted:

parser.parse('date=2017-10-01&boolean=true&integer=10&regexp=/foobar/i&null=null');
// {
//   filter: {
//     date: 2017-09-30T14:00:00.000Z,
//     boolean: true,
//     integer: 10,
//     regexp: /foobar/i,
//     null: null
//   }
// }

If you need to disable or force type casting, you can wrap the values with string(), date() built-in casters or by specifying your own custom functions (See below):

parser.parse('key1=string(10)&key2=date(2017-10-01)&key3=string(null)');
// {
//   filter: {
//     key1: '10',
//     key2: 2017-09-30T14:00:00.000Z,
//     key3: 'null'
//   }
// }

String template for predefined query/variable

Best to reducing the complexity/length of the query string with the ES template literal delimiter as an "interpolate" delimiter (i.e. ${something})

const parser = new MongooseQueryParser();
const preDefined = {
  isActive: { status: { $in: ['In Progress', 'Pending'] } },
  secret: 'my_secret'
};
parser.parse('${isActive}&secret=${secret}', preDefined);
// {
//   filter: {
//     status: { $in: ['In Progress', 'Pending'] },
//     secret: 'my_secret'
//   }
// }

Available options (opts)

Customize operator keys

The following options are useful to change the operator default keys:

const parser = new MongooseQueryParser({
  limitKey: 'max',
  skipKey: 'offset'
});
parser.parse('organizationId=123&offset=10&max=125');
// {
//   filter: {
//     organizationId: 123,
//   },
//   skip: 10,
//   limit: 125
// }

Date format

const parser = new MongooseQueryParser({dateFormat: ['yyyyMMdd', 'yyyy-MM-dd']});
parser.parse('date1=20171001&date2=2017-10-01');
// {
//   filter: {
//     date1: 2017-09-30T14:00:00.000Z
//     date2: 2017-09-30T14:00:00.000Z
//   }
// }

Blacklist

The following options are useful to specify which keys to use in the filter object. (ie, avoid that authentication parameter like apiKey ends up in a mongoDB query). All operator keys are (sort, limit, etc.) already ignored.

const parser = new MongooseQueryParser({ blacklist: ['apiKey'] });
parser.parse('id=e9117e5c-c405-489b-9c12-d9f398c7a112&apiKey=foobar');
// {
//   filter: {
//     id: 'e9117e5c-c405-489b-9c12-d9f398c7a112',
//   }
// }

Add custom casting functions

You can specify you own casting functions to apply to query parameter values, either by explicitly wrapping the value in URL with your custom function name (See example below) or by implicitly mapping a key to a function

const parser = new MongooseQueryParser({
  casters: {
    lowercase: val => val.toLowerCase(),
    int: val => parseInt(val, 10),
  },
  castParams: {
   key3: 'lowercase' 
  }});
parser.parse('key1=lowercase(VALUE)&key2=int(10.5)&key3=ABC');
// {
//   filter: {
//     key1: 'value',
//     key2: 10,
//     key3: 'abc'
//   }
// }

License

MIT