Hapi App Mongo Model
Lightweight abstraction layer wrapping Monk api (MongoDB library)
Current version is stable and used in production However it is still work in progress
Rationale
Most popular ODM for MongoDB manipulations from NodeJS is Mongoose. It is build on the top of MongoDB's native driver. It is build with tone of features such us object schemas and validation.
Mongoose is however unnecesary if you would want to reuse Hapi Joi schemas for validation of your model objects or need lower level apis without package overhead.
Hapi-app-mongo-model is provides lightweight abstraction on the top of Monk, which is abstraction over MongoDB native driver.
Core features
- It can be used stand-alone or registered as Hapi plugin with
AppModel.plugin
extension - It allows to register custom
ModelClass
-es - It exposes mongo collection (monk) methods on custom
ModelClasses
, such us:find()
,findOne()
,insert()
, etc. - It allows to create Models before connection is established (no monk drawbacks)
- It exposes sugar methods (returning promises) on
Model Classes
validate()
,findAndParse()
,findOneAndParse()
insertAndParse()
forceFind()
- Helper methods available on
modelObject
:save()
,validate()
toJSON()
toString()
- Ease of extensibility of the Helper and DAO methods ( see examples below )
Using Hapi App Mongo Model
This part provides simple example of how to create and use custom models
Check example
folder for full example code or check test
folder for test specs.
Required files
Let's assume User model lives in folder models/user
, then required files are:
models/user/
models/user/dao.js
models/user/helpers.js
models/user/index.js
models/user/schema.js
Preparing model source files
File: models/user/index.js
var Model = UserModel = Model;moduleexports = UserModel;
File: models/user/dao.js
moduleexports = {}
File: models/user/helpers.js
moduleexports = { return thisfname + ' ' + thislname; }
File: models/user/schema.js
var Joi = userSchema;userSchema = fname: Joi lname: JOimoduleexports = userSchema;
Connecting to databse
Below examples illustrate connecting to database if you run package outside of Hapi application. For using it as hapi plugin scroll to Using Model as plugin with hapi
Model.connect()
Example 1: default connection In below example Model.connect()
is called without any parameters.
Model will attempt to Connect to default mongo db url:
mongodb://localhost:27017
.
var Model = require('hapi-app-mongo-model'),
connectionConfig = {};
Model
.connect()
.then(function (db) {
// ... CRUD
}, function (error) {
throw new Error(error);
});
Model.connect(config)
Example 2: custom connection Config object takes three parameters:
- url - mongodb url, fefault value will be used if it is undefined
- connectionId - identifier is required when there is more than one connection
- opts - setting object passed to native
connect
method
var Model = require('hapi-app-mongo-model'),
connConfig;
connConfig = {
url: 'mongodb://localhost:27017',
connectionID: 'my-awesome-mongo-connection',
opts: {
"db": {
"native_parser": false
}
}
}
Model
.connect(connConfig)
.then(function (db) {
// ... CRUD
}, function (error) {
throw new Error(error);
});
Creating new user object
File: index.js
var User = user; user = fname: 'John' fname: 'Smith'; // call build-in helperconsole; // call local helperconsole;
User Reference
Model.plugin
Using Model as plugin with hapi done, there are no tests yet
var Hapi = require('hapi'),
server = new Hapi.Server();
server.connection({ port: 3000 });
server.register({
"url": "mongodb://localhost:27017/test",
"opts": {
"db": {
"native_parser": false
}
}
}, function (error) {
//...
server.start();
});
Model.db
Shared connection Model.connect(settings)
creates connection that can be accessed via:
Model.db
YourModel.db
yourObject.db
Schamas
Models are required to have schema.js
file which exports model object schema ready for validation with Joi.validate()
.
Simply follow Joi docs to create one. Check example code to see it in action.
Indexes
Uses monk indexing exposed on collection.
Custom Model namespaced methods
Methods exposed on the level of Custom Model are equivalent to collection methods, and so for example call to below method update()
:
var Model = require('hapi-app-mongo-model');
Model.db.collection[{collection-name}].update( ... )
can be conviniently simplified to:
var UserModel = require('/path/to/user-model');
UserModel.update( ... )
Model.register()
Creating Model Classes Method used to generate Custom Model Class takes config object with three parameters:
- collection - name of mongoDB collection
- path - path to Custom Model directory directory with schema, dao and helpers files.
Example Model Class generation:
var Model = require('hapi-app-mongo-model')
modelTaskConfig;
modelTaskConfig = {
collection: "tasks",
path: __dirname
}
module.exports = Model.generate(modelTaskConfig);
Model.find()
Find method Convenience method
Model.findOne()
FindOne method Convenience method
Model.ObjectId()
and Model.ObjectID()
ObjectId via Convenience method
DAO helpers
new ModelClass(collectionName, [object])
Createing object via ModelClass.create(collectionName, [object])
Createing object via Convenience method for new ModelClass(collectionName, [object])
status: implemented but no tests
<ModelClass>.find()
Find Convenience method
<ModelClass>.findOne()
FindOne Convenience method
Custom DAO helpers
todo: missing test to confirm prototypical inheritance with parent class method exposed via _super that will allow to override them in models/model/dao.js
Model Object helpers
<modelObject>.save()
Save Convenience method returns promise
<modelObject>.validate()
Validate Convenience method returns promise
validate()
is async method and returns a promise.
It can be handled in one of two ways as shown below.
Method 1: promise.then(onSuccess, onError)
user.validate()
.then(function onSuccess(data) {
//.. do something with data
}, function onError(error) {
//.. do something with error
});
Method 2: promise.onFulfill(onSuccess).onReject(onError)
user.validate()
.then(function onSuccess(data) {
//.. do something with data
}, function onError(error) {
//.. do something with error
});
Resources
BIG THANK YOU TO ALL THE AUTHORS FOR DEVELOPING THOSE GREAT PACKAGES, FOR MAKING CODING EASIER, FASTER AND MORE FUN!
CHEEERIO!!!
Used HapiJs package
- Hapi - A rich framework for building applications and services
- Hoek - Utility methods for the hapi ecosystem
- Good - Hapi process monitoring
- Boom - HTTP-friendly error objects
- Joi - Object schema description language and validator for JavaScript objects.
Used packages
- aheckmann/mpromise - A promises/A+ conformant implementation
- hapi-mongo-models
- hapi-mongodb