Key-value storage

Some apps need to store and retrieve data. For example, consider the workflow of a project management app such as JIRA. When an agent links a ticket to an issue in JIRA, a relation between the ticket ID and issue ID is stored, which when retrieved displays the details of the relevant JIRA issue along with the ticket.

To enable the development of such apps, we provide a data store for apps to set (store) and get (retrieve) data. Also, data can be deleted when it is no longer required.

Important:

Consider a case where your global app has two modules. The modules belong to different products and on deployment are deployed on different SKUs (that is, different product bundles). In the local environment, the logic specific to one of these modules can access and use a value that the other module stores in the Key-value storage (KV store). So, the local testing of your app is successful. In production, this cross-SKU access is not there. So, the app breaks.


You should implement your app logic in such a way that a module’s logic does not retrieve and use the value that the other module stores in the KV store, if the two modules cannot be deployed for the same SKU subscriptions.


To verify the compatible SKU subscriptions of a module, see Module introduction > Who can access an app built for this module?.

The data store has the following limitations:

  • Data is stored on a per account AND per app basis i.e., the scope is on a per installation basis. This means that if two apps have been installed by an account, data stored by one app is not accessible by the other app.

  • A rate limit of 50 requests per minute applies with each set, get, and delete counting as one request. This rate limit is applied separately for each installed app which means that if two apps have been installed by an account, the rate limit will apply separately to each app. This limit is not affected by the number of agents in the account.

Store

client.db.set(key, value, options)

Stores the key, value pair in the data store. UTF-8 characters are supported. If an entry with the key is already present, then the value will be updated. The options field is not mandatory and by default is an empty hash.

Important:

Ensure that the following conditions are met while performing the set operation.

  • The key should not be blank and its length should not exceed 60 characters.
  • The combined size of the key and value should not exceed 40 KB.
  • The value should be of type JSON and not blank or empty "{}".
  • The values in the JSON Object will be converted to null - empty strings, NaN, "+/- Infinity".

Tip:When testing, you may need to click the shield icon in your browser’s address bar and then click Load unsafe scripts. For more information, refer to the Testing section.

Options

The following attributes can be specified in the options field.

  • Time to live (ttl)

    Specifies the expiration period of the key in the data store in seconds. The ttl attribute supports both integer and float data types. If you do not set the ttl value or if the value is negative, the key will exist forever.

    app.js
    client.db.set( "contact:101", { "jiraIssueId": 15213 }, {ttl: 60}).then(
      function(data) {
        // success operation
        // "data" value is { "Created" : true }
      },
      function(err) {
        // Handle error
        console.error(err.status);
        console.error(err.message);
    });

    This sample code sets the key to expire after 60 seconds.

  • Set If (setIf)

    The setIf attribute takes any one of the two values: exist or not_exist. The {setIf: "exist"} code stores the value if the key exists in the data store and throws an error if the key does not exist in the data store. Similarly, {setIf: "not_exist"} stores the value if the key does not exist in the data store and throws an error if it is an existing key.

    app.js
    client.db.set( "contact:101", { "jiraIssueId": 15213 }, {setIf: "exist"}).then(
    function(data) {
    // success operation
    // "data" value is { "Created" : true }
    },
    function(err) {
    // Handle error
    console.error(err.status);
    console.error(err.message);
    });

Retrieve

client.db.get(key)

Used to retrieve stored data. If the retrieval is successful, the JSON value can be accessed using the data parameter in the .then function.

Update

client.db.update(key, action, attributes)

Updates the corresponding key value in the data store. UTF-8 characters are supported.

Important:

Ensure that the following conditions are met while performing the update operation.

  • The key should not be blank and its length should not exceed 60 characters.
  • The value should be of type JSON and not blank or empty "{}".
  • The values in the JSON Object will be converted to null - empty strings, NaN, "+/- Infinity".

The action field can take any one of the following parameters.

ParameterDescription
IncrementAdds a new value to the existing attribute value in the attributes object.
AppendAppends a new value to the existing attribute value in the attributes object.
SetAdds one or more top-level or nested attributes and values to the key, value pair.
RemoveRemoves one or more attributes and values from the key, value pair.
Note:

For serverless apps, you need to use the following format.

$db.update(key, action, attributes)

Increment

Adds the new value specified in the attributes object to the existing attribute value in the data store.

client.db.update(key, "increment", attributes)
  • If an attribute does not exist, the increment action adds the specified attribute and its value to the key in the data store.
  • If the new value passed in the attributes object is a negative number, then it is subtracted from the existing value.
  • If you execute the increment action on a key which does not exist in the data store, the attributes object is stored in the data store with the specified key. This is similar to the Store operation.
Notes:
  • The attributes field takes an object containing the attribute name and value which you want to increment.
  • The increment action:
    • Supports only number data type.
    • Can be used on top-level attributes, not nested attributes.

Example

Suppose you want to store the number of customer interactions in the data store. So, when a customer interacts with an agent, you store an object with Customer ID as key using client.db.set. The sample object would look like this in the data store.

{
  Name: "sample_customer",
  Company: "sample_company",
  Interactions: 3
}

To update the interactions value every time the customer interacts with the agent, you can use the update operation with increment action.

Updated object
{
  Name: "sample_customer",
  Company: "sample_company",
  Interactions: 4
}

Append

Appends the new value specified in the attributes object to the existing attribute value in the data store.

client.db.update(key, "append", attributes)
  • If an attribute does not exist, the append action adds the specified attribute and its value to the key in the data store.
  • If you execute the append action on a key which does not exist in the data store, the attributes object is stored in the data store with the specified key. This is similar to the Store operation.
Notes:
  • The attributes field takes an object containing the attribute name and value which you want to append.
  • The append action:
    • Supports only array data type.
    • Can be used on top-level attributes, not nested attributes.

Example

Suppose you want to store a list of customers interacting with an agent. You can create an object in the data store with Agent ID as key.

{
  agent_name: "sample_agent",
  agent_type: "support",
  associated_customers: ["customer1","customer2","customer3"]
}

To add a new customer who interacted with the agent to the list, you can use the update operation with append action.

Updated object
{
  agent_name: "sample_agent",
  agent_type: "support",
  associated_customers: ["customer1","customer2","customer3","customer4"]
}

Set

Adds one or more attributes and values to the specified key, value pair in the data store. If the attributes exist, then they are replaced with the new values. You can use the set action to update both top-level and nested attributes.

client.db.update(key, "set", attributes)
Notes:
  • Adds one or more attributes and values to the specified key, value pair in the data store. If the attributes exist, then they are replaced with the new values. You can use the set action to update both top-level and nested attributes.
  • The path should be of type string and should not be empty.
  • For a top-level attribute, the path refers to the name of the attribute in string format. For a nested attribute, the path refers to the attribute path from the top-level attribute in dot notation.

Example

Suppose, you have a timelog entry for an agent with agent ID as “key” and log information as "value" in the data store. The sample value would be as follows:

{
 "logs": {
    "contact_id:11233": {
      "Timelog":0,
      "Updated": "False"
    },
    "contact_id:12312": {
      "Timelog":300,
      "Updated": "True"
    }
 },
 "agent_name": "sample name"
}

An agent can use the Set action and update the TimeLog value for the first ticket without replacing the whole value object.

Updated object
{
 "logs": {
    "contact_id:11233": {
      "Timelog":500,
      "Updated": "True"
    },
    "contact_id:12312": {
      "Timelog":300,
      "Updated": "True"
    }
 },
 "agent_name": "sample name"
}

Remove

Removes one or more attributes of the specified key, value pair in the data store. You can use the remove action to remove both top-level and nested attributes.

client.db.update(key, "remove", attributes)
Notes:
  • The attributes field takes an array containing paths of the attributes which you want to remove.
  • The path should be of type string and should not be empty.
  • For a top-level attribute, the path refers to the name of the attribute in string format. For a nested attribute, the path refers to the attribute path from the top-level attribute in dot notation.

Example

Suppose, you have a timelog entry for an agent with agent ID as “key” and log information as "value" in the data store. The sample value would be as follows:

{
 "logs": {
    "contact_id:11233": {
      "Timelog":0,
      "Updated": "False"
    },
    "contact_id:12312": {
      "Timelog":300,
      "Updated": "True"
    }
 },
 "agent_name": "sample name"
}

An agent can use the Remove action to remove the ticket logs.

Updated object
{
 "logs": {},
 "agent_name": "sample name"
}

Delete

client.db.delete(key)

Used to delete stored data that is no longer needed.

Testing

For information on how to test an app that uses the Data Storage feature, see Test your App.

Data that the app needs to store is saved in the .fdk/localstore file in the app's root directory.

Errors

In case of failure, a status code is displayed along with a message to troubleshoot the issue.

Example
{
    "status":400,
    "message":"Key length should not exceed 30 characters"
}

The following table lists the supported status code.

Status codeDescription
400Is returned due to invalid input. For example, in the set request, if you provide an invalid input for value you may receive this status code.
401Is returned if you performed an unauthorized request.
404Is returned if the record is not found.
422Is returned if the server does not recognize your request. This may occur due to incorrect syntax.
429Is returned when the number of requests exceeds the threshold.
500Is returned if the server encounters an unexpected condition which prevents it from fulfilling the request.
502Is returned if the server cannot process the request due to request overload.