Thanks to this package, you can parse and convert query parameters into MongoDB query criteria and options.
npm install qs-to-mongo
import qs2m from 'qs-to-mongo' // or const qs2m = require('qs-to-mongo')
const result = qs2m('name=john&age>21&fields=name,age&sort=name,-age&offset=10&limit=10')
The result will be
{
criteria: {
name: 'john',
age: { $gt: 21 }
},
options: {
fields: { name: true, age: true },
sort: { name: 1, age: -1 },
offset: 10,
limit: 10
}
}
Resulting object props (criteria
and options
) are usable as parameters for any MongoDB driver or ODM. For example:
import qs2m from 'qs-to-mongo'
import { MongoClient } from 'mongodb'
;(async function() {
const { db } = await MongoClient.connect(connectionString)
const result = qs2m('name=john&age>21&fields=name,age&sort=name,-age&offset=10&limit=10')
const documents = await db('dbName')
.collection('collectionName')
.find(result.criteria, result.options)
})().catch(console.log)
qs2m(query: string, options: {
ignoredFields?: string | string[]
parser?: {
parse(query: string, options?: any): any
stringify(obj: object, options?: any): string
}
parserOptions?: object
dateFields?: string | string[]
objectIdFields?: string | string[]
fullTextFields?: string | string[]
parameters?: Partial<typeof defaultParameters>
maxLimit?: number
})
-
ignoredFields
: array of query parameters that are ignored, in addition to default ones: "fields", "omit", "sort", "offset", "limit", "q"; -
parser
: custom query parser, must implementparse(query: string, options?: any): any
andstringify(obj: object, options?: any): string
. The default parser is qs; -
parserOptions
: options to pass to the query parser; -
dateFields
: fields that will be converted toDate
. If no fields are passed, any valid date string will be converted to ISOString; -
objectIdFields
: fields that will be converted to ObjectId; -
fullTextFields
: fields that will be used as criteria when passing theq
query parameter; -
parameters
: override default parameters used as query options ("fields", "omit", "sort", "offset", "limit", "q"). For example: {fields:'$fields', omit:'$omit', sort:'$sort', offset:'$offset', limit:'$limit'}; -
maxLimit
: maximum limit that could be passed to thelimit
option.
{
criteria: {
[key: string]: any
}
options: {
projection: {
[key: string]: 0 | 1
}
sort: {
[key: string]: 1 | -1
}
skip: number
limit: number
}
links: (url: string, totalCount: number) => {
prev: string
first: string
next: string
last: string
} | null
}
import qs2m from 'qs-to-mongo' //or const qs2m = require('qs-to-mongo')
const query = qs2m('name=john&age>21&offset=20&limit=10')
query.links('http://localhost/api/v1/users', 100)
This will generate an object that could be used by the Express res.links(http://expressjs.com/en/4x/api.html#res.links) method.
{ prev: 'http://localhost/api/v1/users?name=john&age%3E21=&offset=10&limit=10',
first: 'http://localhost/api/v1/users?name=john&age%3E21=&offset=0&limit=10',
next: 'http://localhost/api/v1/users?name=john&age%3E21=&offset=30&limit=10',
last: 'http://localhost/api/v1/users?name=john&age%3E21=&offset=90&limit=10' }
Any query parameters other than the special parameters fields, omit, sort, offset, limit, and q are interpreted as query criteria. For example name=john&age>21
results in a criteria value of:
{
'name': 'john',
'age': { $gt: 21 }
}
- Supports standard comparison operations (=, !=, >, <, >=, <=).
- Numeric values, where
Number(value) != NaN
, are compared as numbers (i.e.,field=10
yields{field:10}
). - Values of true and false are compared as booleans (ie.
{field: true}
) - ObjectId hex strings can be compared as ObjectId instances if `objectIdFields`` is passed.
- Values that are dates are compared as dates (except for YYYY, which matches the number rule) if
dateFields
is passed. If not, they will be converted to Date ISOString. -
null
values are compared asnull
. For examplebar=null
yields{bar: null}
- special
q
query parameter could be used to perform a full-text search on fields passed in thefullTextFields
argument. - Multiple equals comparisons are merged into a
$in
operator. For example,id=a&id=b
yields{id:{$in:['a','b']}}
. - Multiple not-equals comparisons are merged into a
$nin
operator. For example,id!=a&id!=b
yields{id:{$nin:['a','b']}}
. Comma-separated values in equals or not-equals yield an$
inor
$ninoperator. For example,
id=a,byields
{id:{$in:['a','b']}}`. - Regex patterns. For example,
name=/^john/i
yields{id: /^john/i}
. - Parameters without a value check that the field is present. For example,
foo&bar=10
yields{foo: {$exists: true}, bar: 10}
. - Parameters prefixed with a not (!) and without a value check that the field is not present. For example,
!foo&bar=10
yields{foo: {$exists: false}, bar: 10}
. - Supports some of the named comparison operators ($type, $size and $all). For example,
foo:type=string
, yeilds{ foo: {$type: 'string} }
. - Support for forced string comparison; value in single or double quotes (
field='10'
orfield="10"
) would force a string compare. Allows for a string with an embedded comma (field="a,b"
) and quotes (field="that's all folks"
).
Comparisons on embedded documents should use mongo's dot notation instead of qs (Use foo.bar=value
instead of foo[bar]=value
) 'extended' syntax.
Although exact matches are handled for either method, comparisons (such as foo[bar]!=value
) are not supported because the qs
parser expects an equals sign after the nested object reference; if it's not an equals, the remainder is discarded.
You can adjust the default parameters (fields, omit, sort, offset, limit and q) by providing an alternate set as an option. For example:
const parameters = {
fields:'$fields',
omit:'$omit',
sort:'$sort',
offset:'$offset',
limit:'$limit',
q: '$q',
}
const query = q2m(res.query, { parameters: parameters });
This will then interpret the default parameters as query parameters instead of options. For example a query of age>21&omit=false&$omit=a
results in a criteria value of:
query.criteria = {
'age': { $gt: 21 },
'omit': false
}
and an option value of:
query.option = {
fields: { a: false }
}
This module also takes parsed query as input, so that it could be used by Fastify or express routes without any further addition.
const querystring = require('querystring')
const qs2m = require('qs-to-mongo')
const query = 'name=john&age>21&fields=name,age&sort=name,-age&offset=10&limit=10'
const q = q2m(querystring.parse(query))
This makes it easy to use it in fastify route:
fastify.get('/api/v1/mycollection', (req, reply) =>{
const q = q2m(req.query);
...
}
or in express one:
router.get('/api/v1/mycollection', function(req, res, next) {
const q = q2m(res.query);
...
}
The format and names for query parameters were inspired by this article about best practices for RESTful APIs.
This package started as a hard fork of https://github.com/pbatey/query-to-mongo. This is a TypeScript port, with some fixes and many improvements. However, this is not a drop-in replacement because of the changes to the public API.
Notable differences with query-to-mongo
- uses qs instead of querystring for default query parsing
- adds support for
null
andObjectId
hex string values - adds passing options to parser with
parserOptions
parameter - adds support for fulltext search on predefined fields (using
fullTextFields
parameter) - opt-ins date-string conversion to Date with
dateFields
parameter - opt-ins hexstring ObjectId parsing with
objectIdFields
parameter - renames
keywords
parameter toparameters
- renames
ignore
toignoredFields
- renames
fields
toprojection
in returnd mongo options - removes unused and old code
- written in TypeScript, typed out of the box
MIT