A Little Riak Book for LFE

Datatypes

A new feature in Riak 2.0 are datatypes. Rather than the opaque values of days past, these new additions allow a user to define the type of values that are accepted under a given bucket type. In addition to the benefits listed in the previous chapter of automatic conflict resolution, you also interact with datatypes in a different way.

In normal Riak operations, as we've seen, you put a value with a given key into a type/bucket object. If you wanted to store a map, say, as a JSON object representing a person, you would put the entire object with every field/value as an operation.

curl -XPOST "$RIAK/types/json/buckets/people/keys/joe" \
  -H "Content-Type:application/json"
  -d '{"name_register":"Joe", "pets_set":["cat"]}'

But if you wanted to add a fish as a pet, you'd have to replace the entire object.

curl -XPOST "$RIAK/types/json/buckets/people/keys/joe" \
  -H "Content-Type:application/json"
  -d '{"name_register":"Joe", "pets_set":["cat", "fish"]}'

As we saw in the previous chapter, this runs the risk of conflicting, thus creating a sibling.

{"name_register":"Joe", "pets_set":["cat"]}
{"name_register":"Joe", "pets_set":["cat", "fish"]}

But if we used a map, we'd instead issue only updates to create a map. So, assume that the bucket type map is of a map datatype (we'll see how operators can assign datatypes to bucket types in the next chapter). This command will insert a map object with two fields (name_register and pets_set).

curl -XPOST "$RIAK/types/map/buckets/people/keys/joe" \
  -H "Content-Type:application/json"
  -d '{
    "update": {
      "name_register": "Joe"
      "pets_set": {
        "add_all": "cat"
      }
    }
  }'

Next, we want to update the pets_set contained within joe's map. Rather than set Joe's name and his pet cat, we only need to inform the object of the change. Namely, that we want to add a fish to his pets_set.

curl -XPOST "$RIAK/types/map/buckets/people/keys/joe" \
  -H "Content-Type:application/json"
  -d '{
    "update": {
      "pets_set": {
        "add": "fish"
      }
    }
  }'

This has a few benefits. Firstly, we don't need to send duplicate data. Second, it doesn't matter what order the two requests happen in, the outcome will be the same. Third, because the operations are CmRDTs, there is no possibility of a datatype returning siblings, making your client code that much easier.

As we've noted before, there are four Riak datatypes: map, set, counter, flag. The object type is set as a bucket type property. However, when populating a map, as we've seen, you must suffix the field name with the datatype that you wish to store: *_map, *_set, *_counter, *_flag. For plain string values, there's a special *_register datatype suffix.

You can read more about datatypes in the docs.