npm promotes metadefinitions

    mobdb

    1.0.2 • Public • Published

    MarsDB

    Build Status npm version Coverage Status Dependency Status bitHound Overall Score Join the chat at https://gitter.im/c58/marsdb GitHub stars

    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';
     
    // Default storage is in-memory
    // Setup different storage managers
    // (all documents will be save in a browser cache)
    Collection.defaultStorageManager(LocalForageManager);
     
    // Create collection wit new default storage
    const users = new Collection('users');

    Create an in-memory collection

    import Collection from 'marsdb';
    import LocalStorageManager from 'marsdb-localstorage';
     
    // Set some defaults and create collection
    Collection.defaultStorageManager(LocalStorageManager);
    const users = new Collection('users');
     
    // But it may be useful to create in-memory
    // collection without defined defaults
    // (for example to save some session state)
    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 => {
        // do something with 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');
     
    // Get number of all comments in the DB
    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 => {
        // result is a number of all comments
        // in all found posts
      });
     
    // Result is `undefined` because posts
    // is not exists and additional processing
    // is not ran (thanks to `.ifNotEmpty()`)
    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 => {
        // invoked on every result change
        // (on initial result too)
        stopper.stop(); // stops observing
      }).then(docs => {
        // invoked once on initial result
        // (after `observer` callback)
      });

    Find with joins

    const users = new Collection('users');
    const posts = new Collection('posts');
    posts.find()
      .join(doc => {
        // Return a Promise for waiting of the result.
        return users.findOne(doc.authorId).then(user => {
          doc.authorObj = user;
          // any return is ignored
        });
      })
      .join(doc => {
        // For reactive join you must invoke `observe` instead `then`
        // That's it!
        return users.findOne(doc.authorId).observe(user => {
          doc.authorObj = user;
        });
      })
      .join((doc, updated) => {
        // Also any other “join” mutations supported
        doc.another = _cached_data_by_post[doc._id];
     
        // Manually update a joined parameter and propagate
        // update event from current cursor to a root
        // (`observe` callback invoked)
        setTimeout(() => {
          doc.another = 'some another user';
          updated();
        }, 10);
      })
      // Or just pass join spec object for fast joining
      // (only one `find` will be produced for all posts)
      .join({ authorId: users }) // posts[i].authorId will be user object
      .observe((posts) => {
        // do something with posts with authors
        // invoked any time when posts changed
        // (and when observed joins changed too)
      })

    Inserting

    const posts = new Collection('posts');
    posts.insert({text: 'MarsDB is awesome'}).then(docId => {
      // Invoked after persisting document
    })
    posts.insertAll(
      {text: 'MarsDB'},
      {text: 'is'},
      {text: 'awesome'}
    ).then(docsIds => {
      // invoked when all documents inserted
    });

    Updating

    const posts = new Collection('posts');
    posts.update(
      {authorId: {$in: [1, 2, 3]}},
      {$set: {text: 'noop'}}
    ).then(result => {
      console.log(result.modified) // count of modified docs
      console.log(result.updated) // array of updated docs
      console.log(result.original) // array of original docs
    });
     
    // Upsert (insert when nothing found)
    posts.update(
      {authorId: "123"},
      {$set: {text: 'noop'}},
      {upsert: true}
    ).then(result => {
      // { authorId: "123", text: 'noop', _id: '...' }
    });

    Removing

    const posts = new Collection('posts');
    posts.remove({authorId: {$in: [1,2,3]}})
      .then(removedDocs => {
        // do something with removed documents array
      });

    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

    Install

    npm i mobdb

    DownloadsWeekly Downloads

    8

    Version

    1.0.2

    License

    MIT

    Unpacked Size

    1.45 MB

    Total Files

    106

    Last publish

    Collaborators

    • ravi013