jsormdb--an Embedded JavaScript Database

With the rise of Web 2.0 and Rich Internet Applications, the need for a solid JavaScript-based data management paradigm has become much more acute. Using jsormdb, you can develop your applications with the same data-driven paradigm you use on server-side applications.
Querying Data

In order to make the database useful, you need to be able to retrieve records you inserted or loaded—that is, you need to query the database. To do this, you simply call db.find(query). The results will be an array of JavaScript objects that match your query. If no records match, an empty array is returned. If the query itself is invalid, a null object is returned.

The query parameter itself is an object with two fields: “where” and “fields”. The where field informs the database what you need to match in order to retrieve the record. It can be a simple match, or it can be a compound match, joining multiple simple or compound matches into a single larger one. The fields field can be used to restrict which fields are returned from the records that are found:

var where, results;

// simple, retrieves all records where the name field equals "John"
where  = {field: "name", compares: "equals", value: "John"};
results = db.find({where: where});

// compound, retrieves all records where name equals "John"
// or name equals "Jack"
where = {join: 'or',
         terms: [
                {field: "name", compares: "equals", value: "John"},
                {field: "name", compares: "equals", value: "Jack"}]};
results = db.find({where: where});

Compound terms can be joined by 'and' or 'or'. Simple terms can match on any field and can compare the field using one of many conditions, such as “equals”, “in”, “starts”, “gt” and so on. The API docs and Wiki entry, listed in the Resources for this article, have a complete list.

Finally, you can restrict the search, at any level, by the type of record to retrieve. The type field, if available, is always indexed, leading to much faster searches:

// all records of type "car" where age >= 12
where   = {field: "age", compares: "ge", value: 12, type: "car"};
results = db.find({where: where});

It is important to note that the results of a db.find(query) will return a copy of the records, not the originals themselves. Thus, it is safe to modify the returned results at will.

Modifying Data

You can modify data in one of several ways: remove records, add records or change records.

Adding records is fairly straightforward. Simply call db.insert(data), with the data an array of JavaScript object literals:

data = [{name: "Jack",  age:  80},
        {name: "Sam",   age:  22},
        {city: "Paris", type: "location"}]
db.insert(data);

Where these records actually will physically be inserted into the jsormdb database is irrelevant, just as it is in any true database. All that matters is that the records are inserted, and that you can retrieve them.

To remove records, just call db.remove(query). The query parameter is exactly the same as in db.find(). All records that match the where will be removed immediately.

To change records, just call db.update(data,query). The query parameter is exactly the same as in db.find(). The data parameter is a single JavaScript object that has the fields to update. All records whose fields match the where will be updated:

// for every record where the age >= 40, change the age to be 35
var update, where;
where  = {field: "age", compares: "ge", age: 40};
update = {age: 35};
db.update(update,where);

Transactions

As noted earlier, transactions are crucial to anything other than trivial events. jsormdb provides advanced transaction processing to allow you to manage your changes properly.

Transactions are always enabled. From the moment you load a database, a new transaction is started. All the changes you make—update, remove, insert—are tracked by jsormdb. When you have reached the end of your transaction, you must either commit the changes or reject them.

If you commit the changes, all of the change tracking is thrown away, and a new transaction is started. From that point forward, you cannot undo any of your previous changes. On the other hand, if you reject the changes, all of the changes from the beginning of the transaction—either the last load or the last commit or reject—are undone. Additionally, if you want, you can reject only some of your changes. For example, if you have made eight changes in this transaction, and you want to undo only the last four, you can do so. This is particularly useful in the user-interface environment. For example, if you have written a Web 2.0 spreadsheet application with jsormdb as your data store, you probably want to give users the ability to undo each of their changes, one by one, in reverse order, probably using Ctrl-Z on Windows and Linux or Cmd-Z on Mac. Until jsormdb, you would have to code the tracking of these changes manually. Now, you can simply delegate this function to jsormdb. Each time users click Undo, they reject exactly one change.

The following example starts with three records, adds two more, modifies one and removes one:

var data, where, db, recs;

// create and load the database
data = [{name: "Joe",   age: 25},
        {name: "Jill",  age: 30},
        {name: "James", age: 35}];
db = JSORM.db.db({data: data});

// add records
db.insert([{name: "Karl", age: 40}, {name: "Karyn"}]);

// modify Joe
db.update({data:  {age: 26},
           where:
               {field: "name", compares: "equals", value: "Joe"}});

// remove James
db.remove({where:
               {field: "name", compares: "equals", value: "James"}});

// get all of the data
recs = db.find();
// recs = [{name: "Joe",   age: 26},
//         {name: "Jill",  age: 30},
//         {name: "Karl",  age: 40},
//         {name: "Karyn"}]

// we can commit, reject or partially reject
db.commit();  // all changes are saved and a new transaction starts
// OR
db.reject();  // all changes are rolled back;
              // db.find() returns [{name: "Joe",   age: 25},
              //                    {name: "Jill",  age: 30},
              //                    {name: "James", age: 35}]
// OR
db.reject(1); // just the removal of James is rolled back

Last but not least, commit() can cause jsormdb to update the server with its new data in one of several formats, and it even can update itself based on the server's response. This persistence of changes, which uses jsormdb to mediate between browser-side business logic and presentation on the one hand and server-side storage on the other, is the subject of another article.

______________________

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix