Storing Documents in HyperDex with Node.JS

HyperDex recently added support for storing and querying schema-less JSON documents. This is a big step for the next-generation database that pioneered many new techniques for efficient, consistent, fault-tolerant data storage -- it is not only a fast key-value store, but also a document store now. You can store JSON documents and query them by their properties, nested arbitrarily.

The latest HyperDex release also sports Node.js bindings. Combined, the pair make a powerful combination that's easy to work with.

Let's see how these new features work in practice. To get started, you may need to download HyperDex and follow the easy installation instructions for your platform. Once you have HyperDex installed, you can quickly setup a running cluster by running the coordinator:

$ hyperdex coordinator -f -l 127.0.0.1 -p 1982

followed by the storage daemon to store data:

$ hyperdex daemon -f --listen=127.0.0.1 --listen-port=2012 \
                     --coordinator=127.0.0.1 --coordinator-port=1982 \
                     --data=/path/to/data

We now have a HyperDex cluster ready to serve our data. Finally, let's create a new space on the cluster. Spaces in HyperDex are like "tables" in traditional SQL stores, or "collections" in MongoDB. In this example, let's create a space suitable for storing social network profiles.

$ hyperdex add-space << EOF
space profiles
key username
attribute
document profile
EOF

Storing Data with Node

Consider a social networking application that stores each user's profile as a document in HyperDex. Users which provide very little information to the social network will have a relatively sparse profile. The bare minimum profile could look like this:

{"name": "John Smith"}

You can store this profile in HyperDex by connecting to the cluster and simply "putting" the user's profile. Here's a sample program that does just that:

hyperdex_client = require('./hyperdex-client')
c = new hyperdex_client.Client('127.0.0.1', 1982)
c.put('profiles', 'jsmith1', {profile: {name: 'John Smith'}},
        function(err, success) {
            if (err) { /*an error ocurred; look at err for details*/}
            console.log("The \"put\" operation returned: " + success);
        });

If you paste the above code into a file, and run it with node demo.js, you'll see the following:

$ node demo.js
The "put" operation returned: true

The "put" operation completes and then the program exits. True to well-accepted Node practice, HyperDex hooks into the Node event loop, ensuring that operations are performed asynchronously. This enables you to do other things while waiting for the HyperDex operations to complete.

Working with Documents

Let's flesh out our social networking example some more. Consider a user named Jane Doe who has fleshed out his profile some more, and has established a friendship with John Smith. You could encode these relationships with the following code:

hyperdex_client = require('./hyperdex-client')
c = new hyperdex_client.Client('127.0.0.1', 1982)
c.put('profiles', 'jd', {profile: {name: "Jane Doe",
                                   www: "http://example.org",
                                   email: "doe@example.org",
                                   friends: ["John Smith"]}},
        function(err, success) {
            if (err) { /*an error ocurred; look at err for details*/}
            console.log("The \"put\" operation returned: " + success);
        });

The profile for Jane Doe looks just like a Javascript object because it is a Javascript object.

Searching over documents is almost as easy. For example, to retrieve the objects for all people named Jane Doe, you can do a search on profile.name to retrieve all such objects:

hyperdex_client = require('./hyperdex-client')
c = new hyperdex_client.Client('127.0.0.1', 1982)
c.search('profiles', {profile: {name: "Jane Doe"}},
        function(err, obj, done) {
            if (err) { /*an error ocurred; look at err for details*/}
            if (obj !== undefined) { console.log("retrieved %j", obj); }
            if (done) { console.log("the search is done"); }
        });

Here's what will happen when you run this script:

$ node demo.js
retrieved {"username":[106,100],"profile":{"name":"Jane Doe","www":"http://example.org","email":"doe@example.org","friends":["John Smith"]}}
the search is done

The callback will be called once for each object, and then once at the end of the search. You can see that the object returned is the one that we've stored.

Further Reading

We've only scratched the surface of Javascript support in HyperDex. For more information consult the following resources:

  • HyperDex Installation Instructions: Don't yet have HyperDex? Follow these simple instructions to get started in minutes.
  • Documentation on Documents: A quick tutorial that shows how use documents from Python. It also shows how to take advantage of HyperDex's indices to make searches more efficient.
  • Node.js API Docs: It's the most comprehensive guide to working with HyperDex from Node.js.
Share on Linkedin
Share on Reddit
comments powered by Disqus