Description
Awesome MongoDB ODM for Node.js apps.
Just take a look at its beautiful models and API.
Uses official mongodb driver under the hood.
Mongorito alternatives and similar modules
Based on the "ODM / ORM" category.
Alternatively, view Mongorito alternatives based on common mentions on social networks and blogs.
-
SheetJS js-xlsx
📗 SheetJS Spreadsheet Data Toolkit -- New home https://git.sheetjs.com/SheetJS/sheetjs -
TypeORM
ORM for TypeScript and JavaScript. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms. -
Sequelize
Feature-rich ORM for modern Node.js and TypeScript, it supports PostgreSQL (with JSON and JSONB support), MySQL, MariaDB, SQLite, MS SQL Server, Snowflake, Oracle DB (v6), DB2 and DB2 for IBM i. -
MikroORM
TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases. -
Waterline
An adapter-based ORM for Node.js with support for mysql, mongo, postgres, mssql (SQL Server), and more -
SignalDB
SignalDB is a local JavaScript database with a MongoDB-like interface and TypeScript support, enabling optimistic UI with signal-based reactivity across multiple frameworks. It integrates easily with libraries like Angular, Solid.js, Preact, and Vue, simplifying data management with schema-less design, in-memory storage, and fast queries. -
@Sugoi\orm
SugoiJS ORM module typescript based - Simple solution for object handling with predefined lifecycle
InfluxDB - Purpose built for real-time analytics at any scale.
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of Mongorito or a related project?
README
Lightweight and flexible MongoDB ODM for Node.js apps based on Redux.
Features
Flexible
Mongorito is based on 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()
.
Each model instance has a separate Redux store, which ensures isolation between other models and easy extensibility.
No schemas
If 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.
Lightweight
Mongorito 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.
Mongorito is basically a tiny Redux-based application, which uses the official MongoDB driver and 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!
Quick overview
const {Database, Model} = require('mongorito');
const db = new Database('localhost/blog');
await db.connect();
class Post extends Model {}
db.register(Post);
const post = new Post({
title: 'Steve Angello rocks',
author: {
name: 'Emma'
}
});
await post.save();
post.set('author.name', 'Rick');
await post.save();
await db.disconnect();
Note: await
won't work at top level, it's used to reduce the complexity of an example.
Installation
$ npm install --save mongorito
Contents
- Connection
- Models
- - Creating a model
- - Working with fields
- - Saving or removing documents
- - Incrementing fields
- - Embedding other models
- - Configuration
- Queries
- Plugins
- - Using plugins
- - Writing plugins
- - Extending model with new methods
- - Modifying model's state
- - Changing behavior using middleware
- Migrating from legacy version
Connection
Mongorito exports several own classes, as well as a few properties from the MongoDB driver:
const {
Database,
Model,
Timestamp,
ObjectId,
MinKey,
MaxKey,
DBRef,
Long
} = require('mongorito');
Database
and Model
are Mongorito's own exports, all the other ones are exported straight from mongodb
package for convenience. Normally, you'd need only Database
, Model
and ObjectId
.
To connect, initialize a Database
, which accepts a MongoDB connection string and an optional configuration which will be passed to mongodb's connect function.
To connect and disconnect use connect()
/disconnect()
methods. Both returns a Promise.
For convenience, await
will be used in all examples below, even though it doesn't work at top level.
const {Database, Model} = require('mongorito');
const db = new Database('localhost/blog', {
reconnectTries: 5
});
await db.connect();
await db.disconnect();
You don't have to wait until connection establishes to perform operations. Mongorito automatically executes pending operations once connection is up.
Models
Creating a model
Model 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.
class Post extends Model {}
For 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.
db.register(Post);
That's it, the Post
model is good to go!
Working with fields
To create a new document, create an instance of Post
model.
const post = new Post();
Model's constructor also accepts an object of fields to instantiate the document with:
const post = new Post({
title: 'Great post',
author: {
name: 'Sarah'
}
});
Note, documents can contain nested fields and even models, just like in MongoDB.
To get one or all fields from the post
document, use a get()
method.
const title = post.get('title');
//=> "Great post"
const author = post.get('author.name');
//=> "Sarah"
const data = post.get();
//=>
// {
// title: "Great post"
// author: {
// name: "Sarah"
// }
// }
Similarly, use set()
to update fields:
// update fields one by one
post.set('title', 'Amazing post');
post.set('author.name', 'Monica');
// or all at once
post.set({
title: 'Amazing post',
author: {
name: 'Monica'
}
});
To remove a field, use unset()
:
// unset single fields
post.unset('title');
post.unset('author.name');
// or multiple fields at once
post.unset(['title', 'author.name']);
Saving or removing documents
To 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.
await post.save();
When a document is saved, an _id
field is automatically added.
post.get('_id');
//=> ObjectId("5905cb6b543c3a50e03e810d")
To remove a document, use remove()
.
await post.remove();
To remove multiple documents, use remove()
on the model itself with a query as an argument.
await Post.remove({good: false});
Incrementing fields
Mongorito also provides a handy increment()
method to increment or decrement numerical fields:
const post = new Post({
views: 0
});
await post.increment('views');
post.get('views');
//=> 1
You can also supply a value to increment a field by a specific amount.
await post.increment('views', 2);
post.get('views');
//=> 3
Multiple fields can be incremented at once, too.
const post = new Post({
views: 10,
comments: 10
});
await post.increment({
views: 2,
comments: 5
});
post.get('views');
//=> 12
post.get('comments');
//=> 15
Embedding other models
Just like MongoDB, Mongorito allows to effortlessly embed other models. They're transparently converted between JSON and Mongorito models.
To 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.
Here's the quick overview on how it works. Note, that model registering via register()
is skipped in the following example.
class Post extends Model {}
class Author extends Model {}
class Comment extends Model {}
Post.embeds('author', Author);
Post.embeds('comments', Comment);
const post = new Post({
title: 'Great post',
author: new Author({name: 'Steve'}),
comments: [new Comment({body: 'Interesting!'})]
});
await post.save();
The above post will be saved to the database as:
{
"title": "Great post",
"author": {
"name": "Steve"
},
"comments": [
{
"body": "Interesting!"
}
]
}
You can also just pass objects instead of model instances and Mongorito will take care of that too.
const post = new Post({
title: 'Great post',
author: {
name: 'Steve'
},
comments: [{
body: 'Interesting!'
}]
});
When that document will be retrieved from the database next time, all embedded documents will be wrapped with their corresponding models.
const post = await Post.findOne();
const author = post.get('author');
//=> Author { name: "Steve" }
author.get('name');
//=> "Steve"
Configuration
Using a different collection name
In case you need to store documents in a custom collection, you can override the default one using collection()
method.
class Post extends Model {
collection() {
return 'awesome_posts';
}
}
Queries
Mongorito uses 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.
Here's a quick overview of how querying works in Mongorito. All documents returned from queries are automatically wrapped into their models.
// find all posts
await Post.find();
// find all amazing posts
await Post.find({amazing: true});
await Post.where('amazing', true).find();
// find 5 recent posts
await Post
.limit(5)
.sort('created_at', 'desc')
.find();
// find one post
await Post.findOne({incredible: 'yes'});
// count posts
await Post.count({super: false});
Plugins
Using plugins
To use a 3rd-party plugin, all you have to do is to call use()
method.
const timestamps = require('mongorito-timestamps');
db.use(timestamps());
This will apply mongorito-timestamps to models registered after that.
If you want to apply the plugin to a specific model only, call it on the model itself.
Post.use(timestamps());
Writing plugins
A plugin is simply a function that accepts a model. A familiarity with Redux and its concepts will help you tremendously with writing plugins.
const myPlugin = model => {
// do anything with model (Post, in this case)
};
Post.use(myPlugin);
Feel 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.
Extending model with new methods
Here's an example of adding a class method and an instance method to a Post
model.
const extendPost = Post => {
Post.findRecent = function () {
return this
.limit(5)
.sort('created_at', 'desc')
.find();
};
Post.prototype.makeAmazing = function () {
this.set('amazing', true);
};
};
Post.use(extendPost);
const post = new Post();
post.makeAmazing();
post.get('amazing');
//=> true
const posts = await Post.findRecent();
//=> [Post, Post, Post]
Modifying model's state
If 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.
const customReducer = (state = null, action) => {
// reducer code...
};
const extendReducer = model => {
model.modifyReducer(reducer => {
return {
...reducer,
customState: customReducer
}
});
};
Changing behavior using middleware
Middleware can be used to change or modify the behavior of model's operations. You can interact with everything, from get/set operations to queries.
To add plugin's custom middleware to the default middleware stack, return it from the plugin function.
const myPlugin = () => {
return store => next => action => {
// middleware code...
};
};
Obviously, to detect what kind of action is being handled, you need to be aware of Mongorito's action types.
const {ActionTypes} = require('mongorito');
const myPlugin = () => {
return store => next => action => {
if (action.type === ActionTypes.SET) {
// alter set() behavior
}
return next(action);
};
};
Again, 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
:
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 beundefined
.modelClass
- model class (Post
, for example).
Here's an example on how to access all props of the store:
const myPlugin = () => {
return ({getState, dispatch, model, modelClass}) => next => action => {
// `getState()` and `dispatch()` are from Redux itself
// `model` is `post`
// `modelClass` is `Post`
return next(action);
};
};
Post.use(myPlugin);
const post = new Post();
await post.save();
For examples on how to write middleware, check out Mongorito's native ones - https://github.com/vadimdemedes/mongorito/tree/master/lib/middleware.
Migrating from legacy version
Connection
Before:
const mongorito = require('mongorito');
mongorito.connect('localhost/blog');
After:
const {Database} = require('mongorito');
const db = new Database('localhost/blog');
await db.connect();
License
MIT © Vadim Demedes
*Note that all licence references and agreements mentioned in the Mongorito README section above
are relevant to that project's source code only.