qstore

work with collections in js

npm install qstore
4 downloads in the last week
4 downloads in the last month

Qstore

Overview

Work with collections in javascript

  • Create your collections.
  • Search and update data using queries.
  • Use computed fields.
  • Get collections changes.
  • Extend your query language.

Simple examples

Find all green apples from fruits collection:

fruits.find({type: 'apple', color: 'green'});

Find all apples and pears from fruits collection:

fruits.find({type: ['apple', 'pear']});

Which fruits can be red?

    fruits.getList({color: 'red'}, 'type');// ['apple', 'pear', 'strawberries']

See more examples

Instalation

in development

API

Initialisation

Using array of objects:

var fruits = new Qstore([
    {type: 'apple', color: 'red', weight: 0.25, price: 1.5},
    {type: 'pear', color: 'green', weight: 0.4, price: 2},
    {type: 'pear', color: 'red', weight: 0.3, price: 1.8},
    {type: 'apple', color: 'yellow', weight: 0.26, price: 1.2},
]);

Using reduced format:

var fruits = new Qstore({
    columns: ['type', 'color', 'weight', 'price'],
    rows: [
        ['apple', 'red', 0.25, 1.5],
        ['pear', 'green', 0.4, 2],
        ['pear', 'red', 0.3, 1.8],
        ['apple', 'yellow', 0.26, 1.2]
    ]
});

.find (query, [fields], [options])

Returns all objects which are valid for query. See examples of usage

  • query {Object|Array|Function|Bolean}
    If query is true then all rows will be returned.
    If query is Object or Array:
    { } - contains conditions separeted with and
    [ ] - contains conditions separeted with or
    Operators describe as $<operator name>, see Operators.
    Example:

    // find all red or green fruits with price between 0.5 and 1.5  
    fruits.find({color: ['red', 'green'], price: {$gt: 0.5, $lt: 1.5}});
    
    // using regular expressions
    fruits.find({type: /apple/});//returns all apples and pineapples
    

    If query is Function:
    Example:

    // find all red fruits
    fruits.find(function (row) {
        return row.color == 'red';
    });
    

    If query is Object that contains functions:

    Function with field-context:

    // find all fruits with integer price or with 0.5$ price
    fruits.find({price: [0.5, function (price) { return price % 1 == 0}]);
    

    Function with row-context:

    // find all fruits with integer price or with 0.5$ price
    fruits.find([price: 0.5, function (row) { return row.price % 1 == 0});
    
  • [fields=true] {Array|Boolean}
    Array of field names which will be added to result.
    Example:

       fruits.find({type: 'apple'}, ['type', 'color', 'price']);
    

Also you can use fields aliases

  • [options] {Object}

    • limit: rowsCount
    • limit: [fromRow]
    • limit: [fromRow, RowsCount]

    Example:

        // find first two apples
        fruits.find({type: 'apple'}, true, {limit: 2});
    
        // find two yellow fruits beginning with third yellow fruit
        fruits.find ({color: 'yellow'}, true, {limit: [3,2]});
    

Deep search:

Deep search in object:


    var usersMessages = new Qstore ({
        columns: ['text', 'subject', 'user'],
        rows: [
            ['Hi', 'new year', {id: 1, name: 'Bob', company: {name: 'IBM', phone: '+9999'} }],
            ['Happy new year!', 'new year', {id: 2, name: 'Kate', company: {name: 'Microsoft', phone: '+8888'}}],
            ['How to learn javascript?', 'programming', {id: 2, name: 'Stan'}],
            ['Anyone want to dance?', 'new year', {id: 2, name: 'James'}]
        ]
    });

    // find all messages with subject 'New year' from user with name 'Bob' who works in 'IBM' company

    messages.find({subject: 'new year', 'user.name': 'Bob', 'user.company.name': 'IBM'});

    // or
    messages.find({subject: 'new year', user: {name: 'Bob', company: {name: 'IBM'} }});

Deep search in collection:


    // create collection of costumes
    var costumes = new Qstore([
        {name: 'policeman', items: [ {name: 'tie', color: 'black'}, {name: 'cap', color: 'blue'}]},
        {name: 'fireman', items: [{name: 'hemlet', color: 'yellow'}]},
        {name: 'solder', items: [{name: 'hemlet', color: 'green'}]}
    ]);

    // find costumes which have hemlet in items
    costumes.find({items: {name: 'hemlet'} });

Aliases:

You can create aliases for fields by using the syntax "fieldName:aliasName" or by alias map

    // create collection of messages
    var messages = new Qstore ({
        columns: ['text', 'subject', 'user'],
        rows: [
            ['Hello world!', 'programming', {id: 1, name: 'Bob'}],
            ['Happy new year!', 'new year', {id: 2, name: 'Kate'}],
            ['How to learn javascript?', 'programming', {id: 2, name: 'Stan'}],
            ['Anyone want to dance?', 'new year', {id: 2, name: 'James'}]
        ]
    });

    // we need to select "text" and "user.name" from messages collection

    // first way
    messages.find({subject: 'new year'}, ['text', 'user.name:userName']);

    // second way
    messages.find({subject: 'new year'}, {text: true, userName: 'user.name'});

    // [ {text: 'Happy new year!', userName: 'Kate'}, {text: 'Anyone want to dance?', userName: 'James'}]

result of example:

    [
        {text: 'Happy new year!', userName: 'Kate'},
        {text: 'Anyone want to dance?', userName: 'James'}
    ]

Use "fieldname:" syntax to extract field values on one level up.

    // create collection of changes
    var usersChanges = new Qstore ({
        columns: ['source', 'patch'],
        rows: [
            [{id: 2, name: 'Bob', age: 23}, {name: 'Mike'}],
            [{id: 4, name: 'Stan', age: 30}, {age: 31}]
        ]
    });

    var patchForDataBase = usersChanges.find(true, ['source.id:id', 'patch:']);
    // now patchForDataBase contains:
    // [{id: 2, name: 'Mike'}, {id: 4, age: 31}];

Comparison of fields.

Use '$.fieldName' syntax to get the value of field

    // create collection of diet
    var diet = new Qstore ({
        columns: ['month', 'breakfast', 'dinner'],
        rows: [
            ['april', {calories: 400, food: 'egg'}, {calories: 300, food: 'soup'}],
            ['may', {calories: 300, food: 'bacon'}, {calories: 500, food: 'soup'}],
            ['june', {calories: 350, food: 'porridge'}, {calories: 300, food: 'chicken'}]
        ]
    });

    // find diet where dinner calories less when breackfast calories
    diet.find({'dinner.calories': {$lt: '$.breakfast.calories'} });
Queries concatenation:
    // create two filters
    var filter1 = {type: 'apple'};
    var filter2 = {color: 'red'};

    // search rows valid for filter1 or filter2
    var commonFilter1 = [filter1, filter2]

    // search rows valid for filter1 and filter2
    var commonFilter2 = {$and: [filter1, filter2]};

.search (query [,fields=true] [,options])

Same as .find but returns Qstore collection

    // get collection of red fruits sorted by type
    fruits.search({color: 'red'}).sort({fieldName: 'type', order: 'asc');

search with extending

    clients.search({status: 'online'}).sendMessage('hello!');

.findOne (query, [,fields=true] [,options])

find first row valid for query. It same as:

    .find(query, fields, {limit: 1})[0]

Qstore.findIn (rows, query [,fields=true] [,options])

same as .find but work as static method with array.

    var users = [
        {name: 'user1', id: 1, email: 'user1@anymail.com'},
        {name: 'user2', id: 2, email: 'user2@anymail.com'},
        {name: 'user3', id: 3, email: 'user3@anymail.com'},
        {name: 'user4', id: 4, email: 'user4@anymail.com'}
    ];

    // find user with id = 3
    Qstore.findIn(users, {id: 3});

Qstore.test (object, query)

Checks that the object match the query.

    var fruit = {type: 'pineapple', color: 'yellow', weight: 1, price: 4};

    // The fruit is yellow?
    Qstore.test(fruit, {color: 'yellow'}); //true

    // The fruit is pineapple or pear?
    Qstore.test(fruit, {type: ['pear', 'pineapple']}); //true

    // The fruit has "apple" in type?
    Qstore.test(fruit, {type: {$like: 'apple'}}); //true

    // Fruit price less when 1$ per kg
    Qstore.test(fruit, function (fruit) { return fruit.price/fruit.weight < 1});//false

.getList ([query] [,fieldName='idx']);

Returns list of values for fieldName.
Elements of the list are not repeated.

Examples:

    // list of all fruits colors
    fruits.getList('color'); // ['red', 'green', 'yellow']

    // list of all pears colors
    fruits.getList({type: 'pear'}, 'color');// ['green', 'red']

    // What fruits can be red?
    fruits.getList({color: 'red'}, 'type');// ['apple', 'pear', 'strawberries']

    // get fruits types with idx in [3, 5, 6]
    fruits.getList({idx: [3, 5, 6]}); //['pear', 'apple', 'banana']

    //get list of idx
    fruits.getList();

    // list of deep fields
    messages.getList('user.name'); // ['Bob', 'Kate', 'Stan', 'James']

    // you can also use function instead field name
    fruits.getList({type: 'apple'}, function (fruit) {
        return fruit.color + ' ' + fruit.type}
    } // ['red apple', 'yellow apple', 'green apple']

.each ([query=true,] fn)

apply function for each row

  • [query=true] {Object|Function|Boolean} filter query
  • fn {Function} function to apply

    // add message to log for each fruit
    fruits.each(function (row, i, query) {
        conslole.log('fruit №' + i + ' is ' + row.type);
    });

    // it will write:
    //
    // fruit №1 is apple
    // fruit №2 is pear
    // etc... 
    //

Operators

Оperators are used to extending the query language of search operations. Each operator is function which returs true if item valid for query or false if not.

Build-in operators

name description
$eq equals
$ne not equals
$gt more then
$lt less then
$gte more or equals then
$lte less or equals then
$and change condition of [ ] operator from or to and
$like "like" search
$has check exsisting of value in array or in object or in string see $has operator

you can also add your operators - see addOperator method

$has operator:

     var clothes = new Qstore([
         {name: 'skirt', sizes: ['xs', 's', 'xl']},
         {name: 'jeans', sizes: ['m', 'xxl']},
         {name: 'skirt', sizes: ['xs', 's', 'xl']}
     ]);

     clothes.find({name: 'skirt', sizes: {$has: 'xs'}});

     clothes.find({name: 'skirt', sizes: {$has: ['xs', 's'] }});

Qstore.addOperator (operatorName, function [isSimple=true])

Example:

    /* we need find fruits with integer price */

    // add "isInt" operator
    Qstore.addOperator('isInt', function (left, right) {
        var isInt = (left % 1 == 0);
        return right ? isInt : !isInt
    });

    // find them
    fruits.find({price: {$isInt: true}});

    // find other
    fruits.find({price: {$isInt: false}});

Qstore.removeOperator (operatorName)

Remove operator by operatorName.


<a name="functions"">

Functions

Functions used for runtime calculations in query. You may use build-in functions or you own functions

Example of usage "length" function


    // create collection of users
    users = new Qstore ([
        {id: 1, name: 'Bob', friends: ['Mike', 'Sam']},
        {id: 2, name: 'Martin', friends: ['Bob']},
        {id: 3, name: 'Mike', friends: ['Bob', 'Martin', 'Sam']},
        {id: 4, name: 'Sam', friends: []}
    ]);

    // find users who have not any friend
    users.find({'friends.$length': 0});

    // find users who have more than 2 friends
    users.find({'friends.$length': {$gt: 2} });

Example of usage "max" and "min" function:


    // create collection of clothes
    var clothes =  new Qstore([
        {name: 'skirt', sizes: [42, 48, 50]},
        {name: 'jeans', sizes: [48, 54]},
        {name: 'skirt', sizes: [42, 45, 48]}
    ]);

    // select name and maxSize of each item
    clothes.find(true, ['name', 'sizes.$max:maxSize']);

    // find clothes with min size = 42
    clothes.find({'size.$min': 42});

Functions also can be used in fields selection


    // select user name and count of friends
    users.find(true, ['name', 'friends.$length:friendsCount']);

The grouping methods and getList method also supports the functions syntax:


    // get list of all first friends
    users.getList('friends.$first')

You can use result of one function as arguments for another function:


    // get first letter in lower case of first friends

    users.getList({'friends.$length': {$gt: 0}}, 'friends.$first.$first.$lower')

You can pass additional arguments to functions:


// create collection of сostumes for Halloween
costumes = new Qstore([
        {name: 'policeman', items: [ {name: 'tie', color: 'black'}, {name: 'cap', color: 'blue'}]},
        {name: 'fireman', items: [{name: 'helmet', color: 'yellow'}]},
        {name: 'solder', items: [{name: 'helmet', color: 'green'}]},
        {name: 'zombie', items: [{name: 'skin', color: 'green'}, {name: 'brain', color: 'pink'}]}
    ]);

// get list of colors for each costume
costumes.find(true, ['name', 'items.$getList("color"):colors']);

When you use functions, avoid redundant expressions. For example we need to find all costumes wich have yellow color. We may use find and lenght function:

    costumes.find({'items.$find({"color": "yellow"}).$length': {$gt: 0} });

But in this case the right way - using a deep search.

    costumes.find({'items': {color: 'yellow'}});

Build-in functions

name description
$length length of array, string or count of keys in object
$first first item of array or first letter of string or first property of object
$min retunrs max of array
$max returns min of array
$abs absolute value
$find use Qstore.findIn method
$mapOf use Qstore.mapOf method
$indexBy use Qstore.indexBy method
$test use Qstore.test method
$getList use Qstore.getList method
$upper translate string to upper case
$lower translate string to lower case
$toNumber cast to Number
$toString cast to String

You can also add your functions - see addFunction method


Add function

in development


Remove function

in develomnent


Fields selection


Grouping

.indexBy (indexes)

returns map of keys for collection

indexes {String|Array} key or array of keys

    // create collection of users
    var users = new Qstore ([
        {id: 12, name: 'Bob', friends: ['Mike', 'Sam']},
        {id: 4, name: 'Martin', friends: ['Bob']},
        {id: 5, name: 'Mike', friends: ['Bob', 'Martin', 'Sam']},
        {id: 10, name: 'Sam', friends: []},
        {id: 15, name: 'Sam', friends: ['Mike']}
    ]);

    // index by user's name
    users.indexBy('name');

Result of previous example:

{
    Bob: {id: 12, name: 'Bob', friends: ['Mike', 'Sam']},
    Martin: {id: 4, name: 'Martin', friends: ['Bob']}
    Mike: {id: 5, name: 'Mike', friends: ['Bob', 'Martin', 'Sam']},
    Sam: [{id: 10, name: 'Sam', friends: []}, {id: 15, name: 'Sam', friends: ['Mike']}]
}

If for one key exixting more then one item then values will be wrapped in array.

You can also use more then one key:


    // first indexed by name, and then by id
    users.indexBy(['name', 'id']);

Result of previous example:


{
    Bob: {
        12: {id: 12, name: 'Bob', friends: ['Mike', 'Sam']}
    Martin: {
        4: {id: 4, name: 'Martin', friends: ['Bob']}
    },
    Mike: {
        5: {id: 5, name: 'Mike', friends: ['Bob', 'Martin', 'Sam']}
    },
    Sam: {
        10: {id: 10, name: 'Sam', friends: []},
        15: {id: 15, name: 'Sam', friends: ['Mike']}
    }
}

You can also use static implementation of .indexBy : Qstore.indexBy (items, indexes)


.mapOf (indexes)

same as .indexBy, but it always wrap values in array

indexes {String|Array} key or array of keys

example:


    // create collection of shop's locations
    window.shops = new Qstore ({
        columns: ['country', 'city', 'address'],
        rows: [
            ['UK', 'London', 'mace st. 5'],
            ['UK', 'York', 'temple ave. 10'],
            ['France', 'Paris', 'de rivoli st. 20'],
            ['France', 'Paris', 'pelleport st. 3'],
            ['Germany', 'Dresden', 'haydn st. 2'],
            ['Germany', 'Berlin', 'bornitz st. 50'],
            ['Germany', 'Munchen', 'eva st. 12'],
            ['Russia', 'Vladivostok', 'stroiteley st. 9']
        ]
    });

    // first group by country, and then by city
    shops.mapOf(['country', 'city']);

in previous example .mapOf returns object like this:


{
    France: {
        Paris: Array[2],
    Germany: {
        Berlin: Array[1],
        Dresden: Array[1],
        Munchen: Array[1]
    },
    Russia: {
        Vladivostok: Array[1]
    },
    UK: {
        London: Array[1]
        York: Array[1]
    }
}

You can use function which returns index:


    shops.mapOf(function (shop) {
        return shop.country + ' - ' + shop.city
    });

Reslut:

    'France - Paris': Array[2]
    'Germany - Berlin': Array[1]
    'Germany - Dresden': Array[1]
    'Germany - Munchen': Array[1]
    'Russia - Vladivostok': Array[1]
    'UK - London': Array[1]
    'UK - York': Array[1]

You can also use static implementation of .mapOf : Qstore.mapOf (items, indexes)


.groupBy (group1 [, group2, ..., groupN])

Powerful method for creating grouped collections. Returns Qstore.

Group by country:

    var items =  shops.search({country: ['Germany', 'France']});
    var groups = items.groupBy('country');

Result of groups.rows:

    [
        {
            _g: Array[2],
            country: "France",
            idx: 1
        },
        {
            _g: Array[3],
            country: "Germany",
            idx: 2
        }
    ]

All items of group stored in special field _g.

Group first 4 items by country and city:

    var items = shops.search(true, true, {limit: 4});
    var groups = items.groupBy(['country', 'city']);

Result of groups.rows:

    [
        {
            _g: Array[1],
            city: "London",
            country: "UK",
            idx: 1
        },
        {
            _g: Array[1],
            city: "York",
            country: "UK",
            idx: 2
        },
        {
            _g: Array[2]
            city: "Paris"
            country: "France"
            idx: 3
        }
    ]

You can also use long syntax items.groupBy({country: true, city: true}) instead items.groupBy(['country', 'city']). You can use different ways of describing the same action:

    // group by field 'country' and set alias 'countryName' for this field
    shops.groupBy('country:countryName');
    shops.groupBy({'country:countryName': true});
    shops.groupBy({countryName: 'country'});

Group by country and when by city:

    var items = shops.search({country: ['Germany', 'France']});
    var groups = items.groupBy('country', 'city').rows

Result of groups.rows:

[
    {
        _g: [
            {
                _g: Array[2],
                city: "Paris"
            }
        ],
        country: "France",
        idx: 1
    },
    {
        _g: [
            {
                _g: Array[1],
                city: "Dresden"
            },
            {
                _g: Array[1],
                city: "Berlin"
            },
            {
                _g: Array[1],
                city: "Munchen"
            }
        ],
        country: "Germany",
        idx: 2
    }
]

You also can use function instead field name:

    // group contacts by first letter
    var groups = contacts.sort('name').groupBy({
        letter: function (contact) {
            var firstLetter = contact.name.charAt(0);
            if (firstLetter <= 'H') return 'A - H';
            if (firstLetter >= 'R') return 'R - Z';
            return 'I - Q';
        }
    });

Result of groups.rows:

    [
        {
            _g: Array[5],
            idx: 1,
            letter: "A - H"
        },
        {
            _g: Array[4],
            idx: 2,
            letter: "I - Q"
        },
        {
            _g: Array[2],
            idx: 3,
            letter: "R - Z"
        }
    ]

Sometimes you may need to add additional field which must be linked with group. For this case you can use special directive $add:


    var groups = shops.groupBy({
        country: true,
        $add: {
            shopsCount: '_g.$length'
        }
    });

Result of groups.rows:

    {
        _g: Array[2],
        country: "UK",
        idx: 1,
        shopsCount: 2
    },
    {
        _g: Array[2],
        country: "France",
        idx: 2,
        shopsCount: 2
    },
    {
        _g: Array[3]
        country: "Germany"
        idx: 3
        shopsCount: 3
    },
    {
        _g: Array[1]
        country: "Russia"
        idx: 4
        shopsCount: 1
    }

Additional fields processing when operation of grouping was done, therefore in previous example we can got count of items in group with help of $length function.

You can use function as argument for $add directive:

    // group by country and add cities list for each group
    var groups = shops.groupBy({
        country: true,
        $add: function (item) {
            var cities = Qstore.getList(item._g, 'city');
            return {cities: cities.join(', ')};
        }
    });

Result of groups.rows:


[
    {
        _g: Array[2],
        cities: "London, York",
        country: "UK",
        idx: 1
    },
    {
        _g: Array[2],
        cities: "Paris",
        country: "France",
        idx: 2
    },
    {
        _g: Array[3],
        cities: "Dresden, Berlin, Munchen",
        country: "Germany",
        idx: 3
    },
    {
        _g: Array[1],
        cities: "Vladivostok",
        country: "Russia",
        idx: 4
    }
]

Also you can use function as value for additional field, and write previous example at another manner:

    var groups = shops.groupBy({
        country: true,
        $add: {
            cities: function (item) {
                var cities = Qstore.getList(item._g, 'city');
                return cities.join(', ');
            }
        }
    });

Data manipulation

.add (rows [,soft=false])

add new items to collection

  • row {Object|Array}
  • soft soft add. See soft mode.

Examples:

     //add one new fruit
     fruits.add({type: 'carrot', color: 'red', weight: 0.3, price: 0.3});

     //add few new fruits
     fruits.add([
         {type: 'carrot', color: 'red', weight: 0.3, price: 0.3},
         {type: 'orange', color: 'orange', weight: 0.4, price: 0.5}
     ]);

.update ([searchQuery,] updateQuery [,soft=false])

Update items in collection.

  • [searchQuery] {Object|Function} if option is set then will be updated only finded items
  • updateQuery {Object|Function} patch or function returned patch
  • [soft=false] soft update. See soft mode

Examples:

    //all fruits will be apples
    fruits.update({type: 'apple'});

    //make all green fruits red
    fruits.update({color: 'green'}, {color: 'red'});

    //The price of all pears will increase by 1 $
    fruits.update(function (item) {
        if (item.type == 'pear') {
            return {price: item.price + 1}
        }
    });

.patch (values [,key='idx'] [,soft=false])

Update current collection by using update-collection.

  • values array of patches
  • [key='idx'] key field
  • [soft=false] soft patch. See soft mode.
    var patch = [
        {id: 21, connected: true},
        {id: 22, connected: false},
        {id: 33, name: 'unknown'}
    ];

    users.patch(patch, 'id');

.remove (expr [,soft=false])

Delete items from collection and returns count of deleted items.

    // delete messages that do not have author
    messages.remove({author: undefined});

.addFields (fields)

Add new fields in collection.

  • fields {Array|Object} array of new fields settings

Fields with default values:

    messages.addFields([
        {name: 'author', default: 'unknown'},
        {name: 'rating', default: 0}
    ]);

    messages.add({text: 'hello world'});
    messages.findOne({text: 'hello world'}); // {text: 'hello world', author: 'unknown', rating: 0}

Computed fields:

    fruits.addFields({name: 'pricePerKg', compute: function (fruit) {
        return fruit.price / fruit.weight;
    });

.compute ()

Forced recalculate computed fields.
Computed fields automatically recalculeted whan collection was changed. Use this method if you need recalculate computed fields manualy.


.removeFields (fields)

remove fields from collection

  • fields {String|Array} field name or array of field names to delete
    // delete one field
    fruits.removeFields('weight');

    // delete few fields
    fruits.removeFields(['price', 'color']);

.sort (fields [,zeroIsLast=false])

another variant: sort (fn) where fn is sort function

Sort collection.

Examples:

    // sort by idx
    fruits.sort();

    // sort by type (asc)
    fruits.sort({fieldName: 'type', order: 'asc'});

    // sort by type (asc) when by price (desc)
    fruits.sort([
        {fieldName: 'type', order: 'asc'},
        {fieldName: 'price', order: 'desc'},
    ]);

    // sort by price, zero values will be in the end of collection
    fruits.sort({fieldName: 'price', zeroIsLast: true});

    // use sort function
    fruits.sort(function (fruit1, fruit2) {
        return fruit1.price - fruit2.price;
    });

Work with changes

By default, your collections keep changes until you call the method commit or rollback. If you do not need this functionality, see soft mode.

.getChanges ()

returns collection of changes

Examples:

    // we need get the list of idx of removed items
    fruits.remove({type: 'apple'});
    fruits.getChanges().search({action: 'remove'}).getList('source.idx');// [1, 4, 9]

    // do some changes
    fruits.update({type: 'pear'}, {color: 'blue', price: 0.5});
    fruits.add({type: 'apple', color: 'green'});
    fruits.remove({type: 'pineapple'});

    // we need to create patch for database
    var changes = fruits.getChanges();
    var patch = {};
    patch.add = changes.find({action: 'add'}, ['values:']);
    patch.remove = changes.search({action: 'remove'}).getList('source.idx');
    patch.update = changes.find(true, ['source.idx:id', 'values:']);

An easier way to get the map of changes - use getChangesMap method.


.getChangesMap ([keyField='idx'])

Use this method to get map of changes group by action like:

{
    add: [array of added items]
    remove: [array of removed keys]
    update: [array of updated values]
}

.commit ()

Commit changes.


.rollback ()

Revert all changes.


softMode

Some actions may be called with soft mode. This means that they do not add information about the change in the list of changes.

If you want that your collection always work in soft mode use .setSoftMode method.

    fruits.setSoftMode(true)

If you want that anyone new collection will be work in soft mode use Qstore.setSoftMode method


Utilites

.size ()

Returns rows count.


.pack ([query] [,fields])

Returs reduced collection.

    // create fruits collection
    var fruits = new Qstore([
        {type: 'apple', color: 'red', weight: 0.25, price: 1.5},
        {type: 'pear', color: 'green', weight: 0.4, price: 2},
        {type: 'pear', color: 'red', weight: 0.3, price: 1.8},
        {type: 'apple', color: 'yellow', weight: 0.26, price: 1.2}
    ]);

    var apples =  fruits.pack({type: 'apple'}, ['idx', 'weight', 'price']);

    //now apples contains:
    {
        columns: ['idx', 'weight', 'price'],
        rows: [
            [1, 0.25, 1.5],
            [4, 0.26, 1.2]
        ]
    }

You can use this method if you whant to send collection or part of collection by network, because it will reduce the outgoing traffic.


.getCopy ()

Returns a new independent collection, which will be copy of current collection.


Events

Events list

  • change
  • commit
  • sort

Use setListener method to react on changes.


.setListener (fn)

  • fn {Function} listener function

Example:

// We want to add messages to the log, if any apple will change its color.
var listener = function (name, data, collection) {

    // We are interested only in the event "change" with the action "update"
    if (name != 'change' || data.action != 'update') return;

    // get operations changes
    var changes = data.changes;

    // find apples with changed color
    var applePainting = changes.find({'source.type': 'apple', 'patch.color': {$ne: undefined} });

    // write to log
    for (var i = 0; i < applePainting.length; i++) {
        var change = applePainting[i];
        console.log('Some apple change color from ' + change.source.color + ' to ' + change.patch.color);
    }
};

fruits.setListener(listener);

fruits.update({color: 'blue'}); // it will write to log:
// Some apple change color from red to blue
// Some apple change color from yellow to blue
// Some apple change color from green to blue

Examples of collections

In many examples of the API docs using various collections. You can explore their in this section.

fruits


    var fruits = new Qstore({
        columns: ['type', 'color', 'weight', 'price'],
        rows: [
            ['apple', 'red', 0.25, 1.5],
            ['pear', 'green', 0.4, 2],
            ['pear', 'red', 0.3, 1.8],
            ['apple', 'yellow', 0.26, 1.2],
            ['pineapple', 'yellow', 1, 4],
            ['banana', 'yellow', 0.3, 1.5],
            ['melon', 'yellow', 3, 3],
            ['watermelon', 'green', 10, 5],
            ['apple', 'green', 0.24, 1],
            ['strawberries', 'red', 0.1, 0.2]
        ]
    });

usersMessages


    var usersMessages = new Qstore ({
        columns: ['text', 'subject', 'user'],
        rows: [
            ['Hi', 'new year', {id: 1, name: 'Bob', company: {name: 'IBM', phone: '+9999'} }],
            ['Happy new year!', 'new year', {id: 2, name: 'Kate', company: {name: 'Microsoft', phone: '+8888'}}],
            ['How to learn javascript?', 'programming', {id: 2, name: 'Stan'}],
            ['Anyone want to dance?', 'new year', {id: 2, name: 'James'}]
        ]
    });

messages


    var messages = new Qstore ({
        columns: ['text', 'subject', 'user'],
        rows: [
            ['Hello world!', 'programming', {id: 1, name: 'Bob'}],
            ['Happy new year!', 'new year', {id: 2, name: 'Kate'}],
            ['How to learn javascript?', 'programming', {id: 2, name: 'Stan'}],
            ['Anyone want to dance?', 'new year', {id: 2, name: 'James'}]
        ]
    });

diet


    var diet = new Qstore ({
        columns: ['month', 'breakfast', 'dinner'],
        rows: [
            ['april', {calories: 400, food: 'egg'}, {calories: 300, food: 'soup'}],
            ['may', {calories: 300, food: 'bacon'}, {calories: 500, food: 'soup'}],
            ['june', {calories: 350, food: 'porridge'}, {calories: 300, food: 'chicken'}]
        ]
    });

users


    var users = new Qstore ([
        {id: 12, name: 'Bob', friends: ['Mike', 'Sam']},
        {id: 4, name: 'Martin', friends: ['Bob']},
        {id: 5, name: 'Mike', friends: ['Bob', 'Martin', 'Sam']},
        {id: 10, name: 'Sam', friends: []},
        {id: 15, name: 'Sam', friends: ['Mike']}
    ]);

costumes


    var costumes = new Qstore([
        {name: 'policeman', items: [ {name: 'tie', color: 'black'}, {name: 'cap', color: 'blue'}]},
        {name: 'fireman', items: [{name: 'helmet', color: 'yellow'}]},
        {name: 'solder', items: [{name: 'helmet', color: 'green'}]},
        {name: 'zombie', items: [{name: 'skin', color: 'green'}, {name: 'brain', color: 'pink'}]}
    ]);

clothes


    var clothes =  new Qstore([
        {name: 'skirt', sizes: [42, 48, 50]},
        {name: 'jeans', sizes: [48, 54]},
        {name: 'skirt', sizes: [42, 45, 48]}
    ]);

usersChanges


    var usersChanges = new Qstore ({
        columns: ['source', 'patch'],
        rows: [
            [{id: 2, name: 'Bob', age: 23}, {name: 'Mike'}],
            [{id: 4, name: 'Stan', age: 30}, {age: 31}]
        ]
    });

shops

    var shops = new Qstore ({
        columns: ['country', 'city', 'address'],
        rows: [
            ['UK', 'London', 'mace st. 5'],
            ['UK', 'York', 'temple ave. 10'],
            ['France', 'Paris', 'de rivoli st. 20'],
            ['France', 'Paris', 'pelleport st. 3'],
            ['Germany', 'Dresden', 'haydn st. 2'],
            ['Germany', 'Berlin', 'bornitz st. 50'],
            ['Germany', 'Munchen', 'eva st. 12'],
            ['Russia', 'Vladivostok', 'stroiteley st. 9']
        ]
    });

contacts


    var contacts = new Qstore({
        columns: ['name', 'phone'],
        rows: [
            ['Leonardo Da Vinci', '23090533'],
            ['Elvis Presley', '247543'],
            ['Christopher Columbus', '85321443'],
            ['Pablo Piccaso', '2512567'],
            ['Walt Disney', '123456464'],
            ['Albert Einstein', '0865443'],
            ['Aristotle', '23090533'],
            ['William Shakespeare', '235667'],
            ['Ludwig van Beethoven', '245433'],
            ['Cleopatra', '346422'],
            ['Paul McCartney', '5532173'],
        ]
    });

meetings


    var meetings = new Qstore({
        columns: ['day','month', 'year', 'details'],
        rows: [
            [2, 'feb', 2012, 'Meeting with Albert Einstein'],
            [14, 'feb', 2012,'Meeting with Elvis Presley'],
            [20, 'feb', 2013, 'Meeting with Christopher Columbus'],
            [3, 'mar', 2013, 'Meeting with Pablo Piccaso'],
            [2, 'apr', 2013, 'Meeting with Walt Disney'],
            [10, 'apr', 2013,'Meeting with Aristotle'],
            [11, 'may', 2013, 'Meeting with William Shakespeare'],
            [13, 'may', 2013, 'Meeting with Cleopatra']
        ]
    });

npm loves you