PubNub FunctionsStoring and Retrieving Data with the Key/Value Store

In this exercise, we'll illustrate using the globally replicated Key/Value Store (KV Store) to store and retrieve data.

Message data that passes through PubNub Functions may contain both constant / non-changing information, as well as computed and temporary information. Both types of data have the potential to be used as part of an expression to compute additional datasets, and/or to be conditionally chained and forwarded to other PubNub Functions for computation, output, logging, etc.

One way to save this information for future use is to store it into the built-in KV DB. That is what we'll learn about next.

 
Another way to save the data (via propagation) is to re-publish it to another channel for use by another block (AKA chaining). We'll cover that in the next lesson.

Let's add some logic to our Hello World app that will:

  • Generate a random number if it does not already exist.
  • Save it to the KV DB.
  • Retrieve it from the KV DB.
  • Augment the message with it via the randNum attribute.

To add this logic, go back into the Hello World Function and:

  1. export default (request) => {
        const db = require("kvstore");
    
        console.log("The message", request.message, "was published on", request.channels[0], "via", request.meta.clientip);
    
        request.message.hello = "world!"; // augment hello = world
        
        delete request.message.foo; // delete the foo attribute
    
        return db.get("randNum").then((randNum) => {
            // db.removeItem("randNum");
            
            if (!randNum) {
                randNum = Math.random();
                db.set("randNum", randNum)
                .catch((err) => {
                    console.log("An error occured saving the random number.", err);
                });
                console.log("randNum does not exist. Creating.");
            } else {
                console.log("randNum already exists:", randNum);
            }
        
            request.message.randNum = randNum;
            return request.ok();
        });
    };
  2. Click Save.
  3. Click Stop block.
  4. Click Start block.

    The block will go from stopped to running. You should see this status in the bottom log panel.

    Once running, let's once again test this functionality using the built-in test console.

  5. {
    	"foo":"bar"
    }
  6. Click Publish.

    On this initial publish attempt, you'll see the number is not yet created. So the block consequently generates it, then saves it via the set() method to the KV Store.

    Random Number Initial
     

    On the second publish attempt, you'll see your previously generated number once again. This is because it's being read via the get() method from the KV store.

    Random Number Second

Let's quickly step through the code to see what's happening.

const db = require("kvstore");

We subsequently call all DB-related methods off this db variable.

db.get("randNum").then(...);

This method (like all KV store methods) returns a promise which resolves to the value of the randNum key.

After pulling from the KV store (aka db), we check what's in the randNum variable. If it's null, we create a new value via Math.random(), and then use the db.set() method to asynchronously save the value to the distributed KV store.

if (!randNum) {
	randNum = Math.random();
	db.set("randNum", randNum).catch(...);
 
KV store values may have a maximum size of up to 32K per key.

Finally, we augment the randNum key and value to the request.message attribute, returning the request promise (by way of the randomResponse.)

//db.removeItem("randNum"); // for the sake of brevity, no then() block is used.

Uncomment this out to cause the removeItem() method to delete the randNum key from the KV DB, and to generate a new randNum value.

Because the KV store calls are asynchronous, the first time you run with this line uncommented, unless you wrap the inner logic around the removeItem()'s then() block, the value may still be read from the db successfully before it has time to be deleted.

If this is the case, just run it again to see the results.

In this example we set and get from a single Function. In the general case, the KV store has Subscribe-Key Level Scope. All PubNub Functions across a given Subscribe Key may share data amongst themselves via the KV DB.

So far, we've re-used values from a Block via the KV DB. Next, we'll learn how to use reuse values via chaining with the PubNub Publish and Fire APIs.