Schema-less, multi-tenancy ODM for MongoDB.

Plato's Model

A schema-less, multi-tenancy ODM for MongoDB.

$ npm install platos-model

A Model is representative of a set of similar collections (one per tenant). Creating them is easy:

var Platos = require("platos-model");

var Model = Platos.create("Model");

There's no need to define a schema, we're using document storage so you shouldn't box yourself in. Instead, your Model provides a convenient location for housing common methods and operations relevant to your domain logic. Here's an example:

var Customer = Platos.create("Customer");

//All customers receive a default balance of $20
Customer.prototype.balance = 20;

Customer.prototype.spend = function (amount) {
    this.balance -= amount;

This Model can then be accessed anywhere from within your package just by referencing platos-model:

var Customer = require("platos-model").Customer;

Following along from the example above, you'll want to create an instance of your Model:

var bob = new Customer({ name: "Bob", email: "" });
//Bob now has a balance of $15

And of course, this is easily saved to MongoDB: (err, customer) {
    //'err' will contain any errors
    //'customer' will contain the newly saved document => { "name": "Bob", "balance": 15 }

Once saved, you can retrieve the document again with the static Model.find() method:

Customer.find({ balance: 15 }, function (err, customers) {
    //'customers' will contain an Array of all customers with a balance of 15

If you don't have a reference to an existing Model (which is very likely in large-scale applications), you can update it in-place without finding it.

Customer.update({ name: "Bob" }, { balance: 50 }, callback);

Or alternatively, if you know some of the existing properties, you can create a partial instance and update based on determined keys:

var bob = new Customer({ name: "Bob", balance: 60 });
bob.update([ "name" ], function (err, updateCount) {
    //All customers named "Bob" will have their balance set to 60
    //and all other existing properties will remain the same

If you're building a web app, you'll probably have multiple clients running on the same codebase. It's easy to store different clients' data into separate collections with multi-tenancy:"tenant", function (err, customer) { });

Likewise, you can easily search tenant-specific collections:

Customer.find("tenant", { name: "Bob" }, function (err, customers) {
    //'customers' will contain an Array of customers named Bob in the 'tenant.Customer' collection.

Plato's Model encourages the use of Node's standard functional inheritance pattern:

var Employee = Platos.create("Employee"); = function () {
    console.log("Oh no!")

var Manager = Platos.create("Manager");
util.inherits(Manager, Employee);

var frank = new Manager();;   // > "Oh no!"

This works as expected but as an added bonus, Plato's Model will internally store child classes in the same Mongo collection and handle mapping to your models automatically:

(new Employee()).save();
(new Manager()).save();
(new Employee()).save();

Employee.find(function (employees) {
    //employees = [ Employee, Manager, Employee ];

//Coming soon (**not yet implemented**):
Manager.find(function (managers) {
    //managers = [ Manager ];

The documentation is lacking at the moment so explore the codebase and look at the tests to get a feeling for what else is possible!

Run tests using Make or npm:

$ npm test
$ make test-unit
$ make test-integration

All contributions are welcome! I'm happy to accept pull requests as long as they conform to the following guidelines:

  • Keep the API clean, we prefer ease-of-use over extra features
  • Don't break the build and add tests where necessary
  • Keep the coding style consistent, we follow JSHint's Coding Style

Otherwise, please open an issue if you have any suggestions or find a bug.

The MIT License (MIT) - Copyright (c) 2013 Clear Learning Systems