SmartStore defines standard fields that help you track entries and synchronize soups with external servers.
System Fields: _soupEntryId and _soupLastModifiedDate
To track soup entries for insert, update, and delete actions, SmartStore adds a few fields to each entry:
\_soupEntryId—This field is the primary key for the soup entry in the table for a given soup.
\_soupLastModifiedDate, \_soupCreatedDate—The number of milliseconds since 1/1/1970.
To convert a date value to a JavaScript date, use new Date(entry._soupLastModifiedDate).
To convert a date to the corresponding number of milliseconds since 1/1/1970, use date.getTime().
When you insert or update soup entries, SmartStore automatically sets these fields. When you remove or retrieve specific entries, you can reference them by \_soupEntryId.
Beginning with Mobile SDK 4.2, SmartStore creates indexes on the \_soupLastModifiedDate and \_soupCreatedDate fields. These indexes provide a performance boost for queries that use these fields. In older soups, the \_soupLastModifiedDate and \_soupCreatedDate fields exist but are not indexed. To create these indexes to legacy soups, simply call alterSoup and pass in your original set of index specs.
About Upserting
To insert or update soup entries—letting SmartStore determine which action is appropriate—you use an upsert method.
If \_soupEntryId is already set in any of the entries presented for upsert, SmartStore updates the soup entry that matches that ID. If an upsert entry doesn’t have a \_soupEntryId slot, or its \_soupEntryId doesn’t match an existing soup entry, SmartStore inserts the entry and overwrites its \_soupEntryId.
Upserting with an External ID
If your soup entries mirror data from an external system, you usually refer to those entries by their external primary key IDs. For that purpose, SmartStore supports upsert with an external ID. When you perform an upsert, you can designate any index field as the external ID field. SmartStore looks for existing soup entries with the same value in the designated field with the following results:
If no field with the same value is found, SmartStore creates a soup entry.
If the external ID field is found, SmartStore updates the entry with the matching external ID value.
If more than one field matches the external ID, SmartStore returns an error.
To create an entry locally, set the external ID field to a value that you can query when uploading the new entries to the server.
When you update the soup with external data, always use the external ID. Doing so guarantees that you don’t end up with duplicate soup entries for the same remote record.
SmartStore also lets you track inter-object relationships. For example, imagine that you create a product offline that belongs to a catalog that doesn’t yet exist on the server. You can capture the product’s relationship with the catalog entry through the parentSoupEntryId field. Once the catalog exists on the server, you can capture the external relationship by updating the local product record’s parentExternalId field.
Upsert Methods
JavaScript:
The cordova.force.js library provides two JavaScript upsert functions, each with one overload:
To upsert local data only, use the first upsert() function. To upsert data from an external server, use the second function, which supports the externalPathId parameter.
iOS native:
The iOS SFSmartStore class provides two instance methods for upserting. The first lets you specify all available options:
Soup name
NSArray object containing index specs
Path for an external ID field name
An output NSError object to communicate errors back to the app
The following JavaScript code contains sample scenarios. First, it calls upsertSoupEntries to create an account soup entry. In the success callback, the code retrieves the new record with its newly assigned soup entry ID. It then changes the account description and calls forcetk.mobilesdk methods to create the account on the server and then update it. The final call demonstrates an upsert with external ID. To make the code more readable, no error callbacks are specified. Also, because all SmartStore calls are asynchronous, real applications perform each step in the success callback of the previous step.
This code uses the value new for the id field because the record doesn’t yet exist on the server. When the app comes online, it can query for records that exist only locally (by looking for records where id == "new") and upload them to the server. Once the server returns IDs for the new records, the app can update their id fields in the soup.
1var sfSmartstore = function(){2 return cordova.require("com.salesforce.plugin.smartstore");3};4// ...5// Specify data for the account to be created6var acc = {id: "new", Name: "Cloud Inc", Description: "Getting started"};78// Create account in9// This upsert does a "create" because10// the account has no _soupEntryId field11sfSmartstore().upsertSoupEntries("accounts", [acc], function(accounts){12 acc = accounts[0];13 // acc should now have a _soupEntryId field14 // (and a _lastModifiedDate as well)15});1617// Update account's description in memory18acc["Description"] = "Just shipped our first app ";1920// Update account in21// This does an "update" because acc has a _soupEntryId field22sfSmartstore().upsertSoupEntries("accounts", [acc], function(accounts){23 acc = accounts[0];24});2526// Create account on server27// (sync client -> server for entities created locally)28force.create(29 "account",30{31 Name: acc["Name"],32 Description: acc["Description"],33},34 function(result){35 acc["id"] = result["id"];36 // Update account in37 sfSmartstore().upsertSoupEntries("accounts", [acc]);38},39);4041// Update account's description in memory42acc["Description"] = "Now shipping for iOS and Android";4344// Update account's description on server45// Sync client -> server for entities existing on server46force.update("account", acc["id"], {Description: acc["Description"]});4748// Later, there is an account (with id: someSfdcId) that you want49// to get locally5051// There might be an older version of that account in the52// already5354// Update account on client55// sync server -> client for entities that might or might not56// exist on client57force.retrieve("account", someSfdcId, "id,Name,Description", function(result){58 // Create or update account in59 // (looking for an account with the same sfdcId)60 sfSmartstore().upsertSoupEntriesWithExternalId("accounts", [result], "id");61});
We've Moved
Welcome to the new home of the Mobile SDK Developer Guide! For now, the Japanese guide can be found in PDF form.