{"id":13659096,"url":"https://github.com/diegohaz/querymen","last_synced_at":"2025-04-06T02:12:00.787Z","repository":{"id":7902990,"uuid":"56445062","full_name":"diegohaz/querymen","owner":"diegohaz","description":"Querystring parser middleware for MongoDB, Express and Nodejs (MEN)","archived":false,"fork":false,"pushed_at":"2023-02-17T22:38:56.000Z","size":92,"stargazers_count":129,"open_issues_count":27,"forks_count":34,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-10-22T01:54:10.403Z","etag":null,"topics":["express","express-middleware","mongodb","mongoose","nodejs","querystrings","schema"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diegohaz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-04-17T15:55:45.000Z","updated_at":"2024-09-12T21:12:58.000Z","dependencies_parsed_at":"2022-09-16T01:35:28.517Z","dependency_job_id":"efa6827d-0e29-4f22-a0d0-adc4a75aef01","html_url":"https://github.com/diegohaz/querymen","commit_stats":{"total_commits":95,"total_committers":5,"mean_commits":19.0,"dds":"0.13684210526315788","last_synced_commit":"436c11d647556c8be9ada3176d87152ddf8f9975"},"previous_names":["diegohaz/menquery"],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegohaz%2Fquerymen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegohaz%2Fquerymen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegohaz%2Fquerymen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegohaz%2Fquerymen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diegohaz","download_url":"https://codeload.github.com/diegohaz/querymen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247423515,"owners_count":20936626,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["express","express-middleware","mongodb","mongoose","nodejs","querystrings","schema"],"created_at":"2024-08-02T05:01:05.245Z","updated_at":"2025-04-06T02:12:00.766Z","avatar_url":"https://github.com/diegohaz.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Querymen\n\n[![JS Standard Style][standard-image]][standard-url]\n[![NPM version][npm-image]][npm-url]\n[![Build Status][travis-image]][travis-url]\n[![Coveralls Status][coveralls-image]][coveralls-url]\n[![Dependency Status][depstat-image]][depstat-url]\n[![Downloads][download-badge]][npm-url]\n\n\u003e Querystring parser middleware for MongoDB, Express and Nodejs\n\n## Install\n\n```sh\nnpm install --save querymen\n```\n\n## Examples\n\n### Pagination\nQuerymen has a default schema to handle pagination. This is the most simple and common usage.\n```js\nimport { middleware as query } from 'querymen';\n\napp.get('/posts', query(), ({ querymen: { query, select, cursor } }, res) =\u003e {\n\n  Post.find(query, select, cursor).then(posts =\u003e {\n    // posts are proper paginated here\n  });\n});\n```\nUser requests `/posts?page=2\u0026limit=20\u0026sort=-createdAt` querymen will be:\n```js\nquerymen = {\n  query: {},\n  select: {},\n  cursor: {\n    limit: 20, \n    skip: 20, \n    sort: { createdAt: -1 }\n  }\n}\n```\nUser requests `/posts?q=term\u0026fields=title,desc` querymen will be:\n\u003e When user requests `/posts?q=term`, querymen parses it to `{keywords: /term/i}`. It was designed to work with [mongoose-keywords](https://github.com/diegohaz/mongoose-keywords) plugin, which adds a `keywords` field to schemas (check that out).\n\n```js\nquerymen = {\n  query: {\n    keywords: /term/i\n  },\n  select: {\n    title: 1,\n    desc: 1\n  },\n  cursor: {\n    // defaults\n    limit: 30, \n    skip: 0, \n    sort: { createdAt: -1 }\n  }\n}\n```\nUser requests `/posts?fields=-title\u0026sort=name,-createdAt` querymen will be:\n```js\nquerymen = {\n  query: {},\n  select: {\n    title: 0\n  },\n  cursor: {\n    limit: 30, \n    skip: 0, \n    sort: {\n      name: 1,\n      createdAt: -1\n    }\n  }\n}\n```\n\n### Custom schema\nYou can define a custom schema, which will be merged into querymen default schema (explained above).\n```js\nimport { middleware as query } from 'querymen';\n\napp.get('/posts', query({\n  after: {\n    type: Date,\n    paths: ['createdAt'],\n    operator: '$gte'\n  }\n}), ({ querymen }, res) =\u003e {\n  Post.find(querymen.query).then(posts =\u003e {\n    // ...\n  });\n});\n```\nUser requests `/posts?after=2016-04-23` querymen will be:\n```js\nquerymen = {\n  query: {\n    createdAt: { $gte: 1461369600000 }\n  },\n  select: {},\n  cursor: {\n    // defaults\n    limit: 30, \n    skip: 0, \n    sort: { createdAt: -1 }\n  }\n}\n```\n\n### Reusable schemas\nYou can create reusable schemas as well. Just instantiate a `Schema` object.\n```js\nimport { middleware as query, Schema } from 'querymen';\n\nconst schema = new Schema({\n  tags: {\n    type: [String],\n  }\n});\n\n// user requests /posts?tags=world,travel\n// querymen.query is { tags: { $in: ['world', 'travel'] }}\napp.get('/posts', query(schema));\napp.get('/articles', query(schema));\n```\n\n### Advanced schema\n```js\nimport { middleware as query, Schema } from 'querymen';\n\nconst schema = new Schema({\n  active: Boolean, // shorthand to { type: Boolean }\n  sort: '-createdAt', // shorthand to { type: String, default: '-createdAt' }\n  term: {\n    type: RegExp,\n    paths: ['title', 'description'],\n    bindTo: 'search' // default was 'query'\n  },\n  with_picture: {\n    type: Boolean,\n    paths: ['picture'],\n    operator: '$exists'\n  }\n}, {\n  page: false, // disable default parameter `page`\n  limit: 'max_items' // change name of default parameter `limit` to `max_items`\n});\n\napp.get('/posts', query(schema), ({ querymen }, res) =\u003e {\n  // user requests /posts?term=awesome\u0026with_picture=true\u0026active=true\u0026max_items=100\n  // querymen.query is { picture: { $exists: true }, active: true }\n  // querymen.cursor is { limit: 100, sort: { createdAt: -1 } }\n  // querymen.search is { $or: [{ title: /awesome/i }, { description: /awesome/i }]}\n});\n```\n\n### Dynamic advanced schema\n```js\nimport { middleware as query, Schema } from 'querymen';\nconst schema = new Schema();\n\nschema.formatter('scream', (scream, value, param) =\u003e {\n  if (scream) {\n    value = value.toUpperCase() + '!!!!!!!';\n  }\n  return value;\n});\n\nschema.param('text', null, { type: String }); // { type: String }\nschema.param('text').option('scream', true); // { type: String, scream: true }\nschema.param('text').value('help');\nconsole.log(schema.param('text').value()); // HELP!!!!!!!\n\nschema.validator('isPlural', (isPlural, value, param) =\u003e {\n  return {\n    valid: !isPlural || value.substr(-1) === 's',\n    message: param.name + ' must be in plural form.'\n  };\n});\n\nschema.param('text').option('isPlural', true); // { type: String, scream: true, isPlural: true }\nconsole.log(schema.validate()); // false\nschema.param('text', 'helps');\nconsole.log(schema.validate()); // true\nconsole.log(schema.param('text').value()); // HELPS!!!!!!!\n\nschema.parser('elemMatch', (elemMatch, value, path, operator) =\u003e {\n  if (elemMatch) {\n    value = { [path]: { $elemMatch: {[elemMatch]: {[operator]: value } }}};\n  }\n  return value;\n});\n\nschema.param('text', 'ivegotcontrols');\nconsole.log(schema.param('text').parse()); // { text: 'IVEGOTCONTROLS!!!!!!!' }\n\nschema.param('text').option('elemMatch', 'prop');\nconsole.log(schema.param('text').parse()); // { text: { $elemMatch: { prop: { $eq: 'IVEGOTCONTROLS!!!!!!!'} }}}\n```\n\n### Geo queries\nQuerymen also support geo queries, but it's disabled by default. To enable geo queries you just need to set `near` option to true in schema options.\n```js\nimport { middleware as query } from 'querymen';\n\napp.get('/places', query({}, { near: true }), (req, res) =\u003e {\n  \n});\n```\nIts `paths` option is set to `['location']` by default, but you can change this as well:\n```js\nimport { middleware as query } from 'querymen';\n\napp.get('/places', \n  query({\n    near: { paths: ['loc'] }\n  }, {\n    near: true\n  }), \n  (req, res) =\u003e {\n  \n  });\n```\nUser requests `/places?near=-22.332113,-44.312311` (latitude, longitude), req.querymen.query will be:\n```js\nreq.querymen.query = {\n  loc: {\n    $near: {\n      $geometry: {\n        type: 'Point',\n        coordinates: [-44.312311, -22.332113]\n      }\n    }\n  }\n}\n```\nUser requests `/places?near=-22.332113,-44.312311\u0026min_distance=200\u0026max_distance=2000` (min_distance and max_distance in meters), req.querymen.query will be:\n```js\nreq.querymen.query = {\n  loc: {\n    $near: {\n      $geometry: {\n        type: 'Point',\n        coordinates: [-44.312311, -22.332113]\n      },\n      $minDistace: 200,\n      $maxDistance: 2000\n    }\n  }\n}\n```\nYou can also use legacy geo queries as well. Just set `geojson` option in param:\n```js\nimport { middleware as query } from 'querymen';\n\napp.get('/places', \n  query({\n    near: {\n      paths: ['loc'],\n      geojson: false\n    }\n  }, {\n    near: true\n  }), \n  (req, res) =\u003e {\n  \n  });\n```\nUser requests `/places?near=-22.332113,-44.312311\u0026min_distance=200\u0026max_distance=2000`, req.querymen.query will be:\n```js\nreq.querymen.query = {\n  loc: {\n    $near: [-44.312311, -22.332113],\n    // convert meters to radians automatically\n    $minDistace: 0.000031,\n    $maxDistance: 0.00031\n  }\n}\n```\n\n### Error handling\n```js\n// user requests /posts?category=world\nimport { middleware as query, querymen, Schema } from 'querymen';\n\nconst schema = new Schema({\n  category: {\n    type: String,\n    enum: ['culture', 'general', 'travel']\n  }\n});\n\napp.get('/posts', query(schema));\n\n// create your own handler\napp.use((err, req, res, next) =\u003e {\n  res.status(400).json(err);\n});\n\n// or use querymen error handler\napp.use(querymen.errorHandler());\n```\nResponse body will look like:\n```json\n{\n  \"valid\": false,\n  \"name\": \"enum\",\n  \"enum\": [\"culture\", \"general\", \"travel\"],\n  \"value\": \"world\",\n  \"message\": \"category must be one of: culture, general, travel\"\n}\n```\n\n## Contributing\n\nThis package was created with [generator-rise](https://github.com/bucaran/generator-rise). Please refer to there to understand the codestyle and workflow. Issues and PRs are welcome! \n\n## License\n\nMIT © [Diego Haz](http://github.com/diegohaz)\n\n[standard-url]: http://standardjs.com\n[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg\n\n[npm-url]: https://npmjs.org/package/querymen\n[npm-image]: https://img.shields.io/npm/v/querymen.svg?style=flat-square\n\n[travis-url]: https://travis-ci.org/diegohaz/querymen\n[travis-image]: https://img.shields.io/travis/diegohaz/querymen.svg?style=flat-square\n\n[coveralls-url]: https://coveralls.io/r/diegohaz/querymen\n[coveralls-image]: https://img.shields.io/coveralls/diegohaz/querymen.svg?style=flat-square\n\n[depstat-url]: https://david-dm.org/diegohaz/querymen\n[depstat-image]: https://david-dm.org/diegohaz/querymen.svg?style=flat-square\n\n[download-badge]: http://img.shields.io/npm/dm/querymen.svg?style=flat-square\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiegohaz%2Fquerymen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiegohaz%2Fquerymen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiegohaz%2Fquerymen/lists"}