{"id":15040572,"url":"https://github.com/nswbmw/mongolass","last_synced_at":"2025-04-06T13:10:33.160Z","repository":{"id":57301900,"uuid":"53487901","full_name":"nswbmw/mongolass","owner":"nswbmw","description":"Elegant MongoDB driver for Node.js.","archived":false,"fork":false,"pushed_at":"2020-09-22T10:19:54.000Z","size":122,"stargazers_count":432,"open_issues_count":2,"forks_count":28,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-03-30T11:11:09.588Z","etag":null,"topics":["mongodb","nodejs","odm","schema"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nswbmw.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-09T10:07:53.000Z","updated_at":"2025-02-11T15:48:31.000Z","dependencies_parsed_at":"2022-08-24T17:11:47.165Z","dependency_job_id":null,"html_url":"https://github.com/nswbmw/mongolass","commit_stats":null,"previous_names":["mongolass/mongolass"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nswbmw%2Fmongolass","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nswbmw%2Fmongolass/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nswbmw%2Fmongolass/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nswbmw%2Fmongolass/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nswbmw","download_url":"https://codeload.github.com/nswbmw/mongolass/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247485287,"owners_count":20946398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mongodb","nodejs","odm","schema"],"created_at":"2024-09-24T20:44:45.313Z","updated_at":"2025-04-06T13:10:33.141Z","avatar_url":"https://github.com/nswbmw.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Mongolass\n\n[![NPM version][npm-image]][npm-url]\n[![Build status][travis-image]][travis-url]\n[![Dependency Status][david-image]][david-url]\n[![License][license-image]][license-url]\n[![Downloads][downloads-image]][downloads-url]\n\nElegant MongoDB driver for Node.js.\n\n## Installation\n\n```bash\n$ npm i mongolass --save\n```\n\n## Usage\n\n```js\nconst Mongolass = require('mongolass')\nconst mongolass = new Mongolass()\nmongolass.connect('mongodb://localhost:27017/test')// const mongolass = new Mongolass('mongodb://localhost:27017/test')\n\nconst User = mongolass.model('User')\n\nUser\n  .find()\n  .select({ name: 1, age: 1 })\n  .sort({ name: -1 })\n  .exec()\n  .then(console.log)\n  .catch(console.error)\n```\n\nOr use **optional** schema:\n\n```js\nconst Mongolass = require('mongolass')\nconst Schema = Mongolass.Schema\nconst mongolass = new Mongolass('mongodb://admin:123456@localhost:27017/admin', {\n  dbName: 'testdb'\n})\n\nconst UserSchema = new Schema('UserSchema', {\n  name: { type: 'string', required: true },\n  age: { type: 'number', default: 18 }\n})\nconst User = mongolass.model('User', UserSchema)\n\n/*\nequal to:\nconst User = mongolass.model('User', {\n  name: { type: 'string', required: true },\n  age: { type: 'number', default: 18 }\n})\nwill create inner schema named `UserSchema`.\n*/\n\nUser\n  .insertOne({ name: 'nswbmw', age: 'wrong age' })\n  .exec()\n  .then(console.log)\n  .catch(console.error)\n/*\n{ TypeError: ($.age: \"wrong age\") ✖ (type: number)\n    at Model.insertOne (/Users/nswbmw/Desktop/test/node_modules/mongolass/lib/query.js:101:16)\n    at Object.\u003canonymous\u003e (/Users/nswbmw/Desktop/test/app.js:21:4)\n    at Module._compile (module.js:635:30)\n    at Object.Module._extensions..js (module.js:646:10)\n    at Module.load (module.js:554:32)\n    at tryModuleLoad (module.js:497:12)\n    at Function.Module._load (module.js:489:3)\n    at Function.Module.runMain (module.js:676:10)\n    at startup (bootstrap_node.js:187:16)\n    at bootstrap_node.js:608:3\n  validator: 'type',\n  path: '$.age',\n  actual: 'wrong age',\n  expected: { type: 'number', default: 18 },\n  schema: 'UserSchema',\n  model: 'User',\n  op: 'insertOne',\n  args: [ { name: 'nswbmw', age: 'wrong age' } ],\n  pluginName: 'MongolassSchema',\n  pluginOp: 'beforeInsertOne',\n  pluginArgs: [] }\n*/\n```\n\nObjectId schema:\n\n```js\n'use strict'\n\nconst Mongolass = require('mongolass')\nconst mongolass = new Mongolass('mongodb://localhost:27017/test')\n\nconst Post = mongolass.model('Post', {\n  author: { type: Mongolass.Types.ObjectId }\n}, { collName: 'post' })\n\nPost.insertOne({ author: '111111111111111111111111' })\n  .then(function () {\n    return Post.find({ author: '111111111111111111111111' })\n  })\n  .then(console.log)\n/*\n[ { _id: 57caed24ecda6ffb15962591,\n    author: 111111111111111111111111 } ]\n */\n```\n**NB:** You can pass `collName` as collection name.\n\n## API\n\nSame as [node-mongodb-native](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html).\n\n## Mongolass vs Mongoose\n\n知乎：[从零开始写一个 Node.js 的 MongoDB 驱动库](https://zhuanlan.zhihu.com/p/24308524)\n\n----------------------------\n\nI'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:\n\n1. Pure Schema. In Mongoose, Schema and Model and Entity are confused.\n\n  \u003e 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.\n\n  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.\n\n2. 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:\n\n  ```js\n  User.plugin('xx', {\n    beforeFind: function (...args) {},// or function return Promise\n    afterFind: async function (result, ...args) {\n      console.log(result, args)\n      ...\n    },\n    // afterFind: async function (result, ...args) {\n    //   console.log(result, args)\n    //   ...\n    // }\n  })\n  ```\n\n  Above added two hook functions for `User`, when `User.find().xx().exec()` is called, the execution order is as follows:\n\n  ```\n  beforeFind(handle query args) -\u003e retrieve data from mongodb -\u003e afterFind(handle query result)\n  ```\n\n  Mongolass's plugins could be substituted for Mongoose's (document instance methods + static Model methods + plugins).\n\n3. Detailed error informations. see [usage](https://github.com/mongolass/mongolass#usage).\n\n  ```js\n  User\n    .insertOne({ name: 'nswbmw', age: 'wrong age' })\n    .exec()\n    .then(console.log)\n    .catch(console.error)\n  /*\n  { TypeError: ($.age: \"wrong age\") ✖ (type: number)\n      at Model.insertOne (/Users/nswbmw/Desktop/test/node_modules/mongolass/lib/query.js:105:16)\n      at Object.\u003canonymous\u003e (/Users/nswbmw/Desktop/test/app.js:23:4)\n      at Module._compile (module.js:573:30)\n      at Object.Module._extensions..js (module.js:584:10)\n      at Module.load (module.js:507:32)\n      at tryModuleLoad (module.js:470:12)\n      at Function.Module._load (module.js:462:3)\n      at Function.Module.runMain (module.js:609:10)\n      at startup (bootstrap_node.js:158:16)\n      at bootstrap_node.js:598:3\n    validator: 'type',\n    actual: 'wrong age',\n    expected: { type: 'number' },\n    path: '$.age',\n    schema: 'UserSchema',\n    model: 'User',\n    op: 'insertOne',\n    args: [ { name: 'nswbmw', age: 'wrong age' } ],\n    pluginName: 'MongolassSchema',\n    pluginOp: 'beforeInsertOne',\n    pluginArgs: [] }\n  */\n  ```\n\n  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`.\n\n## Schema\n\nsee [another-json-schema](https://github.com/nswbmw/another-json-schema), support `default` and `required`.\n\n#### required\n\n```js\nconst Mongolass = require('mongolass')\nconst mongolass = new Mongolass('mongodb://localhost:27017/test')\n\nconst User = mongolass.model('User', {\n  name: { type: 'string', required: true },\n  age: { type: 'number', default: 18 }\n})\n\n;(async function () {\n  await User.insert({ age: 17 })\n})().catch(console.error)\n```\n\nOutput:\n\n```js\n{ TypeError: ($.name: undefined) ✖ (required: true)\n    at Model.insert (/Users/nswbmw/Desktop/test/node_modules/mongolass/lib/query.js:101:16)\n    at /Users/nswbmw/Desktop/test/app.js:10:14\n    at Object.\u003canonymous\u003e (/Users/nswbmw/Desktop/test/app.js:11:3)\n    at Module._compile (module.js:635:30)\n    at Object.Module._extensions..js (module.js:646:10)\n    at Module.load (module.js:554:32)\n    at tryModuleLoad (module.js:497:12)\n    at Function.Module._load (module.js:489:3)\n    at Function.Module.runMain (module.js:676:10)\n    at startup (bootstrap_node.js:187:16)\n  validator: 'required',\n  path: '$.name',\n  actual: undefined,\n  expected: { type: 'string', required: true },\n  schema: 'UserSchema',\n  model: 'User',\n  op: 'insert',\n  args: [ { age: 17 } ],\n  pluginName: 'MongolassSchema',\n  pluginOp: 'beforeInsert',\n  pluginArgs: [] }\n```\n\n#### default\n\n```js\nconst Mongolass = require('mongolass')\nconst mongolass = new Mongolass('mongodb://localhost:27017/test')\n\nconst User = mongolass.model('User', {\n  name: { type: 'string', required: true },\n  age: { type: 'number', default: 18 },\n  createdAt: { type: Mongolass.Types.Date, default: Date.now }\n})\n\n;(async function () {\n  await User.insert({ name: 'nswbmw' })\n  const user = await User.findOne({ name: 'nswbmw' })\n  console.log(user)\n  // { _id: 5a530c5d39d9a4eb3aa57856, name: 'nswbmw', age: 18, createdAt: 2019-01-10T09:50:26.831Z }\n})()\n```\n\n## Types\n\n- string\n- number\n- boolean\n- Mongolass.Types.ObjectId\n- Mongolass.Types.String\n- Mongolass.Types.Number\n- Mongolass.Types.Date\n- Mongolass.Types.Buffer\n- Mongolass.Types.Boolean\n- Mongolass.Types.Mixed\n\n**What's difference between `number` and `Mongolass.Types.Number` ?**\n`number` only check type, `Mongolass.Types.Number` will try to convert value to a number, if failed then throw error.\n\n## Plugins\n\n```js\nmongolass.plugin(pluginName, hooks)// register global plugin\nUser.plugin(pluginName, hooks)// register model plugin\n```\n\nexample:\n\n```js\nconst moment = require('moment')\nconst Mongolass = require('mongolass')\nconst mongolass = new Mongolass('mongodb://localhost:27017/test')\nconst User = mongolass.model('User')\n\nmongolass.plugin('addCreatedAt', {\n  beforeInsert: function (format) {\n    console.log('beforeInsert', this._op, this._args, format)\n    // beforeInsert insert [ { firstname: 'san', lastname: 'zhang' } ] YYYY-MM-DD\n    this._args[0].createdAt = moment().format(format)\n  }\n})\n\nUser.plugin('addFullname', {\n  afterFindOne: function (user, opt) {\n    console.log('afterFindOne', this._op, this._args, opt)\n    // afterFindOne findOne [] { sep: '-' }\n    if (!user) return user\n    user.fullname = user.firstname + opt.sep + user.lastname\n    return user\n  },\n  afterFind: async function (users, opt) {\n    console.log('afterFind', this._op, this._args, opt)\n    // afterFind find [ { firstname: 'san' } ] { sep: ' ' }\n    if (!users.length) return users\n    return users.map(user =\u003e {\n      user.fullname = user.firstname + opt.sep + user.lastname\n      return user\n    })\n  }\n})\n\n;(async function () {\n  // when use await, .exec() is omissible.\n  await User.insert({ firstname: 'san', lastname: 'zhang' }).addCreatedAt('YYYY-MM-DD')\n  console.log(await User.findOne().addFullname({ sep: '-' }))\n  // { _id: 5850186544c3b82d23a82e45,\n  //   firstname: 'san',\n  //   lastname: 'zhang',\n  //   createdAt: '2016-12-13',\n  //   fullname: 'san-zhang' }\n  console.log(await User.find({ firstname: 'san' }).addFullname({ sep: ' ' }))\n  // [ { _id: 5850186544c3b82d23a82e45,\n  //     firstname: 'san',\n  //     lastname: 'zhang',\n  //     createdAt: '2016-12-13',\n  //     fullname: 'san zhang' } ]\n})().catch(console.error)\n```\n\n**NOTE**: Different order of calling plugins will output different results. The priority of Model's plugins is greater than global's.\n\nexample:\n\n```js\nconst Mongolass = require('mongolass')\nconst mongolass = new Mongolass('mongodb://localhost:27017/test')\nconst User = mongolass.model('User')\n\nUser.plugin('add2', {\n  afterFindOne: function (user) {\n    if (!user) return user\n    user.name = `${user.name}2`\n    return user\n  }\n})\nUser.plugin('add3', {\n  afterFindOne: async function (user) {\n    if (!user) return user\n    user.name = `${user.name}3`\n    return user\n  }\n})\n\n;(async function () {\n  await User.insert({ name: '1' })\n  console.log(await User.findOne().add2().add3())\n  // { _id: 58501a8a7cc264af259ca691, name: '123' }\n  console.log(await User.findOne().add3().add2())\n  // { _id: 58501a8a7cc264af259ca691, name: '132' }\n})().catch(console.error)\n```\n\nsee [mongolass-plugin-populate](https://github.com/mongolass/mongolass-plugin-populate).\n\n### Built-in plugins\n\nMongolass has some built-in plugins, only for `find` and `findOne`.\n\n- [limit](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [sort](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [projection(alias: select)](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [fields(alias: select)](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [skip](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [hint](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [populate]()\n- [explain](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [snapshot](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [timeout](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [tailable](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [batchSize](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [returnKey](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [maxScan](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [min](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [max](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [showDiskLoc](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [comment](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [raw](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [promoteLongs](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [promoteValues](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [promoteBuffers](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [readPreference](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [partial](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [maxTimeMS](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [collation](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n- [session](http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find)\n\nexample:\n\n```js\nconst Mongolass = require('mongolass')\nconst mongolass = new Mongolass('mongodb://localhost:27017/test')\nconst User = mongolass.model('User')\n\n;(async function () {\n  await User.insert({ name: '1' })\n  await User.insert({ name: '2' })\n  const result = await User\n    .find()\n    .skip(1)\n    .limit(1)\n  console.log(result)\n  // [ { _id: 58501c1281ea915a2760a2ee, name: '2' } ]\n})().catch(console.error)\n```\n\n## Test\n\n```bash\n$ npm test (coverage 100%)\n```\n\n## License\n\nMIT\n\n[npm-image]: https://img.shields.io/npm/v/mongolass.svg?style=flat-square\n[npm-url]: https://npmjs.org/package/mongolass\n[travis-image]: https://img.shields.io/travis/mongolass/mongolass.svg?style=flat-square\n[travis-url]: https://travis-ci.org/mongolass/mongolass\n[david-image]: http://img.shields.io/david/mongolass/mongolass.svg?style=flat-square\n[david-url]: https://david-dm.org/mongolass/mongolass\n[license-image]: http://img.shields.io/npm/l/mongolass.svg?style=flat-square\n[license-url]: LICENSE\n[downloads-image]: http://img.shields.io/npm/dm/mongolass.svg?style=flat-square\n[downloads-url]: https://npmjs.org/package/mongolass\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnswbmw%2Fmongolass","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnswbmw%2Fmongolass","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnswbmw%2Fmongolass/lists"}