mon

mongolass

Elegant MongoDB driver for Node.js.

Showing:

Popularity

Downloads/wk

42

GitHub Stars

427

Maintenance

Last Commit

1yr ago

Contributors

5

Package

Dependencies

8

Size (min+gzip)

279.2KB

License

MIT

Type Definitions

Tree-Shakeable

No?

Readme

Mongolass

NPM version Build status Dependency Status License Downloads

Elegant MongoDB driver for Node.js.

Installation

$ npm i mongolass --save

Usage

const Mongolass = require('mongolass')
const mongolass = new Mongolass()
mongolass.connect('mongodb://localhost:27017/test')// const mongolass = new Mongolass('mongodb://localhost:27017/test')

const User = mongolass.model('User')

User
  .find()
  .select({ name: 1, age: 1 })
  .sort({ name: -1 })
  .exec()
  .then(console.log)
  .catch(console.error)

Or use optional schema:

const Mongolass = require('mongolass')
const Schema = Mongolass.Schema
const mongolass = new Mongolass('mongodb://admin:123456@localhost:27017/admin', {
  dbName: 'testdb'
})

const UserSchema = new Schema('UserSchema', {
  name: { type: 'string', required: true },
  age: { type: 'number', default: 18 }
})
const User = mongolass.model('User', UserSchema)

/*
equal to:
const User = mongolass.model('User', {
  name: { type: 'string', required: true },
  age: { type: 'number', default: 18 }
})
will create inner schema named `UserSchema`.
*/

User
  .insertOne({ name: 'nswbmw', age: 'wrong age' })
  .exec()
  .then(console.log)
  .catch(console.error)
/*
{ TypeError: ($.age: "wrong age") ✖ (type: number)
    at Model.insertOne (/Users/nswbmw/Desktop/test/node_modules/mongolass/lib/query.js:101:16)
    at Object.<anonymous> (/Users/nswbmw/Desktop/test/app.js:21:4)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Function.Module.runMain (module.js:676:10)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3
  validator: 'type',
  path: '$.age',
  actual: 'wrong age',
  expected: { type: 'number', default: 18 },
  schema: 'UserSchema',
  model: 'User',
  op: 'insertOne',
  args: [ { name: 'nswbmw', age: 'wrong age' } ],
  pluginName: 'MongolassSchema',
  pluginOp: 'beforeInsertOne',
  pluginArgs: [] }
*/

ObjectId schema:

'use strict'

const Mongolass = require('mongolass')
const mongolass = new Mongolass('mongodb://localhost:27017/test')

const Post = mongolass.model('Post', {
  author: { type: Mongolass.Types.ObjectId }
}, { collName: 'post' })

Post.insertOne({ author: '111111111111111111111111' })
  .then(function () {
    return Post.find({ author: '111111111111111111111111' })
  })
  .then(console.log)
/*
[ { _id: 57caed24ecda6ffb15962591,
    author: 111111111111111111111111 } ]
 */

NB: You can pass collName as collection name.

API

Same as node-mongodb-native.

Mongolass vs Mongoose

知乎:从零开始写一个 Node.js 的 MongoDB 驱动库


I've been using Mongoose for years, it's great but complex sucks, so i wrote Mongolass. Mongolass is not simply mimicking Mongoose, but rather draw on the advantages of mongoose redesigned the architecture. Mongolass has some exciting features different from Mongoose:

  1. Pure Schema. In Mongoose, Schema and Model and Entity are confused.

    Schemas not only define the structure of your document and casting of properties, they also define document instance methods, static Model methods, compound indexes and document lifecycle hooks called middleware.

    In Mongolass, Schema is only used for defining the structure of your document and casting of properties, Model used for retrievaling data from mongodb and register plugins, Entity(as result) is plain object. Schema is also optional.

  2. Awesome plugin system. Mongoose plugin system is not strong enough, eg: .pre, .post, use async next(). In Mongolass, we can register a plugin for Model or global mongolass instance. like:

    User.plugin('xx', {
      beforeFind: function (...args) {},// or function return Promise
      afterFind: async function (result, ...args) {
        console.log(result, args)
        ...
      },
      // afterFind: async function (result, ...args) {
      //   console.log(result, args)
      //   ...
      // }
    })
    

    Above added two hook functions for User, when User.find().xx().exec() is called, the execution order is as follows:

    beforeFind(handle query args) -> retrieve data from mongodb -> afterFind(handle query result)
    

    Mongolass's plugins could be substituted for Mongoose's (document instance methods + static Model methods + plugins).

  3. Detailed error informations. see usage.

    User
      .insertOne({ name: 'nswbmw', age: 'wrong age' })
      .exec()
      .then(console.log)
      .catch(console.error)
    /*
    { TypeError: ($.age: "wrong age") ✖ (type: number)
        at Model.insertOne (/Users/nswbmw/Desktop/test/node_modules/mongolass/lib/query.js:105:16)
        at Object.<anonymous> (/Users/nswbmw/Desktop/test/app.js:23:4)
        at Module._compile (module.js:573:30)
        at Object.Module._extensions..js (module.js:584:10)
        at Module.load (module.js:507:32)
        at tryModuleLoad (module.js:470:12)
        at Function.Module._load (module.js:462:3)
        at Function.Module.runMain (module.js:609:10)
        at startup (bootstrap_node.js:158:16)
        at bootstrap_node.js:598:3
      validator: 'type',
      actual: 'wrong age',
      expected: { type: 'number' },
      path: '$.age',
      schema: 'UserSchema',
      model: 'User',
      op: 'insertOne',
      args: [ { name: 'nswbmw', age: 'wrong age' } ],
      pluginName: 'MongolassSchema',
      pluginOp: 'beforeInsertOne',
      pluginArgs: [] }
    */
    

    According to the error instance, esay to know age expect a number but got a string, from error stack know it's broken on app.js:23:4 and the operator is Model.insertOne.

Schema

see another-json-schema, support default and required.

required

const Mongolass = require('mongolass')
const mongolass = new Mongolass('mongodb://localhost:27017/test')

const User = mongolass.model('User', {
  name: { type: 'string', required: true },
  age: { type: 'number', default: 18 }
})

;(async function () {
  await User.insert({ age: 17 })
})().catch(console.error)

Output:

{ TypeError: ($.name: undefined) ✖ (required: true)
    at Model.insert (/Users/nswbmw/Desktop/test/node_modules/mongolass/lib/query.js:101:16)
    at /Users/nswbmw/Desktop/test/app.js:10:14
    at Object.<anonymous> (/Users/nswbmw/Desktop/test/app.js:11:3)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Function.Module.runMain (module.js:676:10)
    at startup (bootstrap_node.js:187:16)
  validator: 'required',
  path: '$.name',
  actual: undefined,
  expected: { type: 'string', required: true },
  schema: 'UserSchema',
  model: 'User',
  op: 'insert',
  args: [ { age: 17 } ],
  pluginName: 'MongolassSchema',
  pluginOp: 'beforeInsert',
  pluginArgs: [] }

default

const Mongolass = require('mongolass')
const mongolass = new Mongolass('mongodb://localhost:27017/test')

const User = mongolass.model('User', {
  name: { type: 'string', required: true },
  age: { type: 'number', default: 18 },
  createdAt: { type: Mongolass.Types.Date, default: Date.now }
})

;(async function () {
  await User.insert({ name: 'nswbmw' })
  const user = await User.findOne({ name: 'nswbmw' })
  console.log(user)
  // { _id: 5a530c5d39d9a4eb3aa57856, name: 'nswbmw', age: 18, createdAt: 2019-01-10T09:50:26.831Z }
})()

Types

  • string
  • number
  • boolean
  • Mongolass.Types.ObjectId
  • Mongolass.Types.String
  • Mongolass.Types.Number
  • Mongolass.Types.Date
  • Mongolass.Types.Buffer
  • Mongolass.Types.Boolean
  • Mongolass.Types.Mixed

What's difference between number and Mongolass.Types.Number ? number only check type, Mongolass.Types.Number will try to convert value to a number, if failed then throw error.

Plugins

mongolass.plugin(pluginName, hooks)// register global plugin
User.plugin(pluginName, hooks)// register model plugin

example:

const moment = require('moment')
const Mongolass = require('mongolass')
const mongolass = new Mongolass('mongodb://localhost:27017/test')
const User = mongolass.model('User')

mongolass.plugin('addCreatedAt', {
  beforeInsert: function (format) {
    console.log('beforeInsert', this._op, this._args, format)
    // beforeInsert insert [ { firstname: 'san', lastname: 'zhang' } ] YYYY-MM-DD
    this._args[0].createdAt = moment().format(format)
  }
})

User.plugin('addFullname', {
  afterFindOne: function (user, opt) {
    console.log('afterFindOne', this._op, this._args, opt)
    // afterFindOne findOne [] { sep: '-' }
    if (!user) return user
    user.fullname = user.firstname + opt.sep + user.lastname
    return user
  },
  afterFind: async function (users, opt) {
    console.log('afterFind', this._op, this._args, opt)
    // afterFind find [ { firstname: 'san' } ] { sep: ' ' }
    if (!users.length) return users
    return users.map(user => {
      user.fullname = user.firstname + opt.sep + user.lastname
      return user
    })
  }
})

;(async function () {
  // when use await, .exec() is omissible.
  await User.insert({ firstname: 'san', lastname: 'zhang' }).addCreatedAt('YYYY-MM-DD')
  console.log(await User.findOne().addFullname({ sep: '-' }))
  // { _id: 5850186544c3b82d23a82e45,
  //   firstname: 'san',
  //   lastname: 'zhang',
  //   createdAt: '2016-12-13',
  //   fullname: 'san-zhang' }
  console.log(await User.find({ firstname: 'san' }).addFullname({ sep: ' ' }))
  // [ { _id: 5850186544c3b82d23a82e45,
  //     firstname: 'san',
  //     lastname: 'zhang',
  //     createdAt: '2016-12-13',
  //     fullname: 'san zhang' } ]
})().catch(console.error)

NOTE: Different order of calling plugins will output different results. The priority of Model's plugins is greater than global's.

example:

const Mongolass = require('mongolass')
const mongolass = new Mongolass('mongodb://localhost:27017/test')
const User = mongolass.model('User')

User.plugin('add2', {
  afterFindOne: function (user) {
    if (!user) return user
    user.name = `${user.name}2`
    return user
  }
})
User.plugin('add3', {
  afterFindOne: async function (user) {
    if (!user) return user
    user.name = `${user.name}3`
    return user
  }
})

;(async function () {
  await User.insert({ name: '1' })
  console.log(await User.findOne().add2().add3())
  // { _id: 58501a8a7cc264af259ca691, name: '123' }
  console.log(await User.findOne().add3().add2())
  // { _id: 58501a8a7cc264af259ca691, name: '132' }
})().catch(console.error)

see mongolass-plugin-populate.

Built-in plugins

Mongolass has some built-in plugins, only for find and findOne.

example:

const Mongolass = require('mongolass')
const mongolass = new Mongolass('mongodb://localhost:27017/test')
const User = mongolass.model('User')

;(async function () {
  await User.insert({ name: '1' })
  await User.insert({ name: '2' })
  const result = await User
    .find()
    .skip(1)
    .limit(1)
  console.log(result)
  // [ { _id: 58501c1281ea915a2760a2ee, name: '2' } ]
})().catch(console.error)

Test

$ npm test (coverage 100%)

License

MIT

Rate & Review

Great Documentation0
Easy to Use0
Performant0
Highly Customizable0
Bleeding Edge0
Responsive Maintainers0
Poor Documentation0
Hard to Use0
Slow0
Buggy0
Abandoned0
Unwelcoming Community0
100
No reviews found
Be the first to rate

Alternatives

tyranidMetadata Library for node.js
User RatingN/A
Top Feedback
N/A
GitHub Stars
6
Weekly Downloads
15
jug
jugglingdbMulti-database ORM for nodejs: redis, mongodb, mysql, sqlite3, postgresql, arango, in-memory...
User Rating
4.5/ 5
2
Top Feedback
1Great Documentation
1Highly Customizable
GitHub Stars
2K
Weekly Downloads
1K
der
derivejsDeriveJS is a reactive ODM - Object Document Mapper - framework, a "wrapper" around a database, that removes all the hassle of data-persistence by handling it transparently in the background, in a DRY manner.
User Rating
5.0/ 5
2
Top Feedback
2Great Documentation
2Easy to Use
GitHub Stars
50
Weekly Downloads
49
mongooseMongoDB object modeling designed to work in an asynchronous environment.
User Rating
4.7/ 5
208
Top Feedback
65Great Documentation
60Easy to Use
55Performant
GitHub Stars
23K
Weekly Downloads
2M
typeormORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.
User Rating
4.4/ 5
74
Top Feedback
12Poor Documentation
11Easy to Use
7Performant
GitHub Stars
26K
Weekly Downloads
810K
See 11 Alternatives

Tutorials

No tutorials found
Add a tutorial