Data 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 conversation to an issue in JIRA, a relation between the conversation ID and issue ID is stored, which when retrieved displays the details of the relevant JIRA issue along with the conversation.

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. 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.

Note:
You need to have CLI v4.1.2 or higher in order to use this feature. For more information on how to get the latest version, click here.

Take a look at the Data Storage Freshdesk sample app for a demonstration of this feature. The same functionality is available in Freshcaller.

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. Ensure that the following conditions are met while performing the set operation:

  • The key should not be blank and its length should not exceed 30 characters.
  • The combined size of the key and value should not exceed 8 KB.
  • The value should be of type JSON and not blank or empty "{}".
  • The following values in the JSON Object will be converted to null - empty strings, NaN, "+/- Infinity".
app.js Copied Copy
1
2
3
4
5
6
7
8
9
client.db.set( "conversation:101", { "jiraIssueId": 15213 }).then ( function(data) { // success operation // "data" value is { "Created" : true } }, function(error) { // failure operation console.log(error) });

Note:
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

    Copied Copy
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    client.db.set( "conversation:101", { "jiraIssueId": 15213 }, {ttl: 60}) .done(function(data) { // success operation // "data" value is { "Created" : true } }) .fail(function(error_data) { // failure operation console.log(error_data.status) console.log(error_data.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

    Copied Copy
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    client.db.set( "conversation:101", { "jiraIssueId": 15213 }, {setIf: "exist"}) .done(function(data) { // success operation // "data" value is { "Created" : true } }) .fail(function(error_data) { // failure operation console.log(error_data.status) console.log(error_data.message) });
    EXPAND ↓

Take a look at the Advanced Data Storage Freshdesk sample app for a demonstration of this feature.

Retrieve

client.db.get(key) - Is used to retrieve stored data. If the retrieval is successful, the JSON value can be accessed using the data parameter in the .then function.

app.js

Copied Copy
1
2
3
4
5
6
7
8
9
client.db.get("conversation:101").then ( function(data) { // success operation // "data" value is { "jiraIssueId": 15213 } }, function(error) { console.log(error) // failure operation });
Update

client.db.update(key, action, attributes) - Updates the corresponding key value in the data store. UTF-8 characters are supported. Ensure that the following conditions are met while performing the update operation:

  • The key should not be blank and its length should not exceed 30 characters.
  • The attributes object should be of type JSON and not blank or empty "{}".
  • The following 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.

PARAMETER DESCRIPTION
Increment Adds a new value to the existing attribute value in the attributes object.
Append Appends a new value to the existing attribute value in the attributes object.
Set Adds one or more top-level or nested attributes and values to the key, value pair.
Remove Removes one or more attributes and values from the key, value pair.

  • Increment - client.db.update(key, "increment", attributes) - Adds the new value specified in the attributes object to the existing attribute value in the data store.
    • 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.
  • Note:
    1. The attributes field takes an object containing the attribute name and value which you want to increment.
    2. The increment action:
    a. Supports only number data type.
    b. Can be used on top-level attributes, not nested attributes.

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

    1
    2
    3
    4
    5
    { Name: "sample_user", Company: "sample_company", Interactions: 3 }

    Now, to update the interactions value every time the user interacts with the agent, you can use the update operation with increment action.

    app.js

    Copied Copy
    1
    2
    3
    4
    5
    6
    7
    8
    9
    client.db.update("user_id: 100", "increment", {"Interactions": 1}).then ( function(data) { // success operation // "data" value is { "Updated" : true} }, function(error) { // failure operation console.log(error) });
    Updated object
    1
    2
    3
    4
    5
    { Name: "sample_user", Company: "sample_company", Interactions: 4 }

  • Append - client.db.update(key, "append", attributes) - Appends the new value specified in the attributes object to the existing attribute value in the data store.
    • 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.
  • Note:
    1. The attributes field takes an object containing the attribute name and value which you want to append.
    2. The append action:
    a. Supports only array data type.
    b. Can be used on top-level attributes, not nested attributes.

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

    1
    2
    3
    4
    5
    { agent_name: "sample_agent", agent_type: "support", associated_users: ["user1","user2","user3"] }

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

    app.js

    Copied Copy
    1
    2
    3
    4
    5
    6
    7
    8
    9
    client.db.update("agent_id: 100","append", {associated_users: ["user4"]}).then ( function(data) { // success operation // "data" value is { "Updated" : true} }, function(error) { // failure operation console.log(error) });
    Updated object
    1
    2
    3
    4
    5
    { agent_name: "sample_agent", agent_type: "support", associated_users: ["user1","user2","user3","user4"] }

  • Set - client.db.update(key, "set", attributes) - 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.

  • Note:
    1. The attributes field takes a JSON object containing the path and value which you want to set.
    2. The path should be of type string and should not be empty.
    3. 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:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    { "logs": { "conversation_id:11233": { "Timelog":0, "Updated": "False" }, "conversation_id:12312": { "Timelog":300, "Updated": "True" } }, agent_name: "sample name" }
    EXPAND ↓

    Now, an agent can use the Set action and update the 'TimeLog' value for the first conversation without replacing the whole value object.

    app.js

    Copied Copy
    1
    2
    3
    4
    5
    6
    7
    client.db.update("agent_id: 1234762398","set", {"logs.conversation_id:11233.TimeLog": 500, "logs.conversation_id:11233.Updated": "True"}).then(function(data) { // success operation // "data" value is { "Updated" : true} }, function(error) { // failure operation console.log(error) });
    Updated object
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    { "logs": { "conversation_id:11233": { "Timelog":500, "Updated": "True" }, "conversation_id:12312": { "Timelog":300, "Updated": "True" } }, "agent_name": "sample name" }
    EXPAND ↓

  • Remove - client.db.update(key, "remove", attributes) - 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.

  • Note:
    1. The attributes field takes an array containing paths of the attributes which you want to remove.
    2. The path should be of type string and should not be empty.
    3. 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
    In the above example, to remove the conversation logs, view following code.

    app.js

    Copied Copy
    1
    2
    3
    4
    5
    6
    7
    client.db.update("agent_id: 1234762398","remove", ["logs.conversation_id:11233", "logs.conversation_id:12312"]).then(function(data) { // success operation // "data" value is { "Updated" : true} }, function(error) { // failure operation console.log(error) });
    Updated object
    1
    2
    3
    4
    { "logs": {}, "agent_name": "sample name" }
Delete

client.db.delete(key) - Is used to delete stored data that is no longer needed.

Note:
When an app is uninstalled, all the data stored by it will automatically be deleted and cannot be recovered.

app.js

Copied Copy
1
2
3
4
5
6
7
8
9
client.db.delete("conversation:101").then ( function(data) { // success operation // "data" value is { "Deleted" : true } }, function(error) { console.log(error); // failure operation });
Testing

For information on how to test an app that uses the Data Storage feature, see Test the 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.

An example of a status code and message is given.

1
2
3
4
{ "status":400, "message":"Key length should not exceed 30 characters" }

The following table lists all the supported status code.

STATUS CODE DESCRIPTION
400 Is 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.
401 Is returned if you performed an unauthorized request.
404 Is returned if the record is not found.
422 Is returned if the server does not recognize your request. This may occur due to incorrect syntax.
429 Is returned when the number of requests exceeds the threshold.
500 Is returned if the server encounters an unexpected condition which prevents it from fulfilling the request.
502 Is returned if the server cannot process the request due to request overload.