At my
company we've created a new Node.js MongoDB ODM called mongolayer which we've released as open source (
github,
npm). The idea behind it is similar to Mongoose but very different in execution. Mongolayer handles declaration of Models (mongoose's schemas), validation of data, creation of Document methods, creation of Document properties, model methods, relationship management, and has a powerful hook system. This is shameless promotion so I'm not sure if this belongs here, but I think it is a useful package which could be helpful to other Node.js mongodb users out there who may have grown frustrated with some of the eccentricities of the most commonly used Node.js ODM - mongoose.
Here is a list of some of the important features:
- Built upon node-mongodb-native.
- Supports the common queries with validation, required, defaults and hooks - find(), findById(), insert(), update(), save(), count(), and remove().
- Fully recursive population of relationships. The relationships which are pulled in are declared at query time and can go infinitely deep. So relationships can have relationships. Mongoose does not support this feature.
- Pulled in related records records remain instanceof their defined model.Document. This means they have all virtuals and document methods which were declared in that model. Mongoose does not support this feature.
- Primitive type-strict: If a field is declared as boolean, then you must pass boolean true. "true" or "1" will not pass validation. Mongolayer doesn't do any casting magic under the hood, which I think makes it more consistent for developers and makes the underlying code far simpler.
- The structure of most queries more closely adheres to the syntax that node-mongodb-native uses than mongoose. In example sorting in mongo-db-native is done by sort : { field : 1, field2 : -1 }, so we do it the same as well. In example, this means we do not automatically wrap update() queries in a $set like Mongoose does. If you want to run a $set update operator, then you have to pass it that way, without it you'll get a full doc replacement which is exactly the way node-mongodb-native and mongodb shell operate.
- Unlike mongoose, save() has a similar query syntax to the other queries, rather than requiring new Doc() syntax.
- Update() and save() both run validation and hooks.
- Powerful hook system allowing developers to do a ton of really cool things.
Hooks run before and after certain queries and can be required (so they always run), or passed at query time. In example, lets say every time a developer does a find() on your Model, you want to also async query some non-mongodb data and fold it into the result set, or async write an entry to a log, or transform a filter before the query is executed, you can create hooks for all of that. The hooks all receive control flow and all operate async to the possibilities are endless. You can operate as many hooks as you want, and you can also execute hooks on related models. In fact the entire relationship system is written using hooks (dogfood).
Lastly, the reason we decided to create our own rather than simply contributing to mongoose is two fold. First, competition is good. Second, contributing to mongoose is very challenging due to the size and scale of the code base. We needed the hook system for a variety of reasons and adding that to Mongoose looked a very daunting endeavor and may conflict with existing implementations and the vision of that module. I think we cover the majority of Mongoose's commonly used features and do it in roughly 20x less code.
If you have any questions feel free to hit me up here or on github!
Thanks,
Owen Allen