norm

The no-ORM for the most popular no-SQL database. Operates on vanilla JS objects, not complex models. Use the same Mongo methods you're used to from the shell, but with additional safeguards and helpers. Validate data against JSON schemas, rename fields, convert between ObjectIds and strings, handle standardized errors, and more.

Usage no npm install needed!

<script type="module">
  import norm from 'https://cdn.skypack.dev/norm';
</script>

README

Norm.

The no-ORM for the most popular no-SQL database. Operates on vanilla JS objects, not complex models. Use the same Mongo methods you're used to from the shell, but with additional safeguards and helpers. Validate data against JSON schemas, rename fields, convert between ObjectIds and strings, handle standardized errors, and more.

Usage

Can run commands with make or npm run.

  • npm run prepublish: Compiles Coffeescript to Javascript, once.
  • npm run watch: Runs build after every change.
  • npm run test: Runs tests.

Api

Initialization

Basic setup

var MongoClient = require('mongodb')
var Norm = require("norm");

MongoClient.connect("CONNECTION STRING", function(err, db) {
  // handle error
  collection = db.collection("COLLECTION_NAME")

  var schema = {
    field1: {
      type: "string",
      required: true
    }
    // etc...
  };

  // optional, detailed below
  var options = {};

  var norm = new Norm(collection, schema, options);
});

Schema

  • Follows standard (JSON Schema format)[http://json-schema.org/].
  • Can include optional "rename" fields to store data with different names in mongo.
  • Uses is-my-json-valid for conversion (at release, the fastest JSON schema validator for node)

Options

  • name: Used in all error messages. (Default: The name of the collection)
  • additionalProperties: Whether to allow properties not in the schema. (Default: false)
  • shardOn: Name of the key to use as a source for the shard key. This should be a key of an Object Id value.
  • shardKeyName: If shardOn is enabled, the name of the shard key. (Default: "k")
  • shardRotation: If shardOn is enabled, the number of characters to rotate the shard key, for even distribution across shards. (Default: 2)
  • validateIndexes: If true, return an Index error whenever a query would perform a full table scan.
  • standardOptions: Override default options for mongo queries. (Default: {j: true, w: 1, getLastError: 1, safe: true, multi: false, new: true})
  • validatorOptions: Override default options for is-my-json-valid. (Default: {verbose: true})

Queries

For all methods, the following holds.

  • If query argument is a string, then query will be set to {_id: ObjectId(query)}

    • An ObjectId error will be returned if the id is invalid.
  • If the query argument is an array, then the query will be set to {_id: {$in: query.map(ObjectId)}}

    • An ObjectId error will be returned if one or more id of the provided ids are invalid.
    • An Empty will be returned if the array has no elements.
    • If the array contains only one element, the query will instead be set to {_id: ObjectId(query)}
  • In all other cases, the query is treated as a regular mongo query.

    • Returns an Operator error if an unsupported operator is used.
  • Pass a callback to use callback-style. Don't pass a callback, and Norm will return you a Promise. The exception to this is findStream, which always returns a streams.

Reads

  • norm.find(query[, options][, cb])
  • norm.findStream(query[, options])
    • Same as find but returns a stream of results.
  • norm.findOne(query[, options][, cb])
    • Returns a NotFound error if no document matches query
  • norm.count(query[, options][, cb])

Writes

  • norm.create(payload[, options][, cb])
    • Returns an Empty error if payload is empty.
    • Returns a Schema error if schema is violated.
    • Returns a Duplicate error if uniqueness is violated.
  • norm.update(query, operation[, options][, cb])
    • If operation does not contain any root-level update operators ($set, $merge, etc), it will be wrapped with $set.
    • {multi: true} must be passed to update multiple documents at once.
    • Returns an Operator error if an unsupported operator is used.
    • Returns an Empty error if any part of the operation payload is empty.
    • Returns a Schema error if schema is violated.
    • Returns a Duplicate error if uniqueness is violated.
    • DOES NOT return results. Use findAndModify for that, which is somewhat slower.
  • norm.findAndModify(query, operation[, options][, cb])
    • Similar to .update, but returns the result
    • If "multi" option is set, returns an array of results. Otherwise returns a single result.
  • norm.remove(query[, options][, cb])
    • If query argument is a string, then query will be set to {_id: ObjectId(query)}

Decorators

  • norm.decorate(methods, wrapper)
    • methods is an array of strings, each of which should be a Norm method
    • For convenience, Norm.READS and Norm.WRITES are included on the prototype. Norm.OPERATIONS is their concatenation.
    • The wrapper function should be of the signature (methodName, args, operation, cb), where:
      • methodName is the name of the wrapped method
      • args is an array of non-cb arguments passed to the method
      • operation will perform the requested operation
      • cb is the final callback. Remember to pass it the error and results!
      • The context is set to the norm.

For example, the following code will log all db operations:

  norm.decorate(Norm.OPERATIONS, function(methodName, args, operation, cb) {
    var start = Date.now();
    var that = this;
    operation(function(err, result) {
      console.log("Collection:", that.name)
      console.log("Executed:", methodName);
      console.log("Arguments:", args);
      console.log("Errored?", !!err)
      console.log("Time:", Date.now() - start);
      cb(err, result);
    });
  });

Instance properties

  • norm.collection
    • The raw mongo collection passed in as input
  • norm.errors
    • Exposes the error types that can be returned by store methods.
    • These can be created if needed.
    • Available types: NotFound, Schema, ObjectId, Empty, Operator, Sharding, Duplicate

Further work

  • Support for patternProperties