For up-to-date product documentation, see the IBM MobileFirst Foundation Developer Center.


JSONStore API concepts

JSONStore provides API reference information for Cordova Android, iOS, Windows 8 Universal, and native Android and iOS applications.


Store


Open and initialize a collection

Starts one or more collections. Starting or provisioning a JSONStore collection means that the persistent storage that is used to contain collections and documents is created, if it does not exist. If the store is encrypted and a correct password is passed, the required security procedures to make the data accessible are run. There is minimal effort in initializing all the collections when an application starts.

After you open a collection, an accessor to the collection is available, which gives access to collection APIs. It allows developers to call functions such as find, add, and replace on an initialized collection.

It is possible to initialize multiple times with different collections. New collections are initialized without affecting collections that are already initialized.


Destroy

Completely wipes data for all users, destroys the internal storage, and clears security artifacts. The destroy function removes the following data:


Close all

Locks access to all the collections in a store until the collections are reinitialized. Where initialize can be considered a login, close can be considered a logout.


Start, commit, and rollback transaction

A transaction is a set of operations that must all succeed for the operations to manipulate the store. If any operation fails, the transaction can be rolled back to revert the store to its previous state. After a transaction is started, it is important that you handle committing or rolling back your transactions to prevent excess processing. Three operations exist in the Store API for transactions:

Note: Due to system limitations with multi-threaded transactions, transactions are not supported in Android 2.3.x for Cordova applications. To use transactions in a Cordova application in Android 2.3.x, we can create a Cordova plug-in that uses the native Android JSONStore API to execute the code for the transaction. The whole transaction must be done in the same thread because multi-threaded transactions do not work properly in Android 2.3.x.


Collection


Store and add a document

We can add a document or array of documents to a collection. We can also pass an array of objects (for example [{name: 'carlos'}, {name: 'tim'}]) instead of a single object. Every object in the array is stored as a new document inside the collection.


Remove a document

Marks one or more documents as removed from a collection. Removed documents are not returned by the find or count operations.


Find All Documents, Find Documents by Id, and Find With Query

We can find documents in a collection by their search fields and extra search fields. An internal search field, _id, holds a unique integer identifier that can be used to find the document (Find by Id). We can search for documents with the following APIs:

Filter returns what is being indexed, which might be different than what was saved to a collection. Some examples of unexpected results are:

  1. If your search field has uppercase letters, the result is returned in all lowercase letters.
  2. If you pass something that is not a string, it is indexed as a string. For example, 1 is '1', 1.0 is '1.0', true is '1', and false is '0'.
  3. If your filter criteria includes non top-level search fields, you might get a single string with all the terms that are joined by a special identifier (-@-). For example, 'carlos-@-mike-@-dgonz'.


Replace a document and change documents

We can use the Replace API to replace the contents of a document in the collection with new data, which is based on the _id. If the data contains the _id field of a document in the database, the document is replaced with the data and all search fields are reindexed for that document.

The Change API is similar to the Replace API, but the Replace is based on a set of search field criteria instead of _id. The Replace API can be emulated by performing the Change API with the search field criteria of only _id. All search fields in the search field criteria must exist in the documents in the store, and in the data that is passed to the Change API.


Count All Documents, Count All Dirty Documents, and Count With Query

The Count API returns an integer number by counting the total number of documents that match the query. There are three Count APIs:


Remove Collection and Clear Collection

Removing a collection deletes all data that is associated with a collection, and causes the collection accessor to be no longer usable.

Clearing a collection deletes all documents in the collection. This operation keeps the collection open after it completes.


Mark Clean

The Mark Clean API is used to remove the dirty flag from a document in the collection, and deletes the document completely from the collection if it was marked dirty by a remove document operation. The Mark Clean API is useful when used with the Find All Dirty Documents API to sync the collection with a remote database.


Additional references


Search Query format

When an API requires a search query, a common format is followed for the collection. A query consists of an array of objects where each key/value pair is ANDed together. Each object in the array is ORed together. For example:

[{fn: "Mike", age: 30}, {fn: "Carlos", age: 36}] is represented as (with fuzzy search):

(fn LIKE "%Mike%" AND age LIKE "%30%") OR (fn LIKE "%Carlos%" AND age LIKE "%36%")


Search Query Parts format

The following examples use pseudocode to convey how query parts work. A query such as {name: 'carlos', age: 10} can be passed a modifier such as {exact: true}, which ensures only items that exactly match name and age are returned. Query parts give you the flexibility of adding modifiers to any part of the query. For example:

queryPart1 = QueryPart().like('name', 'carlos').lessThan('age', 10);

The previous example is transformed into something like:

('name' LIKE %carlos%) AND (age < 10)

We can also create another query part, for example:

queryPart2 = QueryPart().equal('name', 'mike')

When you add various query parts with the find API, for example:

find([queryPart1, queryPart2]

You get something like:

( ('name' LIKE %carlos%) AND (age < 10) ) OR (name EQUAL 'mike')


Limit and Offset

Passing a limit to an API's options restricts the number of results by the number specified. It is also possible to pass an offset to skip results by the number specified. To pass an offset, a limit must also be passed. This API is useful for implementing pagination or for optimization. By limiting the data to a subset that is necessary, the memory and processing power is reduced.


Fuzzy Search versus Exact Search

The default behavior is fuzzy searching, which means that queries return partial results. For example, the query {name: 'carl'} finds 'carlos' and 'carl' (for example, name LIKE '%carl%'). When {exact: true} is passed, matches are exact but not case-sensitive. For example, 'hello' matches 'Hello' (for example, name.toLowerCase() = 'hello'). Integer matching is not type-sensitive. For example, "1" matches both "1" and "1.0". Numbers are stored as their decimal representation. For example, "1" is stored as "1.0". Boolean values are indexed as 1 (true) and 0 (false).

Parent topic: JSONStore