Creating Objects in Riak KV
Writes in Riak KV (storing or modifying objects) are like HTTP PUT
requests. Here is the basic form of writes:
PUT /types/<type>/buckets/<bucket>/keys/<key>
# If you're using HTTP to interact with Riak, you can also use POST
In the example above, our read was unsuccessful because our Riak cluster
is currently empty. Let’s change that by storing an object containing
information about a dog named Rufus. We’ll store that object in the
location described above, i.e. in the key rufus
in the bucket dogs
,
which bears the animals
bucket type.
The object we’re storing will be very simple, just a basic text snippet of something that Rufus might say. Let’s build the object and then store it.
String quote = "WOOF!";
Namespace bucket = new Namespace("animals", "dogs");
Location rufusLocation = new Location(bucket, "rufus");
RiakObject rufusObject = new RiakObject()
.setContentType("text/plain")
.setValue(BinaryValue.create(quote));
StoreValue storeOp = new StoreValue.Builder(rufusObject)
.withLocation(rufusLocation)
.build();
client.execute(storeOp);
bucket = client.bucket_type('animals').bucket('dogs')
obj = Riak::RObject.new(bucket, 'rufus')
obj.content_type = 'text/plain'
obj.data = 'WOOF!'
obj.store
$response = (new \Riak\Riak\Command\Builder\StoreObject($riak))
->buildLocation('rufus', 'users', 'animals')
->buildObject('WOOF!', 'text/plain')
->build()
->execute();
bucket = client.bucket_type('animals').bucket('dogs')
obj = RiakObject(client, bucket, 'rufus')
obj.content_type = 'text/plain'
obj.data = 'WOOF!'
obj.store()
var id = new RiakObjectId("animals", "dogs", "rufus")
var obj = new RiakObject(id, "WOOF!", "text/plain");
var result = client.Put(obj);
var riakObj = new Riak.Commands.KV.RiakObject();
riakObj.setContentType('text/plain');
riakObj.setValue('WOOF!');
client.storeValue({
bucketType: 'animals', bucket: 'dogs', key: 'rufus',
value: riakObj
}, function (err, rslt) {
if (err) {
throw new Error(err);
}
});
obj := &riak.Object{
ContentType: "text/plain",
Charset: "utf-8",
ContentEncoding: "utf-8",
Value: []byte("WOOF!"),
}
cmd, err := riak.NewStoreValueCommandBuilder().
WithBucketType("animals").
WithBucket("dogs").
WithKey("rufus").
WithContent(obj).
Build()
if err != nil {
fmt.Println(err.Error())
return
}
if err := cluster.Execute(cmd); err != nil {
fmt.Println(err.Error())
return
}
svc := cmd.(*riak.StoreValueCommand)
rsp := svc.Response
Notice that we specified both a value for the object, i.e. WOOF!
, and
a content type, text/plain
. See content types for more information.
Now, run the same read operation in Reading Objects. If the write operation was successful, you should be able to successfully read the object. Your Riak cluster is no longer empty!
Store an Object
Your application will often have its own method of generating the keys for its data, e.g. on the basis of timestamps. If so, storing that data is easy. The basic request looks like this.
PUT /types/TYPE/buckets/BUCKET/keys/KEY
# If you're using HTTP, POST can be used instead of PUT. The only
# difference between POST and PUT is that you should POST in cases where
# you want Riak to auto-generate a key. More on this can be found in the
# examples below.
There is no need to intentionally create buckets in Riak. They pop into
existence when keys are added to them, and disappear when all keys have
been removed from them. If you don’t specify a bucket’s type, the type
default
will be applied.
Write Parameters
Similar to how read requests support the r
query parameter, write
requests also support the following parameters:
Parameter | Default | Description |
---|---|---|
w |
quorum |
How many replicas to write to before returning a successful response |
pw |
0 |
How many primary vnodes must respond for a write to be deemed successful |
dw |
quorum |
How many replicas to commit to durable storage before returning a successful response |
returnbody |
false |
Whether to return the contents of the stored object |
Here is an example of storing an object (another brief text snippet)
under the key viper
in the bucket dodge
, which bears the type
cars
, with w
set to 3
:
Location viperKey = new Location(new Namespace("cars", "dodge"), "viper");
BinaryValue text = BinaryValue.create("vroom");
RiakObject obj = new RiakObject()
.setContentType("text/plain")
.setValue(text);
StoreValue store = new StoreValue.Builder(myKey, obj)
.withOption(StoreOption.W, new Quorum(3))
.build();
client.execute(store);
bucket = client.bucket_type('cars').bucket('dodge')
obj = Riak::RObject.new(bucket, 'viper')
obj.content_type = 'text/plain'
obj.raw_data = 'vroom'
obj.store(w: 3)
(new \Riak\Riak\Command\Builder\StoreObject($riak))
->buildLocation('viper', 'dodge', 'cars')
->buildObject('vroom', 'text/plain')
->withParameter('w', 3)
->build()
->execute();
bucket = client.bucket_type('cars').bucket('dodge')
obj = RiakObject(client, bucket, 'viper')
obj.content_type = 'text/plain'
obj.data = 'vroom'
obj.store(w=3)
var id = new RiakObjectId("cars", "dodge", "viper");
var obj = new RiakObject(id, "vroom", "text/plain");
var options = new RiakPutOptions();
options.SetW(new Quorum(3));
var result = client.Put(obj, options);
var riakObj = new Riak.Commands.KV.RiakObject();
riakObj.setContentType('text/plain');
riakObj.setValue('vroom');
var options = {
bucketType: 'cars', bucket: 'dodge', key: 'viper',
w: 3, value: riakObj
};
client.storeValue(options, function (err, rslt) {
if (err) {
throw new Error(err);
}
});
Object = riakc_obj:new({<<"cars">>, <<"dodge">>},
<<"viper">>,
<<"vroom">>,
<<"text/plain">>,
[{w, 3}]).
riakc_pb_socket:put(Pid, Object).
obj := &riak.Object{
ContentType: "text/plain",
Charset: "utf-8",
ContentEncoding: "utf-8",
Value: []byte("vroom"),
}
cmd, err := riak.NewStoreValueCommandBuilder().
WithBucketType("cars").
WithBucket("dodge").
WithKey("viper").
WithW(3).
WithContent(obj).
Build()
if err != nil {
fmt.Println(err.Error())
return
}
if err := cluster.Execute(cmd); err != nil {
fmt.Println(err.Error())
return
}
curl -XPUT \
-H "Content-Type: text/plain" \
-d "vroom" \
http://localhost:8098/types/cars/buckets/dodge/keys/viper?w=3
Normal HTTP status codes (responses will vary for client libraries):
200 OK
204 No Content
300 Multiple Choices
Return Body
If returnbody
is set to true
, any of the response headers expected
from a read request may be present. Like a GET
request, 300 Multiple
Choices
may be returned if siblings existed or were created as part of
the operation, and the response can be dealt with similarly.
Let’s give it a shot, using the same object from above:
Location viperKey = new Location(new Namespace("cars", "dodge"), "viper");
BinaryValue text = BinaryValue.create("vroom");
RiakObject obj = new RiakObject()
.setContentType("text/plain")
.setValue(text);
StoreValue store = new StoreValue.Builder(myKey, obj)
.withOption(StoreOption.W, new Quorum(3))
.withOption(StoreOption.RETURN_BODY, true)
.build();
client.execute(store);
bucket = client.bucket_type('cars').bucket('dodge')
obj = Riak::RObject.new(bucket, 'viper')
obj.content_type = 'text/plain'
obj.raw_data = 'vroom'
obj.store(w: 3, returnbody: true)
(new \Riak\Riak\Command\Builder\StoreObject($riak))
->buildLocation('viper', 'dodge', 'cars')
->buildObject('vroom', 'text/plain')
->withParameter('w', 3)
->withParameter('returnbody', 'true')
->build()
->execute();
bucket = client.bucket_type('cars').bucket('dodge')
obj = RiakObject(client, bucket, 'viper')
obj.content_type = 'text/plain'
obj.data = 'vroom'
obj.store(w=3, return_body=True)
var id = new RiakObjectId("cars", "dodge", "viper");
var obj = new RiakObject(id, "vroom", "text/plain");
var options = new RiakPutOptions();
options.SetW(new Quorum(3));
options.SetReturnBody(true);
var result = client.Put(obj, options);
var riakObj = new Riak.Commands.KV.RiakObject();
riakObj.setContentType('text/plain');
riakObj.setValue('vroom');
var options = {
bucketType: 'cars', bucket: 'dodge', key: 'viper',
w: 3, returnBody: true, value: riakObj
};
client.storeValue(options, function (err, rslt) {
if (err) {
throw new Error(err);
}
var riakObj = rslt.values.shift();
var viper = riakObj.value;
logger.info("dodge viper: %s", viper.toString('utf8'));
});
Object = riakc_obj:new({<<"cars">>, <<"dodge">>},
<<"viper">>,
<<"vroom">>,
<<"text/plain">>).
riakc_pb_socket:put(Pid, Object, [return_body]).
obj := &riak.Object{
ContentType: "text/plain",
Charset: "utf-8",
ContentEncoding: "utf-8",
Value: []byte("vroom"),
}
cmd, err := riak.NewStoreValueCommandBuilder().
WithBucketType("cars").
WithBucket("dodge").
WithKey("viper").
WithW(3).
WithContent(obj).
WithReturnBody(true).
Build()
if err != nil {
fmt.Println(err.Error())
return
}
if err := cluster.Execute(cmd); err != nil {
fmt.Println(err.Error())
return
}
curl -XPUT \
-H "Content-Type: text/plain" \
-d "vroom" \
http://localhost:8098/types/cars/buckets/dodge/keys/viper?w=3&returnbody=true
Store a New Object and Assign a Random Key
If your application would rather leave key-generation up to Riak, issue
a POST
request to the bucket URL instead of a PUT to a bucket/key
pair:
POST /types/TYPE/buckets/BUCKET/keys
If you don’t pass Riak a key
name after the bucket, it will know to
create one for you.
Supported headers are the same as for bucket/key write requests, though
X-Riak-Vclock
will never be relevant for these POST requests.
Supported query parameters are also the same as for bucket/key PUT
requests.
Normal status codes:
201 Created
This command will store an object in the bucket random_user_keys
,
which bears the bucket type users
.
Namespace locationWithoutKey = new Namespace("users", "random_user_keys");
BinaryValue text = BinaryValue.create("{'user':'data'}");
RiakObject obj = new RiakObject()
.setContentType("application/json")
.setValue(text);
StoreValue store = new StoreValue.Builder(locationWithoutKey, obj)
.build();
String key = client.execute(store).getLocation().getKeyAsString();
// The Java client will assign a random key along the following lines:
"ZPFF18PUqGW9efVou7EHhfE6h8a"
bucket = client.bucket_type('users').bucket('random_user_keys')
obj = Riak::RObject.new(bucket)
obj.content_type = 'application/json'
obj.raw_data = '{"user":"data"}'
obj.store
# The client will assign a key like the following:
obj.key
"GB8fW6DDZtXogK19OLmaJf247DN"
$response = (new \Riak\Riak\Command\Builder\StoreObject($riak))
->buildBucket('random_user_keys', 'users')
->buildJsonObject(['user'=>'data'])
->build()
->execute();
echo $response->getLocation()->getKey(); // GB8fW6DDZtXogK19OLmaJf247DN
bucket = client.bucket_type('users').bucket('random_user_keys')
obj = RiakObject(client, bucket)
obj.content_type = 'application/json'
obj.data = '{"user":"data"}'
obj.store()
obj.key
# The Python client will assign a random key along the following lines:
'ZPFF18PUqGW9efVou7EHhfE6h8a'
var id = new RiakObjectId("users", "random_user_keys", null);
var obj = new RiakObject(id, @"{'user':'data'}",
RiakConstants.ContentTypes.ApplicationJson);
var rslt = client.Put(obj);
Debug.WriteLine(format: "Generated key: {0}", args: rslt.Value.Key);
// The .NET client will output a random key similar to this:
// Generated key: DWDsnpYSqOU363c0Bqe8hCwAM7Q
var user = {
user: 'data'
};
var options = {
bucketType: 'users', bucket: 'random_user_keys',
returnBody: true, value: user
};
client.storeValue(options, function (err, rslt) {
if (err) {
throw new Error(err);
}
var riakObj = rslt.values.shift();
var generatedKey = riakObj.getKey();
logger.info("Generated key: %s", generatedKey);
});
// The Node.js client will output a random key similar to this:
// info: Generated key: VBAMoX0OOucymVCxeQEYzLzzAh2
Object = riakc_obj:new({<<"users">>, <<"random_user_keys">>}, undefined, <<"{'user':'data'}">>, <<"application/json">>).
riakc_pb_socket:put(Pid, Object).
%% The key can be retrieved from the output of the above call.
%% It will look something like this:
{ok,{riakc_obj,{<<"users">>,<<"random_user_keys">>},
<<"EZ7pp4bpdfpZw0fPUdTUafveQjO">>,undefined,[],undefined,
undefined}}
obj := &riak.Object{
ContentType: "application/json",
Charset: "utf-8",
ContentEncoding: "utf-8",
Value: []byte("{'user':'data'}"),
}
cmd, err := riak.NewStoreValueCommandBuilder().
WithBucketType("users").
WithBucket("random_user_keys").
WithContent(obj).
Build()
if err != nil {
fmt.Println(err.Error())
return
}
if err := cluster.Execute(cmd); err != nil {
fmt.Println(err.Error())
return
}
svc := cmd.(*riak.StoreValueCommand)
rsp := svc.Response
fmt.Printf("Generated key: %v\n", rsp.GeneratedKey)
// Output:
// Generated key: QSHkZjFdWwfrxtKl3wtUhL2gz7N
curl -i -XPOST \
-H "Content-Type: text/plain" \
-d "this is a test" \
http://localhost:8098/types/users/buckets/random_user_keys/keys
# In the output, you should see a Location header that will give you the
# location of the object in Riak, with the key at the end:
Location: /buckets/test/keys/G7FYUXtTsEdru4NP32eijMIRK3o