Managing State
Learn about how to manage the data.
About Manage State
A manage state implies that the parameters data are stored on a thread level, and this data can be accessed anytime after the first conversation.
Parameters are variables that were set during a conversation. However, whenever a session expires or resets, the variable's data is lost.
To ensure that the variable's data are intact, Khoros Flow uses a simple storage mechanism that can manage stateful data.
Count Code example
The example below shows how to store the data count.
async payload => {
// Get the current count, or 0
let count = await state.get('count') || 0
// Save the current count
await state.save('count', count + 1 )
// Show or speak the current count
return new Message(`Count is ${count}`)
}
Saving a Value
Use the state.save()
method to save key-value data. The code below is an example of saving a value.
async payload => {
await state.save('watched', {
season: 1,
episode: 2,
serie: 'game-of-thrones'
})
}
Fetching a Value
Use the get()
method to fetch a value using its key. The code below is an example of fetching the watched
key.
async payload => {
// Could be null if not found
const watched = await state.get('watched')
if(watched) {
// ....
}
}
Note
If no data exists
get()
returns anull
value.
Removing values
Use the remove()
method to remove a specific key value.
The code below shows how to remove the watched
key.
async payload => {
// Remove aa specific key
await state.remove('watched')
}
Use the clear() method to clear all the stored values.
The code below shows how to clear the conversation.
async payload => {
// Remove all data for this conversation
await state.clear()
}
Shared State Example
Let's say you have a simple quiz bot, and you want to let users submit their score to a leaderboard. You can use a collection to let users get a reference to the scores of other users.
In the below code action example, assume the user already has a score parameter.
In the Code Action below, you can:
- Create a score object with the score parameter value and the userId parameter to track the user’s score.
- Retrieve the scores from the leaderboard collection.
- If that parameter value is empty, create a new empty array.
- If the user already has a score on the leaderboard, we override the value with the new score. Otherwise, we add the new score.
- Save the shared state again in the leaderboard collection.
async payload => {
try {
console.log("payload", payload);
const score = {
score: payload.params.score[payload.params.score.length - 1].value,
userId: payload.user.userId ? payload.user.userId: payload.user.name
}
let scores = await state.get('scores', 'leaderboard');
if (scores === null) scores = [];
const existingScoreIndex = scores.findIndex((scoreInState) => scoreInState.userId === score.userId);
if (existingScoreIndex !== -1) {
scores[existingScoreIndex].score = score.score;
} else {
scores.push(score);
}
console.log("Storing new scores to state", scores);
await state.save('scores', scores, 'leaderboard');
} catch(err) {
console.error(err)
}
}
In another Code Action, set the parameters to display the full leaderboard or the user’s position within a reply:
async payload => {
try {
let scores = await state.get('scores', 'leaderboard');
console.log("scores", scores);
let fullLeaderboardObj = null;
let leaderboardPlayerResult = "You are not on the leaderboard yet. Answer the quiz questions to get a score on the leaderboard.";
if (scores?.length > 0) {
const sortedScores = scores.sort((a, b) => b.score - a.score);
console.log("sortedScores", sortedScores);
const userId = payload.user.userId ? payload.user.userId : payload.user.name;
let playerFound = false;
let playerRank;
let playerScore;
fullLeaderboard = "";
for (let i = 0; i < sortedScores.length; i++) {
if (sortedScores[i].userId === userId) {
playerFound = true;
playerRank = i + 1;
playerScore = sortedScores[i].score;
}
fullLeaderboard += `${sortedScores[i].userId} - ${sortedScores[i].score} points\n\n`;
}
console.log("fullLeaderboard", fullLeaderboard);
fullLeaderboardObj = [{
value: fullLeaderboard,
match: fullLeaderboard
}]
leaderboardPlayerResult = "";
if (playerFound) leaderboardPlayerResult = `You are on rank ${playerRank} of all ${sortedScores.length} players on the leaderboard with ${playerScore} points.`
}
console.log("leaderboardPlayerResult", leaderboardPlayerResult);
return {
params: {
...payload.params,
leaderboardPlayerResult: [{
value: leaderboardPlayerResult,
match: leaderboardPlayerResult
}],
fullLeaderboard: fullLeaderboardObj
}
}
} catch(err) {
console.error(err)
}
}
Finally, reset the full leaderboard with the state.clear()
function and collectionName
.
async payload => {
try {
await state.clear("leaderboard");
} catch(err) {
console.error(err)
}
}
Reference
state.save(key, value)
Save data in state
Returns: Promise
- Promise that resolves with the value being stored
Properties
Name | Type | Description |
---|---|---|
key | string | Key used to save data |
value | object | Either an object, array, or string to store |
collectionName | string | Optional. Custom collection name to share state across multiple users |
state.get(key)
Retrieve data from the state by key.
Returns: Promise
- Promise that resolved with the value being stored or null
if the key does not exist.
Properties
Name | Type | Description |
---|---|---|
key | string | Key used to find the data |
collectionName | string | Optional. Custom collection name to find shared state from other users |
state.remove(key)
Remove data from the state by key.
Returns: Promise
- Resolves with the key of the deleted data
Properties
Name | Type | Description |
---|---|---|
key | string | Key of the data to delete |
collectionName | string | Optional. Name of custom collection to delete |
state.clear()
Clear all data from the state.
Returns: undefined
Updated 22 days ago