{"id":13431561,"url":"https://github.com/vadimdemedes/mongorito","last_synced_at":"2025-09-28T21:31:17.485Z","repository":{"id":57302390,"uuid":"3458747","full_name":"vadimdemedes/mongorito","owner":"vadimdemedes","description":"🍹 MongoDB ODM for Node.js apps based on Redux","archived":true,"fork":false,"pushed_at":"2020-03-24T17:23:14.000Z","size":2054,"stargazers_count":1389,"open_issues_count":43,"forks_count":103,"subscribers_count":35,"default_branch":"master","last_synced_at":"2024-04-15T12:13:35.829Z","etag":null,"topics":["mongodb","odm"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vadimdemedes.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-02-16T09:53:59.000Z","updated_at":"2024-01-26T09:49:36.000Z","dependencies_parsed_at":"2022-09-20T20:00:20.145Z","dependency_job_id":null,"html_url":"https://github.com/vadimdemedes/mongorito","commit_stats":null,"previous_names":["vdemedes/mongorito"],"tags_count":53,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadimdemedes%2Fmongorito","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadimdemedes%2Fmongorito/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadimdemedes%2Fmongorito/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadimdemedes%2Fmongorito/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vadimdemedes","download_url":"https://codeload.github.com/vadimdemedes/mongorito/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234563151,"owners_count":18853062,"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","odm"],"created_at":"2024-07-31T02:01:04.086Z","updated_at":"2025-09-28T21:31:17.137Z","avatar_url":"https://github.com/vadimdemedes.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cbr\u003e\n  \u003cimg width=\"400\" src=\"media/logo.png\"\u003e\n  \u003cbr\u003e\n  \u003cbr\u003e\n\u003c/h1\u003e\n\n\u003e Lightweight and flexible MongoDB ODM for Node.js apps based on Redux.\n\n[![Build Status](https://travis-ci.org/vadimdemedes/mongorito.svg?branch=master)](https://travis-ci.org/vadimdemedes/mongorito) [![Coverage Status](https://coveralls.io/repos/vadimdemedes/mongorito/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/vadimdemedes/mongorito?branch=master)\n\n\n## Features\n\n**Flexible**\n\nMongorito is based on [Redux](https://github.com/reactjs/redux), which opens the doors for customizing literally everything - from model's state (reducers) to the behavior of core methods, like `set()`, `save()` or `find()`.\n\nEach model instance has a separate Redux store, which ensures isolation between other models and easy extensibility.\n\n**No schemas**\n\nIf MongoDB doesn't enforce schemas, why would Mongorito do? Enjoy the schema-free data management with Mongorito the same way you do in `mongo` console.\n\n**Lightweight**\n\nMongorito is betting on 3rd-party plugins to deliver extra functionality to developers. Mongorito ships with a barebones model with basic get/set, save/remove and querying functionality and let's you be in control of what's included and what's not.\n\nMongorito is basically a tiny Redux-based application, which uses the official MongoDB driver and [mquery](https://github.com/aheckmann/mquery) for querying. Not that amount of lines are relevant when measuring complexity, but each file (module) is less than 300 lines. Check out the source code and see for yourself!\n\n\n## Quick overview\n\n```js\nconst {Database, Model} = require('mongorito');\n\nconst db = new Database('localhost/blog');\nawait db.connect();\n\nclass Post extends Model {}\n\ndb.register(Post);\n\nconst post = new Post({\n\ttitle: 'Steve Angello rocks',\n\tauthor: {\n\t\tname: 'Emma'\n\t}\n});\n\nawait post.save();\n\npost.set('author.name', 'Rick');\nawait post.save();\n\nawait db.disconnect();\n```\n\n*Note*: `await` won't work at top level, it's used to reduce the complexity of an example.\n\n\n## Installation\n\n```\n$ npm install --save mongorito\n```\n\n\n## Contents\n\n- [Connection](#connection)\n- [Models](#models)\n- - [Creating a model](#creating-a-model)\n- - [Working with fields](#working-with-fields)\n- - [Saving or removing documents](#saving-or-removing-documents)\n- - [Incrementing fields](#incrementing-fields)\n- - [Embedding other models](#embedding-other-models)\n- - [Configuration](#configuration)\n- [Queries](#queries)\n- [Plugins](#plugins)\n- - [Using plugins](#using-plugins)\n- - [Writing plugins](#writing-plugins)\n- - [Extending model with new methods](#extending-model-with-new-methods)\n- - [Modifying model's state](#modifying-models-state)\n- - [Changing behavior using middleware](#changing-behavior-using-middleware)\n- [Migrating from legacy version](#migrating-from-legacy-version)\n\n\n## Connection\n\nMongorito exports several own classes, as well as a few properties from the MongoDB driver:\n\n```js\nconst {\n\tDatabase,\n\tModel,\n\tTimestamp,\n\tObjectId,\n\tMinKey,\n\tMaxKey,\n\tDBRef,\n\tLong\n} = require('mongorito');\n```\n\n`Database` and `Model` are Mongorito's own exports, all the other ones are exported straight from [`mongodb`](https://github.com/mongodb/node-mongodb-native) package for convenience. Normally, you'd need only `Database`, `Model` and `ObjectId`.\n\nTo connect, initialize a `Database`, which accepts a MongoDB connection string and an optional configuration which will be passed to mongodb's [connect function](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html).\n\nTo connect and disconnect use `connect()`/`disconnect()` methods. Both returns a Promise.\n\nFor convenience, `await` will be used in all examples below, even though it doesn't work at top level.\n\n```js\nconst {Database, Model} = require('mongorito');\n\nconst db = new Database('localhost/blog', {\n\treconnectTries: 5\n});\n\nawait db.connect();\nawait db.disconnect();\n```\n\nYou don't have to wait until connection establishes to perform operations. Mongorito automatically executes pending operations once connection is up.\n\n## Models\n\n### Creating a model\n\nModel is the connection between your data and a database. Each model represents a single collection. Model is a simple class, which doesn't even need to have any properties or methods.\n\n```js\nclass Post extends Model {}\n```\n\nFor `Post` model to work and be aware of the database it's connected to, make sure to register it in the database we created earlier.\n\n```js\ndb.register(Post);\n```\n\nThat's it, the `Post` model is good to go!\n\n### Working with fields\n\nTo create a new document, create an instance of `Post` model.\n\n```js\nconst post = new Post();\n```\n\nModel's constructor also accepts an object of fields to instantiate the document with:\n\n```js\nconst post = new Post({\n\ttitle: 'Great post',\n\tauthor: {\n\t\tname: 'Sarah'\n\t}\n});\n```\n\nNote, documents can contain nested fields and even models, just like in MongoDB.\n\nTo get one or all fields from the `post` document, use a `get()` method.\n\n```js\nconst title = post.get('title');\n//=\u003e \"Great post\"\n\nconst author = post.get('author.name');\n//=\u003e \"Sarah\"\n\nconst data = post.get();\n//=\u003e\n//  {\n//    title: \"Great post\"\n//    author: {\n//      name: \"Sarah\"\n//    }\n//  }\n```\n\nSimilarly, use `set()` to update fields:\n\n```js\n// update fields one by one\npost.set('title', 'Amazing post');\npost.set('author.name', 'Monica');\n\n// or all at once\npost.set({\n\ttitle: 'Amazing post',\n\tauthor: {\n\t\tname: 'Monica'\n\t}\n});\n```\n\nTo remove a field, use `unset()`:\n\n```js\n// unset single fields\npost.unset('title');\npost.unset('author.name');\n\n// or multiple fields at once\npost.unset(['title', 'author.name']);\n```\n\n### Saving or removing documents\n\nTo create or update documents, simply call `save()`. Even though Mongorito differentiates these two operations internally, you don't have to care about that! Mongorito also infers the collection name from the model, so the instances of the model `Post` will be saved to `posts` collection.\n\n```js\nawait post.save();\n```\n\nWhen a document is saved, an `_id` field is automatically added.\n\n```js\npost.get('_id');\n//=\u003e ObjectId(\"5905cb6b543c3a50e03e810d\")\n```\n\nTo remove a document, use `remove()`.\n\n```js\nawait post.remove();\n```\n\nTo remove multiple documents, use `remove()` on the model itself with a query as an argument.\n\n```js\nawait Post.remove({good: false});\n```\n\n### Incrementing fields\n\nMongorito also provides a handy `increment()` method to increment or decrement numerical fields:\n\n```js\nconst post = new Post({\n\tviews: 0\n});\n\nawait post.increment('views');\n\npost.get('views');\n//=\u003e 1\n```\n\nYou can also supply a value to increment a field by a specific amount.\n\n```js\nawait post.increment('views', 2);\n\npost.get('views');\n//=\u003e 3\n```\n\nMultiple fields can be incremented at once, too.\n\n```js\nconst post = new Post({\n\tviews: 10,\n\tcomments: 10\n});\n\nawait post.increment({\n\tviews: 2,\n\tcomments: 5\n});\n\npost.get('views');\n//=\u003e 12\n\npost.get('comments');\n//=\u003e 15\n```\n\n### Embedding other models\n\nJust like MongoDB, Mongorito allows to effortlessly embed other models. They're transparently converted between JSON and Mongorito models.\n\nTo embed models, use `embeds()` method on the model itself to help Mongorito with the model serialization when saving/reading from the database. `embeds()` method accepts a field name, where the embedded document (or array of documents) resides.\n\nHere's the quick overview on how it works. Note, that model registering via `register()` is skipped in the following example.\n\n```js\nclass Post extends Model {}\nclass Author extends Model {}\nclass Comment extends Model {}\n\nPost.embeds('author', Author);\nPost.embeds('comments', Comment);\n\nconst post = new Post({\n\ttitle: 'Great post',\n\tauthor: new Author({name: 'Steve'}),\n\tcomments: [new Comment({body: 'Interesting!'})]\n});\n\nawait post.save();\n```\n\nThe above post will be saved to the database as:\n\n```json\n{\n\t\"title\": \"Great post\",\n\t\"author\": {\n\t\t\"name\": \"Steve\"\n\t},\n\t\"comments\": [\n\t\t{\n\t\t\t\"body\": \"Interesting!\"\n\t\t}\n\t]\n}\n```\n\nYou can also just pass objects instead of model instances and Mongorito will take care of that too.\n\n```js\nconst post = new Post({\n\ttitle: 'Great post',\n\tauthor: {\n\t\tname: 'Steve'\n\t},\n\tcomments: [{\n\t\tbody: 'Interesting!'\n\t}]\n});\n```\n\nWhen that document will be retrieved from the database next time, all embedded documents will be wrapped with their corresponding models.\n\n```js\nconst post = await Post.findOne();\n\nconst author = post.get('author');\n//=\u003e Author { name: \"Steve\" }\n\nauthor.get('name');\n//=\u003e \"Steve\"\n```\n\n### Configuration\n\n#### Using a different collection name\n\nIn case you need to store documents in a custom collection, you can override the default one using `collection()` method.\n\n```js\nclass Post extends Model {\n\tcollection() {\n\t\treturn 'awesome_posts';\n\t}\n}\n```\n\n## Queries\n\nMongorito uses [mquery](https://github.com/aheckmann/mquery) to provide a simple and comfortable API for querying. It inherits all the methods from `mquery` with a few exceptions, which will be documented below. For documentation, please check out mquery's API - https://github.com/aheckmann/mquery.\n\nHere's a quick overview of how querying works in Mongorito. All documents returned from queries are automatically wrapped into their models.\n\n```js\n// find all posts\nawait Post.find();\n\n// find all amazing posts\nawait Post.find({amazing: true});\nawait Post.where('amazing', true).find();\n\n// find 5 recent posts\nawait Post\n\t.limit(5)\n\t.sort('created_at', 'desc')\n\t.find();\n\n// find one post\nawait Post.findOne({incredible: 'yes'});\n\n// count posts\nawait Post.count({super: false});\n```\n\n## Plugins\n\n### Using plugins\n\nTo use a 3rd-party plugin, all you have to do is to call `use()` method.\n\n```js\nconst timestamps = require('mongorito-timestamps');\n\ndb.use(timestamps());\n```\n\nThis will apply [mongorito-timestamps](https://github.com/vadimdemedes/mongorito-timestamps) to models registered after that.\n\nIf you want to apply the plugin to a specific model only, call it on the model itself.\n\n```js\nPost.use(timestamps());\n```\n\n### Writing plugins\n\nA plugin is simply a function that accepts a model. A familiarity with Redux and its concepts will help you tremendously with writing plugins.\n\n```js\nconst myPlugin = model =\u003e {\n\t// do anything with model (Post, in this case)\n};\n\nPost.use(myPlugin);\n```\n\nFeel free to assign new methods to the model or instances, add new middleware, modify the model's state and anything that comes to your mind.\n\n### Extending model with new methods\n\nHere's an example of adding a class method and an instance method to a `Post` model.\n\n```js\nconst extendPost = Post =\u003e {\n\tPost.findRecent = function () {\n\t\treturn this\n\t\t\t.limit(5)\n\t\t\t.sort('created_at', 'desc')\n\t\t\t.find();\n\t};\n\n\tPost.prototype.makeAmazing = function () {\n\t\tthis.set('amazing', true);\n\t};\n};\n\nPost.use(extendPost);\n\nconst post = new Post();\npost.makeAmazing();\npost.get('amazing');\n//=\u003e true\n\nconst posts = await Post.findRecent();\n//=\u003e [Post, Post, Post]\n```\n\n### Modifying model's state\n\nIf you plugin needs to have its own state, you can modify the model's reducer using `modifyReducer()` method. It accepts a function, which receives the existing reducer shape as an argument and should return a new object with added reducers.\n\n```js\nconst customReducer = (state = null, action) =\u003e {\n\t// reducer code...\n};\n\nconst extendReducer = model =\u003e {\n\tmodel.modifyReducer(reducer =\u003e {\n\t\treturn {\n\t\t\t...reducer,\n\t\t\tcustomState: customReducer\n\t\t}\n\t});\n};\n```\n\n### Changing behavior using middleware\n\nMiddleware can be used to change or modify the behavior of model's operations. You can interact with everything, from get/set operations to queries.\n\nTo add plugin's custom middleware to the default middleware stack, return it from the plugin function.\n\n```js\nconst myPlugin = () =\u003e {\n\treturn store =\u003e next =\u003e action =\u003e {\n\t\t// middleware code...\n\t};\n};\n```\n\nObviously, to detect what kind of action is being handled, you need to be aware of Mongorito's action types.\n\n```js\nconst {ActionTypes} = require('mongorito');\n\nconst myPlugin = () =\u003e {\n\treturn store =\u003e next =\u003e action =\u003e {\n\t\tif (action.type === ActionTypes.SET) {\n\t\t\t// alter set() behavior\n\t\t}\n\n\t\treturn next(action);\n\t};\n};\n```\n\nAgain, the middleware is identical to the middleware you're used to when writing apps with Redux. There are only 2 new properties added to the `store`:\n\n- `model` - instance of the model (document) the middleware is currently running in. If middleware is running at the model level (without instantiated model), it will be `undefined`.\n- `modelClass` - model class (`Post`, for example).\n\nHere's an example on how to access all props of the store:\n\n```js\nconst myPlugin = () =\u003e {\n\treturn ({getState, dispatch, model, modelClass}) =\u003e next =\u003e action =\u003e {\n\t\t// `getState()` and `dispatch()` are from Redux itself\n\t\t// `model` is `post`\n\t\t// `modelClass` is `Post`\n\n\t\treturn next(action);\n\t};\n};\n\nPost.use(myPlugin);\n\nconst post = new Post();\nawait post.save();\n```\n\nFor examples on how to write middleware, check out Mongorito's native ones - https://github.com/vadimdemedes/mongorito/tree/master/lib/middleware.\n\n\n## Migrating from legacy version\n\n### Connection\n\nBefore:\n\n```js\nconst mongorito = require('mongorito');\n\nmongorito.connect('localhost/blog');\n```\n\nAfter:\n\n```js\nconst {Database} = require('mongorito');\n\nconst db = new Database('localhost/blog');\nawait db.connect();\n```\n\n\n## License\n\nMIT © [Vadim Demedes](https://github.com/vadimdemedes)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvadimdemedes%2Fmongorito","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvadimdemedes%2Fmongorito","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvadimdemedes%2Fmongorito/lists"}