ObjectDB is a transactional database library that lets you treat tables as JSON structures of arbitrary size and depth. Elements in the JSON structure are addressable with URI-encoded paths, and written using simple put
and delete
calls, as well as append
and insert
for array elements.
ObjectDB is backed by indexedDB, the standard transactional noSQL database available in modern browsers. Its API makes indexedDB much easier to work with, but no less powerful.
The jsonv editor UI below allows you to modify the JSON structure stored in a database on your browser. To the right are the commands executed on your behalf.
Error: Your browser does not appear to support indexedDB. Data below will not be persisted. See Compatibility.
- array:
- elem1
- elem2
- null: null
- number: 123
- object:
- key: value
- string: hello world
var db = objectDB.open("demo", {"array":["elem1","elem2"],"null":null,"number":123,"object":{"key":"value"},"string":"hello world"}); db.get();
Below are examples of objectDB's common uses. For detailed interface specs, see the documentation.
var db = objectDB.open('demo');
var db = objectDB.open('demo', {object: {key: 'value'}, array: ['elem1', 'elem2']});
The JSON data specified in the second argument gets populated to any new objectStore involved in the first transaction on this database if an indexedDB upgrade event is triggered.
var db = objectDB.open('demo', function(upgrade) { upgrade.createObjectStore('newData', {key: 'value'}); }, 2, function(error, blocked) { if (blocked) alert('Database is already open in another window. Please close to continue.'); else console.error(error); });
If the second argument is a function, it should handle an upgrade event using the provided UpgradeTransaction
object. If the third (positive integer) argument is specified and greater than the current database version (1 at database creation), an upgrade event is triggered. An optional fourth argument is both the error handler and blocked operation handler for the database.
The database object returned by open
immediately supports basic reads and writes to the default objectStore.
db.get().then(function(data) { console.log(data); });
{object: {key: 'value'}, array: ['elem1', 'elem2']}
db.get('array').then(function(data) { console.log(data); });
['elem1', 'elem2']
db.get('object').get('array').then(function(obj, arr) { console.log(obj, arr); });
{key: 'value'}, ['elem1', 'elem2']
db.put('path', 'data').then(function(error) { console.error(error); });
db.get('', false, 'immediates').then(function(data) { console.log(data); });
{object: {}, array: []}
db.get('array', function(path, array) { return function(key) { return key < 1; }; }).then(function(data) { console.log(data); });
['elem1']
db.get('number', true).then(function(num) { this.put('number', num+1); // transactional increment });
db.transaction(true, ['sessions', 'users']) .delete('sessions', 'kganser') .delete('users', 'kganser');
ObjectDB requires indexedDB support, including array keys. Check the compatibility table and feature tests for your browser.
objectDBopendatabasestringupgrade`{}`jsonUpgradeTransactionversion1numberonErrorundefinederrorDOMErrorblockedbooleanDatabasedeletedatabasestringcallbackerrorundefinedDOMErrorblockedboolean
ObjectDB is backed by indexedDB
. An upgrade transaction runs on open
if the database version is less than the requested version or does not exist. If upgrade
is a json value, the data stores in the first transaction operation on this Database
will be populated with this value on an upgrade event. Otherwise, an upgrade will be handled by the given function via UpgradeTransaction
.
UpgradeTransactionoldVersionnumbernewVersionnumbercreateObjectStorenamestringdata`{}`jsonUpgradeTransactiondeleteObjectStorenamestringUpgradeTransaction
Databasetransactionwritablefalsebooleanstores'data'string...stringTransactionScopedTransactiongetpath''Pathwritablefalsebooleancursor'deep'Cursorstore'data'stringScopedTransactioncountpath''PathwritablefalsebooleanboundsundefinedBoundsstore'data'stringScopedTransactionputpath''Pathvaluejsonstore'data'stringScopedTransactioninsertpath''Pathvaluejsonstore'data'stringScopedTransactionappendpath''Pathvaluejsonstore'data'stringScopedTransactiondeletepath''Pathstore'data'stringScopedTransactionclosefunction
get
, count
, put
, insert
, append
, and delete
are convenience methods that operate through transaction
for a single objectStore and return the corresponding ScopedTransaction
. get
and count
initiate a read-only transaction by default. transaction
returns a ScopedTransaction
if a single (string) objectStore is specified, and a Transaction
if operating on multiple objectStores.
Transactiongetstorestringpath''Pathcursor'deep'CursorTransactioncountstorestringpath''PathboundsundefinedBoundsTransactionputstorestringpath''PathvaluejsonTransactioninsertstorestringpath''PathvaluejsonTransactionappendstorestringpath''PathvaluejsonTransactiondeletestorestringpath''PathTransactionthencallbackthisTransactionjsonundefined...Transaction
A Transaction
acting on multiple data stores must specify a data store as the first argument to every operation. Otherwise, these methods correspond to ScopedTransaction
methods.
ScopedTransactiongetpath''Pathcursor'deep'CursorScopedTransactioncountpath''PathboundsundefinedBoundsScopedTransactionputpath''PathvaluejsonScopedTransactioninsertpath''PathvaluejsonScopedTransactionappendpath''PathvaluejsonScopedTransactiondeletepath''PathScopedTransactionthencallbackthisScopedTransactionjsonundefined...ScopedTransaction
All methods are chainable and execute on the same transaction in parallel. then
assigns a callback for the preceding sequence of operations, or throws an error if no operations are pending. If the transaction is not writable, put
, insert
, append
, and delete
throw an error.
By default, cursor
buffers all data at the requested path as the result of a get
operation. count
returns a count of the number of elements in an object or array at path
(with optional bounds
). insert
will splice the given value
into the parent array at the specified position, shifting any subsequent elements forward.
When all its pending operations complete, callback
is called with the result of each queued operation in order. More operations can be queued onto the same transaction at that time via this
.
Results from put
, insert
, append
, and delete
are error strings or undefined if successful. get
results are json data or undefined if no value exists at the requested path.
Pathstringstringnumber...
Path is either a /
-delimited string of encodeURIComponent
-encoded keys or an array of unencoded keys and numeric indices to an element within the json data structure; e.g. 'users/123/firstName'
or ['users', 123, 'firstName']
.
BoundslowerBoundnullstringnumberlowerExclusivefalsebooleanupperBoundnullstringnumberupperExclusivefalseboolean
CursorstringLevelCursorpathstringnumber...arraybooleanbooleanActionLevelCursor
LevelCursorlowerBoundnullstringnumberlowerExclusivefalsebooleanupperBoundnullstringnumberupperExclusivefalsebooleandescendingfalsebooleanactionundefinedActionvalueundefinedkeystringnumbernullvaluejsonjsonundefined
Actionkeystringnumberundefinedstring
Cursor
controls how data is traversed and buffered in a get
request. String values 'shallow'
, 'immediates'
, and 'deep'
control the depth of the returned data object. As a function, Cursor
is called for each array or object encountered in the requested json structure. It is called with a path
array (of strings and/or numeric indices) relative to the requested path (i.e. []
represents the path as requested in get
) and an array
boolean that is true if the substructure is an array. It returns an Action
callback or object with a range and action
, or false to prevent recursion into the structure. lowerBound
and upperBound
restrict the keys/indices traversed for this object/array, and the Action
function is called with each key
in the requested range, in order. The Action
callback can optionally return either 'skip'
or 'stop'
to exclude the element at the given key from the structure or to exclude and stop iterating, respectively. If specified, the value
function receives the value retrieved from each key
and returns a value to insert into the parent object or array, or undefined to skip insertion. value
is then also called with null key
and the object/array value itself. If Cursor
is a LevelCursor
object, it applies to the top-level object or array.
For example, the following call uses a cursor to fetch only the immediate members of the object at the requested path (equivalent to 'immediates'
). Object and array values will be empty:
db.get('path/to/object', false, function(path) { return !path.length; });
The following call will get immediate members of the requested object sorted lexicographically (by code unit value) up to and including key value 'c'
, but excluding key 'abc'
(if any):
db.get('path/to/object', false, function(path) { return path.length ? false : { upperBound: 'c', action: function(key) { if (key == 'abc') return 'skip'; } }; });