MongoDB query language for in-memory objects
$ npm install mingo
- Supports Dot Notation for both
<array>.<index>
and<document>.<field>
selectors - Query and Projection Operators
- Aggregation Framework Operators
- Support for adding custom operators using
mingo.addOperators
- Match against user-defined types
- Support for aggregaion variables
- ES6 module compatible
- Support integrating with custom collections via mixin
- Query filtering and aggregation streaming.
For documentation on using query operators see mongodb
// Use as es6 module
import mingo from 'mingo'
// or vanilla nodeJS
const mingo = require('mingo')
The $where
operator is not loaded by default and must be explicitly registered if required. See documentation for preferred alternatives.
The default export of the main module only includes Aggregator
, Query
, aggregate()
, find()
, and remove()
.
Only Query and Projection operators are loaded by default when using the main module.
This is done using the side-effect module mingo/init/basic
, and also automatically includes pipeline operators $project
, $skip
, $limit
, and $sort
.
If your application uses most of the available operators or you do not care about bundle size, you can load all operators as shown below.
// Note that doing this effectively imports the entire library into your bundle and unused operators cannot be tree shaked
import 'mingo/init/system'
Or from the node CLI
node -r 'mingo/init/system' myscript.js
The addOperators
function for registering custom operators and helper constants have been moved to mingo/core
.
The constants OP_XXX
have been deprecated and replace with an enum type OperatorType
also in mingo/core
.
The values defined include;
ACCUMULATOR
EXPRESSION
PIPELINE
PROJECTION
QUERY
Lastly, the function argument to addOperators(operatorType, fn)
now accepts an object with the these two internal functions;
computeValue(obj: AnyVal, expr: AnyVal, operator: string, options?: ComputeOptions): AnyVal
resolve(obj: AnyVal, selector: string, options?: ResolveOptions): AnyVal
Any extra utility may be imported directly from the specific module.
Submodule imports are supported for both ES6 and ES5.
The following two examples are equivalent.
This work natively in typescript since it knows how to load commonJS modules as ES6. You may optionally install the esm module to use this syntax.
import { $unwind } from 'mingo/operators/pipeline'
Unlike the ES6 version, it is necessary to specify the operator module in the path to avoid loading any extras
const $unwind = require('mingo/operators/pipeline/unwind').$unwind
To support tree-shaking, you may import and register specific operators that will be used in your application.
import { useOperators, OperatorType } from 'mingo/core'
import { $trunc } from 'mingo/operators/expression'
import { $bucket } from 'mingo/operators/pipeline'
useOperators(OperatorType.EXPRESSION, { $trunc, $floor })
useOperators(OperatorType.PIPELINE, { $bucket })
import { Query } from 'mingo'
// create a query with criteria
// find all grades for homework with score >= 50
let query = new Query({
type: "homework",
score: { $gte: 50 }
});
// test if an object matches query
query.test(doc)
import { Query } from 'mingo'
// input is either an Array or any iterable source (i.e Object{next:Function}) including ES6 generators.
let criteria = { score: { $gt: 10 } }
let query = new Query(criteria)
// filter collection with find()
let cursor = query.find(collection)
// alternatively use shorthand
// cursor = mingo.find(collection, criteria)
// sort, skip and limit by chaining
cursor.sort({student_id: 1, score: -1})
.skip(100)
.limit(100)
// count matches. exhausts cursor
cursor.count()
// classic cursor iterator (old school)
while (cursor.hasNext()) {
console.log(cursor.next())
}
// ES6 iterators (new cool)
for (let value of cursor) {
console.log(value)
}
// all() to retrieve matched objects. exhausts cursor
cursor.all()
To use the $jsonSchema
operator, you must register your own JsonSchemaValidator
in the options.
No default implementation is provided out of the box so users can use a library with their preferred schema format.
The example below uses Ajv to implement schema validation.
import { RawObject } from "mingo/types"
import { JsonSchemaValidator } from "mingo/core"
import Ajv, { Schema } from "ajv"
const jsonSchemaValidator: JsonSchemaValidator = (s: RawObject) => {
const ajv = new Ajv();
const v = ajv.compile(s as Schema);
return (o: RawObject) => (v(o) ? true : false);
};
const schema = {
type: "object",
required: ["item", "qty", "instock"],
properties: {
item: { type: "string" },
qty: { type: "integer" },
size: {
type: "object",
required: ["uom"],
properties: {
uom: { type: "string" },
h: { type: "number" },
w: { type: "number" },
},
},
instock: { type: "boolean" },
},
};
// queries documents using schema validation
find(docs, { $jsonSchema: schema }, {}, { jsonSchemaValidator }).all();
Note: An error is thrown when the $jsonSchema
operator is used without a the jsonSchemaValidator
configured.
import { Aggregator } from 'mingo/aggregator'
import { useOperators, OperatorType } from 'mingo/core'
import { $match, $group } from 'mingo/operators/pipeline'
import { $min } from 'mingo/operators/accumulator'
// ensure the required operators are preloaded prior to using them.
useOperators(OperatorType.PIPELINE, { $match, $group })
useOperators(OperatorType.ACCUMULATOR, { $min })
let agg = new Aggregator([
{'$match': { "type": "homework"}},
{'$group': {'_id':'$student_id', 'score':{$min:'$score'}}},
{'$sort': {'_id': 1, 'score': 1}}
])
// return an iterator for streaming results
let stream = agg.stream(collection)
// return all results. same as `stream.all()`
let result = agg.run(collection)
- Better alternative to writing custom code for transforming collection of objects
- Quick validation of MongoDB queries without the need for a database
- MongoDB query language is among the best in the market and is well documented
- Squash changes into one commit
- Run
npm test
to build and execute unit tests - Submit pull request
MIT