All Projects → diegohaz → querymen

diegohaz / querymen

Licence: other
Querystring parser middleware for MongoDB, Express and Nodejs (MEN)

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to querymen

peerai-api
Peerism's Peer.ai API built with Truffle, Node.js, Express.js, Solidity, and Ethereum TestRPC
Stars: ✭ 18 (-85.94%)
Mutual labels:  mongoose, express-middleware
Mongoose Patch History
Mongoose plugin that saves a history of JSON patch operations for all documents belonging to a schema in an associated 'patches' collection
Stars: ✭ 82 (-35.94%)
Mutual labels:  schema, mongoose
storage
Mongoose-like schema validation, collections and documents on browser (client-side)
Stars: ✭ 17 (-86.72%)
Mutual labels:  schema, mongoose
bodymen
Body parser middleware for MongoDB, Express and Nodejs (MEN)
Stars: ✭ 49 (-61.72%)
Mutual labels:  mongoose, express-middleware
api
docs.nekos.moe/
Stars: ✭ 31 (-75.78%)
Mutual labels:  mongoose
SICP
✨practice for SICP, the wizard book < Structure and Interpretation of Computer Programs >
Stars: ✭ 89 (-30.47%)
Mutual labels:  schema
E-Commerce-Website-Using-NodeJS
🌟 💻 ᴛʜɪꜱ ɪꜱ ᴀ ᴍᴏɴᴏʟɪᴛʜɪᴄ ᴀᴘᴘʟɪᴄᴀᴛɪᴏɴ ᴜꜱɪɴɢ ɴᴏᴅᴇ ᴊꜱ ᴀꜱ ᴀ ʙᴀᴄᴋᴇɴᴅ ᴛᴇᴄʜɴᴏʟᴏɢʏ 🎯 🚀
Stars: ✭ 12 (-90.62%)
Mutual labels:  mongoose
docker-node-express-boilerplate
Boilerplate for quickly bootstrapping production-ready RESTful APIs / microservices
Stars: ✭ 113 (-11.72%)
Mutual labels:  mongoose
Mail
RiiConnect24 Mail Scripts. OSS.
Stars: ✭ 11 (-91.41%)
Mutual labels:  schema
node-js-project-structure
No description or website provided.
Stars: ✭ 21 (-83.59%)
Mutual labels:  mongoose
node-fs
node-fs
Stars: ✭ 55 (-57.03%)
Mutual labels:  mongoose
element-schema-form
A schema-based element-ui form component for Vue2.x.
Stars: ✭ 31 (-75.78%)
Mutual labels:  schema
dhiwise-nodejs
DhiWise Node.js API generator allows you to instantly generate secure REST APIs. Just supply your database schema to DhiWise, and a fully documented CRUD APIs will be ready for consumption in a few simple clicks. The generated code is clean, scalable, and customizable.
Stars: ✭ 224 (+75%)
Mutual labels:  mongoose
lc-spring-data-r2dbc
An extension of spring-data-r2dbc to provide features such as relationships, joins, cascading save/delete, lazy loading, sequence, schema generation, composite id
Stars: ✭ 30 (-76.56%)
Mutual labels:  schema
express-expeditious
flexible caching middleware for express endpoints
Stars: ✭ 42 (-67.19%)
Mutual labels:  express-middleware
reddit-api-clone-2
Build a Reddit API clone. We cover models and build out the rest of our routes!
Stars: ✭ 15 (-88.28%)
Mutual labels:  mongoose
wily
Build Node.js APIs from the command line (Dead Project 😵)
Stars: ✭ 14 (-89.06%)
Mutual labels:  mongoose
express-boilerplate
ExpressJS boilerplate with Socket.IO, Mongoose for scalable projects.
Stars: ✭ 83 (-35.16%)
Mutual labels:  mongoose
sf-java-ui
Json Schema Form java based library allow developers to define schema and form using field annotations
Stars: ✭ 23 (-82.03%)
Mutual labels:  schema
schema-builder
Laravel/Lumen schema builder & migration generator
Stars: ✭ 51 (-60.16%)
Mutual labels:  schema

Querymen

JS Standard Style NPM version Build Status Coveralls Status Dependency Status Downloads

Querystring parser middleware for MongoDB, Express and Nodejs

Install

npm install --save querymen

Examples

Pagination

Querymen has a default schema to handle pagination. This is the most simple and common usage.

import { middleware as query } from 'querymen';

app.get('/posts', query(), ({ querymen: { query, select, cursor } }, res) => {

  Post.find(query, select, cursor).then(posts => {
    // posts are proper paginated here
  });
});

User requests /posts?page=2&limit=20&sort=-createdAt querymen will be:

querymen = {
  query: {},
  select: {},
  cursor: {
    limit: 20, 
    skip: 20, 
    sort: { createdAt: -1 }
  }
}

User requests /posts?q=term&fields=title,desc querymen will be:

When user requests /posts?q=term, querymen parses it to {keywords: /term/i}. It was designed to work with mongoose-keywords plugin, which adds a keywords field to schemas (check that out).

querymen = {
  query: {
    keywords: /term/i
  },
  select: {
    title: 1,
    desc: 1
  },
  cursor: {
    // defaults
    limit: 30, 
    skip: 0, 
    sort: { createdAt: -1 }
  }
}

User requests /posts?fields=-title&sort=name,-createdAt querymen will be:

querymen = {
  query: {},
  select: {
    title: 0
  },
  cursor: {
    limit: 30, 
    skip: 0, 
    sort: {
      name: 1,
      createdAt: -1
    }
  }
}

Custom schema

You can define a custom schema, which will be merged into querymen default schema (explained above).

import { middleware as query } from 'querymen';

app.get('/posts', query({
  after: {
    type: Date,
    paths: ['createdAt'],
    operator: '$gte'
  }
}), ({ querymen }, res) => {
  Post.find(querymen.query).then(posts => {
    // ...
  });
});

User requests /posts?after=2016-04-23 querymen will be:

querymen = {
  query: {
    createdAt: { $gte: 1461369600000 }
  },
  select: {},
  cursor: {
    // defaults
    limit: 30, 
    skip: 0, 
    sort: { createdAt: -1 }
  }
}

Reusable schemas

You can create reusable schemas as well. Just instantiate a Schema object.

import { middleware as query, Schema } from 'querymen';

const schema = new Schema({
  tags: {
    type: [String],
  }
});

// user requests /posts?tags=world,travel
// querymen.query is { tags: { $in: ['world', 'travel'] }}
app.get('/posts', query(schema));
app.get('/articles', query(schema));

Advanced schema

import { middleware as query, Schema } from 'querymen';

const schema = new Schema({
  active: Boolean, // shorthand to { type: Boolean }
  sort: '-createdAt', // shorthand to { type: String, default: '-createdAt' }
  term: {
    type: RegExp,
    paths: ['title', 'description'],
    bindTo: 'search' // default was 'query'
  },
  with_picture: {
    type: Boolean,
    paths: ['picture'],
    operator: '$exists'
  }
}, {
  page: false, // disable default parameter `page`
  limit: 'max_items' // change name of default parameter `limit` to `max_items`
});

app.get('/posts', query(schema), ({ querymen }, res) => {
  // user requests /posts?term=awesome&with_picture=true&active=true&max_items=100
  // querymen.query is { picture: { $exists: true }, active: true }
  // querymen.cursor is { limit: 100, sort: { createdAt: -1 } }
  // querymen.search is { $or: [{ title: /awesome/i }, { description: /awesome/i }]}
});

Dynamic advanced schema

import { middleware as query, Schema } from 'querymen';
const schema = new Schema();

schema.formatter('scream', (scream, value, param) => {
  if (scream) {
    value = value.toUpperCase() + '!!!!!!!';
  }
  return value;
});

schema.param('text', null, { type: String }); // { type: String }
schema.param('text').option('scream', true); // { type: String, scream: true }
schema.param('text').value('help');
console.log(schema.param('text').value()); // HELP!!!!!!!

schema.validator('isPlural', (isPlural, value, param) => {
  return {
    valid: !isPlural || value.substr(-1) === 's',
    message: param.name + ' must be in plural form.'
  };
});

schema.param('text').option('isPlural', true); // { type: String, scream: true, isPlural: true }
console.log(schema.validate()); // false
schema.param('text', 'helps');
console.log(schema.validate()); // true
console.log(schema.param('text').value()); // HELPS!!!!!!!

schema.parser('elemMatch', (elemMatch, value, path, operator) => {
  if (elemMatch) {
    value = { [path]: { $elemMatch: {[elemMatch]: {[operator]: value } }}};
  }
  return value;
});

schema.param('text', 'ivegotcontrols');
console.log(schema.param('text').parse()); // { text: 'IVEGOTCONTROLS!!!!!!!' }

schema.param('text').option('elemMatch', 'prop');
console.log(schema.param('text').parse()); // { text: { $elemMatch: { prop: { $eq: 'IVEGOTCONTROLS!!!!!!!'} }}}

Geo queries

Querymen 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.

import { middleware as query } from 'querymen';

app.get('/places', query({}, { near: true }), (req, res) => {
  
});

Its paths option is set to ['location'] by default, but you can change this as well:

import { middleware as query } from 'querymen';

app.get('/places', 
  query({
    near: { paths: ['loc'] }
  }, {
    near: true
  }), 
  (req, res) => {
  
  });

User requests /places?near=-22.332113,-44.312311 (latitude, longitude), req.querymen.query will be:

req.querymen.query = {
  loc: {
    $near: {
      $geometry: {
        type: 'Point',
        coordinates: [-44.312311, -22.332113]
      }
    }
  }
}

User requests /places?near=-22.332113,-44.312311&min_distance=200&max_distance=2000 (min_distance and max_distance in meters), req.querymen.query will be:

req.querymen.query = {
  loc: {
    $near: {
      $geometry: {
        type: 'Point',
        coordinates: [-44.312311, -22.332113]
      },
      $minDistace: 200,
      $maxDistance: 2000
    }
  }
}

You can also use legacy geo queries as well. Just set geojson option in param:

import { middleware as query } from 'querymen';

app.get('/places', 
  query({
    near: {
      paths: ['loc'],
      geojson: false
    }
  }, {
    near: true
  }), 
  (req, res) => {
  
  });

User requests /places?near=-22.332113,-44.312311&min_distance=200&max_distance=2000, req.querymen.query will be:

req.querymen.query = {
  loc: {
    $near: [-44.312311, -22.332113],
    // convert meters to radians automatically
    $minDistace: 0.000031,
    $maxDistance: 0.00031
  }
}

Error handling

// user requests /posts?category=world
import { middleware as query, querymen, Schema } from 'querymen';

const schema = new Schema({
  category: {
    type: String,
    enum: ['culture', 'general', 'travel']
  }
});

app.get('/posts', query(schema));

// create your own handler
app.use((err, req, res, next) => {
  res.status(400).json(err);
});

// or use querymen error handler
app.use(querymen.errorHandler());

Response body will look like:

{
  "valid": false,
  "name": "enum",
  "enum": ["culture", "general", "travel"],
  "value": "world",
  "message": "category must be one of: culture, general, travel"
}

Contributing

This package was created with generator-rise. Please refer to there to understand the codestyle and workflow. Issues and PRs are welcome!

License

MIT © Diego Haz

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].