MarsDB is a lightweight client-side database.
It's based on a Meteor's minimongo matching/modifying implementation. It's carefully written on ES6, have a Promise based interface and may be backed with any storage implementation (see plugins). It's also supports observable cursors.
MarsDB supports any kind of find/update/remove operations that Meteor's minimongo does. So, go to the Meteor docs for supported query/modifier operations.
You can use it in any JS environment (Browser, Electron, NW.js, Node.js).
Features
- Promise based API
- Carefully written on ES6
- Very very flexible – just take a look to the plugins section
- Supports many of MongoDB query/modify operations – thanks to a Meteor's minimongo
- Flexible pipeline – map, reduce, custom sorting function, filtering. All with a sexy JS interface (no ugly mongo's aggregation language)
- Persistence API – all collections can be stored (and restored) with any kind of storage (in-memory, LocalStorage, LevelUP, etc)
- Observable queries - live queries just like in Meteor, but with simplier interface
- Reactive joins – out of the box
Bindings
Plugins
Meteor compatible client/server
Sometimes you can't use Meteor infrastructure. Maybe you need to build a custom client. Maybe you need to build a custom server with express and other modules. In meteor it can be done with a ton of hack. But the only reason why it's so ugly to do a simple things is because Meteor forces you to use their infrastructure. I'm trying to solve this issue with DDP client/server modules, based on MarsDB.
Examples
Using within non-ES6 environment
The ./dist
folder contains already compiled to a ES5 code, but some polyfills needed. For using in a browser you must to include marsdb.polyfills.js
before marsdb.min.js
. In node.js you need to require('marsdb/polyfills')
.
It sets in a window/global: Promise, Set and Symbol.
Create a collection
import Collection from 'marsdb';
import LocalForageManager from 'marsdb-localforage';
Collection.defaultStorageManager(LocalForageManager);
const users = new Collection('users');
Create an in-memory collection
import Collection from 'marsdb';
import LocalStorageManager from 'marsdb-localstorage';
Collection.defaultStorageManager(LocalStorageManager);
const users = new Collection('users');
const session = new Collection('session', {inMemory: true});
Find documents
const posts = new Collection('posts');
posts.find({author: 'Bob'})
.project({author: 1})
.sort(['createdAt'])
.then(docs => {
});
Find with pipeline (map, reduce, filter)
An order of pipeline methods invokation is important. Next pipeline operation gives as argument a result of a previous operation.
const posts = new Collection('posts');
posts.find()
.limit(10)
.sortFunc((a, b) => a - b + 10)
.filter(doc => Matsh.sqrt(doc.comment.length) > 1.5)
.map(doc => doc.comments.length)
.reduce((acum, val) => acum + val)
.then(result => {
});
posts.find({author: 'not_existing_name'})
.aggregate(docs => docs[0])
.ifNotEmpty()
.aggregate(user => user.name)
Find with observing changes
Observable cursor returned by a find
and findOne
methods of a collection. Updates of the cursor is batched and debounced (default batch size is 20
and debounce time is 1000 / 15
ms). You can change the paramters by batchSize
and debounce
methods of an observable cursor (methods is chained).
const posts = new Collection('posts');
const stopper = posts.find({tags: {$in: ['marsdb', 'is', 'awesome']}})
.observe(docs => {
stopper.stop();
}).then(docs => {
});
Find with joins
const users = new Collection('users');
const posts = new Collection('posts');
posts.find()
.join(doc => {
return users.findOne(doc.authorId).then(user => {
doc.authorObj = user;
});
})
.join(doc => {
return users.findOne(doc.authorId).observe(user => {
doc.authorObj = user;
});
})
.join((doc, updated) => {
doc.another = _cached_data_by_post[doc._id];
setTimeout(() => {
doc.another = 'some another user';
updated();
}, 10);
})
.observe((posts) => {
})
Inserting
const posts = new Collection('posts');
posts.insert({text: 'MarsDB is awesome'}).then(docId => {
})
posts.insertAll(
{text: 'MarsDB'},
{text: 'is'},
{text: 'awesome'}
).then(docsIds => {
});
Updating
const posts = new Collection('posts');
posts.update(
{authorId: {$in: [1, 2, 3]}},
{$set: {text: 'noop'}}
).then(result => {
console.log(result.modified)
console.log(result.updated)
console.log(result.original)
});
posts.update(
{authorId: "123"},
{$set: {text: 'noop'}},
{upsert: true}
).then(result => {
});
Removing
const posts = new Collection('posts');
posts.remove({authorId: {$in: [1,2,3]}})
.then(removedDocs => {
});
Roadmap
- Indexes support for some kind of simple requests {a: '^b'}, {a: {$lt: 9}}
- Documentation
Contributing
I'm waiting for your pull requests and issues.
Don't forget to execute gulp lint
before requesting. Accepted only requests without errors.
License
See License