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 (LevelUP, LocalStorage, IndexedDB, etc). For now implemented only LocalStorage and LocalForage storage managers. 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
- 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
Storage implementations
Server-side synchronizers
- Meteor
- REST (pull-request if you need it ;))
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 LocalStorageManager from 'marsdb-localstorage';
Collection.defaultStorageManager(LocalStorageManager);
Collection.defaultIdGenerator(() => {
return {
value: Math.random(),
seed: 0,
};
});
const users = new Collection(‘users’);
Find documents
const posts = new Collection(‘posts’);
posts.find({author: ‘Bob’})
.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)
});
Removing
const posts = new Collection(‘posts’);
posts.remove({authorId: {$in: [1,2,3]}})
.then(removedDocs => {
});
Roadmap
- Keep track of multiple remove/update documents in selector (allow only if opations.multi passed)
- Upsert updating
- 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