Foundations.Data.DB

The JavaScript wrapper to db8 (provided with the Foundation libraries) supports a basic set of database operations.

Using Foundations.Data.DB

To use Foundations.Data.DB:

  1. Add the following lines to your app's index.html file:

    <script src="/usr/palm/frameworks/mojo/mojo.js" type="text/javascript" x-mojo-version="1"></script> 
    <script src="/usr/palm/frameworks/mojoloader.js" type="text/javascript"></script>
    
    
  2. Include the following lines of code in your assistant JS file:

    try {
          var libraries = MojoLoader.require({ name: "foundations", version: "1.0"      });
          var Future = libraries["foundations"].Control.Future; // Futures library
          var DB = libraries["foundations"].Data.DB;  // db8 wrapper library
       } catch (Error) {
       Mojo.Log.error(Error);
    }
    
    

    NOTE: The example calls in this documentation use a type of asynchronous callback known as a future. See future link for more information.

  3. To code your JavaScript API calls, see the examples below.

DB Functions

API Description
del Deletes objects from the database. Objects can be specified using a query or array of object IDs.
delKind Deletes a JSON kind object from the database.
find Finds objects matching a query.
get Gets objects by ID. Returns array of complete objects. Fastest way to get data from DB.
merge Updates properties in existing objects. Similar to SQL UPDATE. Objects can be specified using a query or array of object IDs.
put Writes JSON data objects to db8 storage.
putKind Puts a JSON kind object into the database. A kind object must be created before objects of that kind are stored.
reserveIds Reserves a block of object IDs.

 


DB.del

Deletes JSON data objects from the database.

Objects can be specified as a set of IDs (returns PutResponse) or as a db8 Query (returns CountResponse).

Syntax

del(idsOrQuery, purge);

Parameters

Argument Required Type Description
idsOrQuery Yes string array or Query Array of JSON data object IDs or query.
purge No boolean Mark as deleted or purge immediately flag. Default is false. If marked as deleted, records are still retrievable and are not fully deleted until an administrative purge occurs.

Return

Response Succcess: PutResponse (IDs) or CountResponse (query)

Examples

Example delete using ID

   var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls

   var ids = "2+Nd";  // Assign object ID

   DB.del([ids]).then(function(future) {
      var result = future.result;
      if (result.returnValue == true)   
         Mojo.Log.info("del success, count="+result.count);
      else
      {  
         result = future.exception;
         Mojo.Log.info("del failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   });  

Example delete using query

   var DB = libraries["foundations"].Data.DB;  // Get JS wrapper for DB calls

   //**
   //** Delete all records whose state value is equal to "OR" (Oregon)
   //** Note that without state being indexed, this call will fail with a
   //** "no index for query" message.
   //**
   var q = { "from":"com.mystuff.contacts:1", "where":[{"prop":"state","op":"=","val":"OR"}] };

   DB.del(q).then(function(future) {
      var result = future.result;
      if (result.returnValue === true)           
         Mojo.Log.info("del success, count=" + result.count);
      else
      {  
         result = future.exception;
         Mojo.Log.info("del failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   }); 

 


DB.delKind

Deletes a kind object from the database. Deleting a kind deletes ALL data objects of that kind.

Syntax

delKind(id);

Parameters

Argument Required Type Description
id Yes string Name of kind to delete.

Return

Response SuccessResponse

Example

   var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls 
   //...
   DB.delKind("com.mystuff.contacts:1").then(function(future) {
      var result = future.result;
      if (result.returnValue === true)           
         Mojo.Log.info("delKind success");
      else
      {  
         result = future.exception;
         Mojo.Log.info("delKind failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   });

 


DB.find

Returns a set of objects matching a query.

If your query is limited to a specified number of results, you can set a flag to get the number that would have been returned without a limit. You can also set a flag to request notification if any of the returned results from the query changes in the future.

Syntax

find(query, watch, count);

Parameters

Argument Required Type Description
query Yes Query db8 query for retrieving results.
watch Yes boolean Notify if change flag.
count Yes boolean Return number of objects that would have been returned without the limit specified in the query flag.

Return

Response Succcess: FindResponse or NotificationResponse (watch == true)

Examples

Note: The examples below require the loading of the DB foundation libarary:

Example 1: Simple find

This query returns all data objects. No notification and no count is requested.

   var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
   var fquery = {"from":"com.mystuff.contacts:1"};

   DB.find(fquery, false, false).then(function(future) {
      var result = future.result;
      if (result.returnValue === true)   
         Mojo.Log.info("find success, results="+JSON.stringify(result.results));
      else
      {  
         result = future.exception;
         Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
});

Example 2: Simple find with where clause

This query searches for objects whose 'displayName' field begins with a 'J'. All fields are returned. No notification and no count is requested.

   var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
   var fquery = { "from":"com.mystuff.contacts:1","where":[{"prop":"displayName","op":"%","val":"J"}] };

   DB.find(fquery, false, false).then(function(future) {
      var result = future.result;
      if (result.returnValue == true)   
         Mojo.Log.info("find success, results="+JSON.stringify(result.results));
      else
      {  
         result = future.exception;
         Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
});

Example 3: Using select, order by, and desc

This query searches for contacts who live in California (state == 'CA'). The displayName and state fields are returned for each match. Returned objects are sorted on the displayName field in descending order. No notification is requested.

 //**
 //** Note: A dual index for the kind was created, allowing this call to work:
 //**          var indexes = [{"name":"dNameState", props:[{"name": "state"}, {"name":"displayName"}]} ];
 //**
 //**       The query below will not work if 'displayName' is declared as the first 'props' entry and 'state' the second.
 //**       Results can only be returned for contiguously ordered index entries. If you have the entries ["CA", "John Doe"], ["CA","Mabel Syrup"], etc.,
 //**       then, all of the entries with the same state are consecutive and only secondarily ordered by display name. Therefore, the index can answer the query.
 //**       If the index entries were ordered in ["displayName", "state"] order, the entries for the same state are not consecutive and
 //**       could not be used to answer the query (the query would fail with a "no index for query" message).

   var fquery = {"select": ["displayName", "state"],
                 "from":"com.mystuff.contacts:1",
                 "where":[{"prop":"state","op":"=","val":"CA"}], 
                 "orderBy":"displayName",
                 "desc":true };

   DB.find(fquery, false, false).then(function(future) {
      var result = future.result;
      if (result.returnValue == true)   
         Mojo.Log.info("find success, results="+JSON.stringify(result.results));
      else
      {  
         result = future.exception;
         Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   });

Example 4: Query with change notification

This example shows how change notiification for a find works. Initially, a find with change notification (watch=true) is issued on a non-existent Kind and DB. Empty results are then returned. A number of operations are done that alter the results which fires the find's change notification flag. Each time, the find with a watch is re-issued and the new results are printed out.

   //** Create Kind object for test
   var testKind = {
   name: "dbtest:1",
   owner: "com.palm.dbtest",
   indexes: [ 
      {name:"name", props: [{name: "name"}]},
      {name:"profession", props:[{name: "profession"}]}      
      ]
   };

   //** Create 5 test data objects
   var testData =  [
   {
      _kind: testKind.name,
      name: "Mark",
      age: 40,
      profession: "engineer"
   },
   {
      _kind: testKind.name,
      name: "Yvette",
      age: 36,
      profession: "trainer"
   },
   {
       _kind: testKind.name,
      name: "Lenny",
      age: 45,
      profession: "engineer"
   },
   {
      _kind: testKind.name,
      name: "Homer",
      age: 51,
      profession: "safety inspector"
   },
   {
      _kind: testKind.name,
      name: "Marge",
      age: 48,
      profession: "homemaker"
   }
   ];

   //** Create query object for test
   var query = {
      select: ["name", "age"],
      from: testKind.name,
      where: [{prop: "profession", op: "=", val: "engineer"}],
      desc: false,   //** descending
      incDel: false, //** include deleted
      limit: 500
   };

   //** Do find on non-existent Kind with watch. No results initially returned.
   DB.find({from:testKind.name}, true, 500).then(function print_it(future) {

   //** Notification that results have changed
   if (future.result.fired) {
      Mojo.Log.info("DB.find watch fired, re-issuing 'find'");

      //** Re-issue find to get changed results
      return DB.find({from:testKind.name}, true, 500).then(print_it);

   } 
   else { 
       //** Log find results
       Mojo.Log.info("DB.find Database contents: "+JSON.stringify(future.result));
   }

      //** Re-establish future
      future.then(print_it);
      },
      function error(future) { //** Log error
         Mojo.Log.info("error: "+future.exception);
   });

   //** Create test Kind in database
   DB.putKind(testKind.name, testKind.owner, testKind.indexes).then(function(future) {
      Mojo.Log.info("putKind returned "+JSON.stringify(future.result));

   return DB.put(testData); //** Put test data into database

   }).then(function(future){ 
      // Log put results
      Mojo.Log.info("put returned "+JSON.stringify(future.result)); 
      var changes = {
           profession: "janitor"
       };

   return DB.merge(query, changes); // Change all professions to janitor
   }).then(function(future){
      // Log merge results
      Mojo.Log.info("merge returned "+JSON.stringify(future.result));
      var delQuery = {
       from: testKind.name        
   };

   return DB.del(delQuery);  // Delete all records in DB
   }).then(function(future){
      //** Log delete results
      Mojo.Log.info("delete returned "+JSON.stringify(future.result));
      return true;
   }).then(function(future){  
   return;
});

When this code is run, the following results (without comments) are logged, showing the sequence of events:

   //** Initial find results on empty DB
      com.palm.dbtest: Info: DB.find Database contents: {"returnValue":true,"results":[],"count":0}, 

   //** Kind stored in DB
      com.palm.dbtest: Info: putKind returned {"returnValue":true}, 

   //** Put fires find watch, find re-issued
      com.palm.dbtest: Info: DB.find watch fired, re-issuing find, 

   //** Results from put
      com.palm.dbtest: Info: put returned {"returnValue":true,"results":[{"id":"20RH","rev":5906},{"id":"20RI","rev":5907},{"id":"20RJ","rev":5908},{"id":"20RK","rev":5909},{"id":"20RL","rev":5910}]}, 

   //** First reissued find results returned
      com.palm.dbtest: Info: DB.find Database contents: {"returnValue":true,"results":[{"_id":"20RH","_kind":"dbtest:1","_rev":5906,"age":40,"name":"Mark","profession":"engineer"},{"_id":"20RI","_kind":"dbtest:1","_rev":5907,"age":36,"name":"Yvette","profession":"trainer"},{"_id":"20RJ","_kind":"dbtest:1","_rev":5908,"age":45,"name":"Lenny","profession":"engineer"},{"_id":"20RK","_kind":"dbtest:1","_rev":5909,"age":51,"name":"Homer","profession":"safety inspector"},{"_id":"20RL","_kind":"dbtest:1","_rev":5910,"age":48,"name":"Marge","profession":"homemaker"}],"count":5}, 

   //** Merge fires re-issued find
      com.palm.dbtest: Info: DB.find watch fired, re-issuing find, 

   //** Merge results returned
      com.palm.dbtest: Info: merge returned {"returnValue":true,"count":2}, 

   //** Second re-issued find results returned
      com.palm.dbtest: Info: DB.find Database contents: {"returnValue":true,"results":[{"_id":"20RH","_kind":"dbtest:1","_rev":5911,"age":40,"name":"Mark","profession":"janitor"},{"_id":"20RI","_kind":"dbtest:1","_rev":5907,"age":36,"name":"Yvette","profession":"trainer"},{"_id":"20RJ","_kind":"dbtest:1","_rev":5912,"age":45,"name":"Lenny","profession":"janitor"},{"_id":"20RK","_kind":"dbtest:1","_rev":5909,"age":51,"name":"Homer","profession":"safety inspector"},{"_id":"20RL","_kind":"dbtest:1","_rev":5910,"age":48,"name":"Marge","profession":"homemaker"}],"count":5}, 

   //** Delete fires re-issued find
      com.palm.dbtest: Info: DB.find watch fired, re-issuing find, 

   //** Delete results returned
      com.palm.dbtest: Info: delete returned {"returnValue":true,"count":5}, 

   //** Third re-issued find results returned. DB now empty again
      com.palm.dbtest: Info: DB.find Database contents: {"returnValue":true,"results":[],"count":0}, 

Example 4: Query showing use of paging

Query to get 20 contacts, then use page key from first query to get 20 more contacts.

   //** Create query to get 20 contacts who live in California
   var fquery = {"from":"com.mystuff.contacts:1",
                "where":[{"prop":"state","op":"=","val":"CA"}],
                "limit": 20};  

   DB.find(fquery, false, true).then(function(future) {
       var result = future.result;
       if (result.returnValue == true)  
       {
          Mojo.Log.info("First page results, count = "+result.count);
          var rs = result.results;

          for (var i=0; i < rs.length; i++)
             Mojo.Log.info("#"+i+" "+ rs[i].name[0].familyName+", "+rs[i].name[0].givenName);

    //** ...
    //** Do something, i.e., wait for user to press next key
    //** ...

   //**
   //** Create query to get next 20 contacts. Use next page key returned from previous query
   //** 
    fquery = {  "from":"com.mystuff.contacts:1",
                "where":[{"prop":"state","op":"=","val":"CA"}],
                "limit": 20,
                "page":result.next};
    //**
    //** Get next page of results
    //**                 
    DB.find(fquery, false, true).then(function(future) {
         var result = future.result;
         if (result.returnValue === true)        
         {      
            Mojo.Log.info("Next page results, count = "+result.count);
            var rs = result.results;
            for (var i=0; i < rs.length; i++)
               Mojo.Log.info("#"+i+" "+ rs[i].name[0].familyName+", "+rs[i].name[0].givenName);
         }
         else
         {  
            result = future.exception;
            Mojo.Log.info("Next find failure: Err code=" + result.errorCode + "Err message=" + result.message); 
         }
   });

  }
  else
     Mojo.Log.error("First page failure: Err code=" + result.errorCode + "Err text=" + result.errorText);
}); 

 


DB.get

Gets JSON data objects by IDs.

Syntax

get(ids);

Parameters

Argument Required Type Description
ids Yes string array Array of JSON data object IDs.

Return

Response GetResponse

Example

   //** Get JS wrapper for DB calls
   var DB = libraries["foundations"].Data.DB;  
   //...
   var ids = ["2+OG", "2+OK"];    
   DB.get(ids).then(function(future) {
      var result = future.result;
      var rs = future.result.results;
      if (result.returnValue == true)
      {
          for (var i=0; i < result.results.length; i++)
          {             
              Mojo.Log.info("get success, id="+ rs[i]._id+", kind="+rs[i]._kind+", displayName="+rs[i].displayName+", nickname="+rs[i].nickname+", familyName="+rs[i].name[0].familyName);
          }
      }
      else
      {  
         result = future.exception;
         Mojo.Log.info("get failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   }); 

 


DB.merge

Updates properties in existing objects. Objects can be specified using query. (returns CountResponse) or array of IDs.

Syntax

merge(objectsOrQuery, properties);

Parameters

Argument Required Type Description
objectsOrQuery Yes any array of IDs and properties to update, or db8 Query
properties No any Array of name/value pairs to update (if using db8 Query).

Return

Response Succcess: PutResponse (IDs), or CountResponse (query)

Examples

Example using IDs

   var DB = libraries["foundations"].Data.DB;  // Get JS wrapper for DB calls 

   //** Create objects to update nickname field
   var m1 = {  "_id": "2+SF", "nickname": "Spaz" };
   var m2 = {  "_id": "2+SJ","nickname": "Sugar" };

   var objs2 = [m1, m2];
   DB.merge(objs2).then(function(future) {
      var result = future.result;
      var rs = result.results;
      if (result.returnValue === true)   
      {         
         Mojo.Log.info("merge success");
         for (var i=0; i < rs.length; i++)
            Mojo.Log.info("#"+i+": r.id="+rs[i].id+", r.rev="+rs[i].rev);
      }
      else
      {  
         result = future.exception;
         Mojo.Log.info("merge failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   });

Example using query

   //**
   //** Assign a property to update, and create the query
   //** Note that indexes must exist for the fields you are querying on
   //**
   var mprops = { "nickname":"Spud"};
   var mquery = { "from":"com.mystuff.contacts:1","where":[{"prop":"displayName","op":"%","val":"J"}] };

   DB.merge(mquery, mprops).then(function(future) {
      var result = future.result;
      if (result.returnValue === true)   
         Mojo.Log.info("merge success, number updated = "+result.count);
      else
      {  
         result = future.exception;
         Mojo.Log.info("merge failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   });

 


DB.put

Puts JSON data objects of a particular kind into the database. Assigns id field if not set. Returns id and rev for each object stored.

Syntax

put(objs);

Parameters

Argument Required Type Description
objs Yes any object array Array of JSON data objects.

Return

Response PutResponse

Example

   var DB = libraries["foundations"].Data.DB;  // Get JS wrapper for DB calls

   //** Create new JSON data object     
   var  contact1 = {
      _kind: "com.mystuff.contacts:1",
      displayName: "John Doe",
      name: [{"familyName":"Doe", "givenName":"John"}],
      nickname: "Skippy",
      emails:[
        {"value":"jdoe@gmail.com", "type":"home"},
        {"value": "john.doe@palm.com", "type":"work"}]};

   //** Create object array
   var objs = [contact1];

   DB.put(objs).then(function(future) {
      var result = future.result;
      if (result.returnValue === true)   
         Mojo.Log.info("put success, c.id="+result.results[0].id+", c.rev="+result.results[0].rev);
      else
      {  
         result = future.exception;
         Mojo.Log.info("put failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   });

 


DB.putKind

Register a kind JSON object with the database.

Kind objects define the indexes for a JSON data object.

Your index can be composed of multiple fields. When you create your index, be aware that queries can only return results that are contiguously indexed. See All Queries Must be on Indexed Fields for more information.

If your app or service creates objects that other apps or services need to access, then see Allowing Other Apps or Services to Access Your db8 Data for more information.

Syntax

putKind(id, owner, indexes);

Parameters

Argument Required Type Description
id Yes string Kind identifier.
owner Yes string Kind owner - Service's bus address or app's app ID. Only the owner has permission to modify the kind.
indexes No IndexClause array Kind indexes.

Return

Response Succcess: SuccessResponse
Failure: ErrResponse

Example

   var DB = libraries["foundations"].Data.DB;  // Get JS wrapper for DB calls
   var indexes = [{"name":"state", props:[{"name": "state"}]}];
   DB.putKind("com.palm.contacts:1", "com.palm.contacts", indexes).then(function(future) {
      var result = future.result;
      if (result.returnValue === true)                   
         Mojo.Log.info("putKind success");
      else
      {  
         result = future.exception;
         Mojo.Log.info("putKind failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   });

 


DB.reserveIds

Reserves a block of object ids.

Syntax

reserveIds(count);

Parameters

Argument Required Type Description
count Yes integer Number of Ids to reserve.

Return

Response Succcess: SuccessResponse
Failure: ErrResponse

Example

Get block of 10 IDs:

    var DB = libraries["foundations"].Data.DB;  //  Get JS wrapper for DB calls

    DB.reserveIds(10).then(function(future) {
       var result = future.result;
       if (result.returnValue === true)  
          Mojo.Log.info("reserveIds success, results="+JSON.stringify(result.ids));
      else
      {  
         result = future.exception;
         Mojo.Log.info("reserveIds failure: Err code=" + result.errorCode + "Err message=" + result.message); 
      }
   });