{"id":24842887,"url":"https://github.com/goncalotomas/riakc","last_synced_at":"2025-03-26T06:43:20.528Z","repository":{"id":57543887,"uuid":"117604323","full_name":"goncalotomas/riakc","owner":"goncalotomas","description":"A Riak Erlang Client that works with modern Erlang","archived":false,"fork":false,"pushed_at":"2018-08-29T14:38:30.000Z","size":93,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-01T00:44:33.989Z","etag":null,"topics":["client","erlang","riak"],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goncalotomas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-15T22:57:41.000Z","updated_at":"2018-09-11T13:13:08.000Z","dependencies_parsed_at":"2022-08-27T19:10:21.454Z","dependency_job_id":null,"html_url":"https://github.com/goncalotomas/riakc","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goncalotomas%2Friakc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goncalotomas%2Friakc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goncalotomas%2Friakc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goncalotomas%2Friakc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goncalotomas","download_url":"https://codeload.github.com/goncalotomas/riakc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245605709,"owners_count":20643030,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client","erlang","riak"],"created_at":"2025-01-31T08:19:07.914Z","updated_at":"2025-03-26T06:43:20.511Z","avatar_url":"https://github.com/goncalotomas.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Riak Erlang Client [![Build Status](https://travis-ci.org/goncalotomas/riakc.svg?branch=master)](https://travis-ci.org/goncalotomas/riakc)\n\nThis is a fork from Basho's [riak-erlang-client](http://github.com/basho/riak-erlang-client). Updates to that repository are too slow and I wanted to keep a modified version that works with Erlang R16 up to the latest (currently R21). Feel free to improve the existing codebase in any way, although I did not intend for this repository to deviate much from the original.\n\nOld README.md:\n============\n\nThis document assumes that you have already started your Riak cluster. For instructions on that prerequisite, refer to the [setup][kv_setup] guide in the [Basho Docs][basho_docs]. You can also view the Riak Erlang Client EDocs [here][erlang_client_edocs].\n\nThis document assumes that you have already started your Riak cluster.  For instructions on that prerequisite, refer to [Installation and Setup](https://wiki.basho.com/Installation-and-Setup.html) in the [Riak Wiki](https://wiki.basho.com). You can also view the Riak Erlang Client EDocs [here](http://basho.github.com/riak-erlang-client/).\n\nDependencies\n============\n\nTo build the riak-erlang-client you will need Erlang OTP R16B03-1 or later, and Git.\n\nDebian\n------\n\nOn a Debian based system (Debian, Ubuntu, ...) you will need to make sure that certain packages are installed:\n\n    # apt-get install erlang-parsetools erlang-dev erlang-syntax-tools\n\n\nInstalling\n==========\n\n        $ git clone git://github.com/basho/riak-erlang-client.git\n        $ cd riak-erlang-client\n        $ make\n\n\nConnecting\n==========\n\nTo talk to riak, all you need is an Erlang node with the riak-erlang-client library (riakc) in its code path.\n\n        $ erl -pa $PATH_TO_RIAKC/ebin $PATH_TO_RIAKC/deps/*/ebin\n\n\nYou'll know you've done this correctly if you can execute the following commands and get a path to a beam file, instead of the atom 'non_existing':\n\n       1\u003e code:which(riakc_pb_socket).\n       \".../riak-erlang-client/ebin/riakc_pb_socket.beam\"\n\n\nOnce you have your node running, pass your Riak server nodename to `riakc_pb_socket:start_link/2` to connect and get a client. This can be as simple as:\n\n       1\u003e {ok, Pid} = riakc_pb_socket:start_link(\"127.0.0.1\", 8087).\n       {ok,\u003c0.56.0\u003e}\n\nVerify connectivity with the server using `ping/1`.\n\n       2\u003e riakc_pb_socket:ping(Pid).\n       pong\n\n\nStoring New Data\n================\n\nEach bit of data in Riak is stored in a \"bucket\" at a \"key\" that is unique to that bucket. The bucket is intended as an organizational aid, for example to help segregate data by type, but Riak doesn't care what values it stores, so choose whatever scheme suits you. Buckets, keys and values are all binaries.\n\nBefore storing your data, you must wrap it in a riakc_obj:\n\n    3\u003e Object = riakc_obj:new(\u003c\u003c\"groceries\"\u003e\u003e, \u003c\u003c\"mine\"\u003e\u003e, \u003c\u003c\"eggs \u0026 bacon\"\u003e\u003e).\n    {riakc_obj,\u003c\u003c\"groceries\"\u003e\u003e,\u003c\u003c\"mine\"\u003e\u003e,undefined,undefined,\n    {dict,0,16,16,8,80,48,\n    {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],...},\n    {{[],[],[],[],[],[],[],[],[],[],[],[],[],...}}},\n    \u003c\u003c\"eggs \u0026 bacon\"\u003e\u003e}\n\nIf you want to have the server generate you a key (similar to the REST API) pass the atom `undefined` as the second parameter to new().\n\nThe Object refers to a key `\u003c\u003c\"mine\"\u003e\u003e` in a bucket named `\u003c\u003c\"groceries\"\u003e\u003e` with the value `\u003c\u003c\"eggs \u0026 bacon\"\u003e\u003e`. Using the client you opened earlier, store the object:\n\n    5\u003e riakc_pb_socket:put(Pid, Object).\n    ok\n\nIf the return value of the last command was anything but the atom `ok` (or `{ok, Key}` when you instruct the server to generate the key), then the store failed. The return value may give you a clue as to why the store failed, but check the Troubleshooting section below if not.\n\nThe object is now stored in Riak. `put/2` uses default parameters for storing the object. There is also a `put/3` call that takes a proplist of options.\n\n\u003ctable border=\"1\"\u003e\n    \u003cth\u003eOption\u003c/th\u003e\n    \u003cth\u003eDescription\u003c/th\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003ccode\u003e{w, W}\u003c/code\u003e\u003c/td\u003e\n        \u003ctd\u003ethe minimum number of nodes that must respond with success for the write to be considered successful. The default is currently set on the server to quorum.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003ccode\u003e{dw, DW}\u003c/code\u003e\u003c/td\u003e\n        \u003ctd\u003e  the minimum number of nodes that must respond with success * *after durably storing* the object for the write to be considered successful. The default is currently set on the server to quorum.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003ccode\u003ereturn_body\u003c/code\u003e\u003c/td\u003e\n        \u003ctd\u003eimmediately do a get after the put and return a riakc_obj.\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\nSee [Default Bucket Properties][kv_configuring_reference_bucket_properties] for more details.\n\n\n    6\u003e AnotherObject = riakc_obj:new(\u003c\u003c\"my bucket\"\u003e\u003e, \u003c\u003c\"my key\"\u003e\u003e, \u003c\u003c\"my binary data\"\u003e\u003e).\n    7\u003e riakc_pb_socket:put(Pid, AnotherObject, [{w, 2}, {dw, 1}, return_body]).\n    {ok,{riakc_obj,\u003c\u003c\"my bucket\"\u003e\u003e,\u003c\u003c\"my key\"\u003e\u003e,\n    \u003c\u003c107,206,97,96,96,96,206,96,202,5,82,44,140,62,169,115,\n    50,152,18,25,243,88,25,...\u003e\u003e,\n    [{{dict,2,16,16,8,80,48,\n    {[],[],[],[],[],[],[],[],[],[],[],[],...},\n    {{[],[],[],[],[],[],[],[],[],[],...}}},\n    \u003c\u003c\"my binary data\"\u003e\u003e}],\n    {dict,0,16,16,8,80,48,\n    {[],[],[],[],[],[],[],[],[],[],[],[],[],...},\n    {{[],[],[],[],[],[],[],[],[],[],[],...}}},\n    undefined}}\n\nWould make sure at least two nodes responded successfully to the put and at least one node has durably stored the value and an updated object is returned.\n\nSee [this page][kv_learn_glossary_quorum] for more information about W and DW values.\n\nFetching Data\n=============\n\nAt some point you'll want that data back. Using the same bucket and key you used before:\n\n    8\u003e {ok, O} = riakc_pb_socket:get(Pid, \u003c\u003c\"groceries\"\u003e\u003e, \u003c\u003c\"mine\"\u003e\u003e).\n    {ok,{riakc_obj,\u003c\u003c\"groceries\"\u003e\u003e,\u003c\u003c\"mine\"\u003e\u003e,\n    \u003c\u003c107,206,97,96,96,96,204,96,202,5,82,44,12,143,167,115,\n    103,48,37,50,230,177,50,...\u003e\u003e,\n    [{{dict,2,16,16,8,80,48,\n    {[],[],[],[],[],[],[],[],[],[],[],[],...},\n    {{[],[],[],[],[],[],[],[],[],[],...}}},\n    \u003c\u003c\"eggs \u0026 bacon\"\u003e\u003e}],\n    {dict,0,16,16,8,80,48,\n    {[],[],[],[],[],[],[],[],[],[],[],[],[],...},\n    {{[],[],[],[],[],[],[],[],[],[],[],...}}},\n    undefined}}\n\nLike `put/3`, there is a `get/4` function that takes options.\n\n\u003ctable border=\"1\"\u003e\n    \u003cth\u003eOption\u003c/th\u003e\n    \u003cth\u003eDescription\u003c/th\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003ccode\u003e{r, R}\u003c/code\u003e\u003c/td\u003e\n        \u003ctd\u003ethe minimum number of nodes that must respond with success for the read to be considered successful\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\nIf the data was originally stored using the distributed erlang client (riak_client), the server will automatically term_to_binary/1 the value before sending it, with the content type set to application/x-erlang-binary (replacing any user-set value).  The application is responsible for calling binary_to_term to access the content and calling term_to_binary when modifying it.\n\nModifying Data\n==============\n\nSay you had the \"grocery list\" from the examples above, reminding you to get `\u003c\u003c\"eggs \u0026 bacon\"\u003e\u003e`, and you want to add `\u003c\u003c\"milk\"\u003e\u003e` to it. The easiest way is:\n\n    9\u003e {ok, Oa} = riakc_pb_socket:get(Pid, \u003c\u003c\"groceries\"\u003e\u003e, \u003c\u003c\"mine\"\u003e\u003e).\n    ...\n    10\u003e Ob = riakc_obj:update_value(Oa, \u003c\u003c\"milk, \", (riakc_obj:get_value(Oa))/binary\u003e\u003e).\n    11\u003e {ok, Oc} = riakc_pb_socket:put(Pid, Ob, [return_body]).\n    {ok,{riakc_obj,\u003c\u003c\"groceries\"\u003e\u003e,\u003c\u003c\"mine\"\u003e\u003e,\n    \u003c\u003c107,206,97,96,96,96,206,96,202,5,82,44,12,143,167,115,\n    103,48,37,50,230,177,50,...\u003e\u003e,\n    [{{dict,2,16,16,8,80,48,\n    {[],[],[],[],[],[],[],[],[],[],[],[],...},\n    {{[],[],[],[],[],[],[],[],[],[],...}}},\n    \u003c\u003c\"milk, eggs \u0026 bacon\"\u003e\u003e}],\n    {dict,0,16,16,8,80,48,\n    {[],[],[],[],[],[],[],[],[],[],[],[],[],...},\n    {{[],[],[],[],[],[],[],[],[],[],[],...}}},\n    undefined}}\n\n\nThat is, fetch the object from Riak, modify its value with `riakc_obj:update_value/2`, then store the modified object back in Riak. You can get your updated object to convince yourself that your list is updated:\n\nDeleting Data\n=============\n\nThrowing away data is quick and simple: just use the `delete/3` function.\n\n    10\u003e riakc_pb_socket:delete(Pid, \u003c\u003c\"groceries\"\u003e\u003e, \u003c\u003c\"mine\"\u003e\u003e).\n    ok\n\nAs with get and put, delete can also take options\n\n\u003ctable border=\"1\"\u003e\n    \u003cth\u003eOption\u003c/th\u003e\n    \u003cth\u003eDescription\u003c/th\u003e\n    \u003ctr\u003e\n        \u003ctd\u003e\u003ccode\u003e{rw, RW}\u003c/code\u003e\u003c/td\u003e\n        \u003ctd\u003ethe number of nodes to wait for responses from\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\nIssuing a delete for an object that does not exist returns just returns ok.\n\nEncoding\n========\n\nThe initial release of the erlang protocol buffers client treats all values as binaries. The caller needs to make sure data is serialized and deserialized correctly. The content type stored along with the object may be used to store the encoding. For example\n\n    decode_term(Object) -\u003e\n      case riakc_obj:get_content_type(Object) of\n        \u003c\u003c\"application/x-erlang-term\"\u003e\u003e -\u003e\n          try\n            {ok, binary_to_term(riakc_obj:get_value(Object))}\n          catch\n            _:Reason -\u003e\n              {error, Reason}\n          end;\n        Ctype -\u003e\n          {error, {unknown_ctype, Ctype}}\n      end.\n\n    encode_term(Object, Term) -\u003e\n      riakc_obj:update_value(Object, term_to_binary(Term, [compressed]),\n      \u003c\u003c\"application/x-erlang-term\"\u003e\u003e).\n\nSiblings\n========\n\nIf a bucket is configured to allow conflicts (allow_mult=true) then the result object may contain more than one result. The number of values can be returned with\n\n    1\u003e riakc_obj:value_count(Obj).\n    2\n\nThe values can be listed with\n\n    2\u003e riakc_obj:get_values(Obj).\n    \\[\u003c\u003c\"{\\\"k1\\\":\\\"v1\\\"}\"\u003e\u003e,\u003c\u003c\"{\\\"k1\\\":\\\"v2\\\"}\"\u003e\u003e\\]\n\nAnd the content types as\n\n    3\u003e riakc_obj:get_content_types(Obj).\n    []\n\nIf resolution simply requires one of the existing siblings to be selected, this can be done through the `riakc_obj:select_sibling` function. This function updates the record with the value and metadata of the selected Nth sibling.\n\nIt is also possible to get a list of tuples representing all the siblings through the `riakc_obj:get_contents` function. This returns a list of tuples in the form `{metadata(), value()}` which can be used when more complex sibling resolution is required.\n\nOnce the correct combination of metadata and value has been determined, the record can be updated with these using the `riakc_obj:update_value` and `riakc_obj:update_metadata` functions. If the resulting content type needs to be updated, the `riakc_obj:update_content_type` can be used.\n\nListing Keys\n============\n\nMost uses of key-value stores are structured in such a way that requests know which keys they want in a bucket. Sometimes, though, it's necessary to find out what keys are available (when debugging, for example). For that, there is list_keys:\n\n    1\u003e riakc_pb_socket:list_keys(Pid, \u003c\u003c\"groceries\"\u003e\u003e).\n    {ok,[\u003c\u003c\"mine\"\u003e\u003e]}\n\nNote that keylist updates are asynchronous to the object storage primitives, and may not be updated immediately after a put or delete. This function is primarily intended as a debugging aid.\n\n`list_keys/2` is just a convenience function around the streaming version of the call `stream_list_keys(Pid, Bucket)`.\n\n    2\u003e riakc_pb_socket:stream_list_keys(Pid, \u003c\u003c\"groceries\"\u003e\u003e).\n    {ok,87009603}\n    3\u003e receive Msg1 \\-\u003e Msg1 end.\n    {87009603,{keys,[]}}\n    4\u003e receive Msg2 \\-\u003e Msg2 end.\n    {87009603,done}\n\nSee [`riakc_utils:wait_for_list`](https://github.com/basho/riak-erlang-client/blob/develop/src/riakc_utils.erl) for a function to receive data.\n\nBucket Properties\n=================\n\nBucket properties can be retrieved and modified using `get_bucket/2` and `set_bucket/3`. The bucket properties are represented as a proplist. Only a subset of the properties can be retrieved and set using the protocol buffers interface - currently only n_val and allow_mult.\n\nHere's an example of getting/setting properties\n\n    3\u003e riakc_pb_socket:get_bucket(Pid, \u003c\u003c\"groceries\"\u003e\u003e).\n    {ok,[{n_val,3},{allow_mult,false}]}\n    4\u003e riakc_pb_socket:set_bucket(Pid, \u003c\u003c\"groceries\"\u003e\u003e, [{n_val, 5}]).\n    ok\n    5\u003e riakc_pb_socket:get_bucket(Pid, \u003c\u003c\"groceries\"\u003e\u003e).\n    {ok,[{n_val,5},{allow_mult,false}]}\n    6\u003e riakc_pb_socket:set_bucket(Pid, \u003c\u003c\"groceries\"\u003e\u003e, [{n_val, 7}, {allow_mult, true}]).\n    ok\n    7\u003e riakc_pb_socket:get_bucket(Pid, \u003c\u003c\"groceries\"\u003e\u003e).\n    {ok,[{n_val,7},{allow_mult,true}]}\n\n\nUser Metadata\n=============\n\nUser metadata are stored in the object metadata dictionary, and can be manipulated by using the `get_user_metadata_entry/2`, `get_user_metadata_entries/1`, `clear_user_metadata_entries/1`, `delete_user_metadata_entry/2` and `set_user_metadata_entry/2` functions.\n\nThese functions act upon the dictionary returned by the `get_metadata/1`, `get_metadatas/1` and `get_update_metadata/1` functions.\n\nThe following example illustrates setting and getting metadata.\n\n    %% Create new object\n    13\u003e Object = riakc_obj:new(\u003c\u003c\"test\"\u003e\u003e, \u003c\u003c\"usermeta\"\u003e\u003e, \u003c\u003c\"data\"\u003e\u003e).\n    {riakc_obj,\u003c\u003c\"test\"\u003e\u003e,\u003c\u003c\"usermeta\"\u003e\u003e,undefined,[],undefined,\n           \u003c\u003c\"data\"\u003e\u003e}\n    14\u003e MD1 = riakc_obj:get_update_metadata(Object).\n    {dict,0,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}\n    15\u003e riakc_obj:get_user_metadata_entries(MD1).\n    []\n    16\u003e MD2 = riakc_obj:set_user_metadata_entry(MD1,{\u003c\u003c\"Key1\"\u003e\u003e,\u003c\u003c\"Value1\"\u003e\u003e}).\n    {dict,1,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],\n        [[\u003c\u003c\"X-Ri\"...\u003e\u003e,{...}]]}}}\n    17\u003e MD3 = riakc_obj:set_user_metadata_entry(MD2,{\u003c\u003c\"Key2\"\u003e\u003e,\u003c\u003c\"Value2\"\u003e\u003e}).\n    {dict,1,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],\n        [[\u003c\u003c\"X-Ri\"...\u003e\u003e,{...}|...]]}}}\n    18\u003e riakc_obj:get_user_metadata_entry(MD3, \u003c\u003c\"Key1\"\u003e\u003e).\n    \u003c\u003c\"Value1\"\u003e\u003e\n    19\u003e MD4 = riakc_obj:delete_user_metadata_entry(MD3, \u003c\u003c\"Key1\"\u003e\u003e).\n    {dict,1,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],\n        [[\u003c\u003c\"X-Ri\"...\u003e\u003e,{...}]]}}}\n    20\u003e riakc_obj:get_user_metadata_entries(MD4).\n    [{\u003c\u003c\"Key2\"\u003e\u003e,\u003c\u003c\"Value2\"\u003e\u003e}]\n    %% Store updated metadata back to the object\n    21\u003e Object2 = riakc_obj:update_metadata(Object,MD4).\n    {riakc_obj,\u003c\u003c\"test\"\u003e\u003e,\u003c\u003c\"usermeta\"\u003e\u003e,undefined,[],\n           {dict,1,16,16,8,80,48,\n                 {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],...},\n                 {{[],[],[],[],[],[],[],[],[],[],[],[],[],...}}},\n           \u003c\u003c\"data\"\u003e\u003e}\n    22\u003e riakc_pb_socket:put(Pid, Object2).\n    ok\n    23\u003e {ok, O1} = riakc_pb_socket:get(Pid, \u003c\u003c\"test\"\u003e\u003e, \u003c\u003c\"usermeta\"\u003e\u003e).\n    {ok,{riakc_obj,\u003c\u003c\"test\"\u003e\u003e,\u003c\u003c\"usermeta\"\u003e\u003e,\n               \u003c\u003c107,206,97,96,96,96,204,96,202,5,82,28,202,156,255,126,\n                 6,220,157,173,153,193,148,...\u003e\u003e,\n               [{{dict,3,16,16,8,80,48,\n                       {[],[],[],[],[],[],[],[],[],[],[],[],...},\n                       {{[],[],[],[],[],[],[],[],[],[],...}}},\n                 \u003c\u003c\"data\"\u003e\u003e}],\n               undefined,undefined}}\n    24\u003e riakc_obj:get_user_metadata_entries(riakc_obj:get_update_metadata(O1)).\n    [{\u003c\u003c\"Key2\"\u003e\u003e,\u003c\u003c\"Value2\"\u003e\u003e}]\n\n\nSecondary Indexes\n=================\n\nSecondary indexes are set through the object metadata dictionary, and can be manipulated by using the `get_secondary_index/2`, `get_secondary_indexes/1`, `clear_secondary_indexes/1`, `delete_secondary_index/2`, `set_secondary_index/2` and `add_secondary_index/2` functions. These functions act upon the dictionary returned by the `get_metadata/1`, `get_metadatas/1` and `get_update_metadata/1` functions.\n\nWhen using these functions, secondary indexes are identified by a tuple, `{binary_index, string()}` or `{integer_index, string()}`, where the string is the name of the index. `{integer_index, \"id\"}` therefore corresponds to the index \"id_int\". As secondary indexes may have more than one value, the index values are specified as lists of integers or binaries, depending on index type.\n\nThe following example illustrates getting and setting secondary indexes.\n\n    %% Create new object\n    13\u003e Obj = riakc_obj:new(\u003c\u003c\"test\"\u003e\u003e, \u003c\u003c\"2i_1\"\u003e\u003e, \u003c\u003c\"John Robert Doe, 25\"\u003e\u003e).\n    {riakc_obj,\u003c\u003c\"test\"\u003e\u003e,\u003c\u003c\"2i_1\"\u003e\u003e,undefined,[],undefined,\n           \u003c\u003c\"John Robert Doe, 25\"\u003e\u003e}\n    14\u003e MD1 = riakc_obj:get_update_metadata(Obj).\n    {dict,0,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}\n    15\u003e MD2 = riakc_obj:set_secondary_index(MD1, [{{integer_index, \"age\"}, [25]},{{binary_index, \"name\"}, [\u003c\u003c\"John\"\u003e\u003e,\u003c\u003c\"Doe\"\u003e\u003e]}]).\n    {dict,1,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],[],[],[],[],[],[],[],[],[],\n        [[\u003c\u003c\"index\"\u003e\u003e,\n          {\u003c\u003c\"name_bin\"\u003e\u003e,\u003c\u003c\"Doe\"\u003e\u003e},\n          {\u003c\u003c\"name_bin\"\u003e\u003e,\u003c\u003c\"John\"\u003e\u003e},\n          {\u003c\u003c\"age_\"...\u003e\u003e,\u003c\u003c...\u003e\u003e}]],\n        [],[],[],[]}}}\n    16\u003e riakc_obj:get_secondary_index(MD2, {binary_index, \"name\"}).\n    [\u003c\u003c\"Doe\"\u003e\u003e,\u003c\u003c\"John\"\u003e\u003e]\n    17\u003e MD3 = riakc_obj:add_secondary_index(MD2, [{{binary_index, \"name\"}, [\u003c\u003c\"Robert\"\u003e\u003e]}]).\n    {dict,1,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],[],[],[],[],[],[],[],[],[],\n        [[\u003c\u003c\"index\"\u003e\u003e,\n          {\u003c\u003c\"name_bin\"\u003e\u003e,\u003c\u003c\"Doe\"\u003e\u003e},\n          {\u003c\u003c\"name_bin\"\u003e\u003e,\u003c\u003c\"John\"\u003e\u003e},\n          {\u003c\u003c\"age_\"...\u003e\u003e,\u003c\u003c...\u003e\u003e},\n          {\u003c\u003c...\u003e\u003e,...}]],\n        [],[],[],[]}}}\n    18\u003e riakc_obj:get_secondary_indexes(MD3).\n    [{{binary_index,\"name\"},[\u003c\u003c\"Doe\"\u003e\u003e,\u003c\u003c\"John\"\u003e\u003e,\u003c\u003c\"Robert\"\u003e\u003e]},{{integer_index,\"age\"},[25]}]\n    19\u003e Obj2 = riakc_obj:update_metadata(Obj,MD3).\n    {riakc_obj,\u003c\u003c\"test\"\u003e\u003e,\u003c\u003c\"2i_1\"\u003e\u003e,undefined,[],\n           {dict,1,16,16,8,80,48,\n                 {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],...},\n                 {{[],[],[],[],[],[],[],[],[],[],[],[[...]],[],...}}},\n           \u003c\u003c\"John Robert Doe, 25\"\u003e\u003e}\n    20\u003e riakc_pb_socket:put(Pid, Obj2).\n\nIn order to query based on secondary indexes, the `riakc_pb_socket:get_index/4`, `riakc_pb_socket:get_index/5`, `riakc_pb_socket:get_index/6` and `riakc_pb_socket:get_index/7` functions can be used. These functions also allows secondary indexes to be specified using the tuple described above.\n\nThe following example illustrates how to perform exact match as well as range queries based on the record and associated indexes created above.\n\n    21\u003e riakc_pb_socket:get_index(Pid, \u003c\u003c\"test\"\u003e\u003e, {binary_index, \"name\"}, \u003c\u003c\"John\"\u003e\u003e).\n    {ok,[\u003c\u003c\"2i_1\"\u003e\u003e]}\n    22\u003e riakc_pb_socket:get_index(Pid, \u003c\u003c\"test\"\u003e\u003e, {integer_index, \"age\"}, 20, 30).\n    {ok,[\u003c\u003c\"2i_1\"\u003e\u003e]}\n\nRiak Data Types\n===============\n\n[Riak Data Types][kv_developing_data_types] can only be used in buckets of a [bucket type][kv_developing_data_types_setting_up] in which the `datatype` bucket property is set to either `counter`, `set`, or `map`.\n\nAll Data Types in the Erlang client can be created and modified at will prior to being stored. Basic CRUD operations are performed by functions in `riakc_pb_socket` specific to Data Types, e.g. `fetch_type/3,4` instead of `get/3,4,5` for normal objects, `update_type/4,5` instead of `put/2,3,4`, etc.\n\nThe current value of a Data Type on the client side is known as a \"dirty value\" and can be found using the `dirty_value/1` function specific to each Data Type, e.g. `riakc_counter:dirty_value/1` or `riakc_set:dirty_value/1`. Fetching the current value from Riak involves the `riakc_pb_socket:fetch_type/3,4` function applied to the Data Type's bucket type/bucket/key location.\n\n#### Counters\n\nLike all Data Types in the Erlang client, counters can be created and incremented/decremented before they are stored in a bucket type/bucket/key location.\n\n    Counter = riakc_counter:new().\n\nCounters can be incremented or decremented by any integer amount:\n\n    Counter1 = riakc_counter:increment(10, Counter),\n    riakc_counter:dirty_value(Counter1).\n    %% 10\n\nThe following would store `Counter1` under the key `page_visits` in the bucket `users` (which bears the type `counter_bucket`):\n\n    riakc_pb_socket:update_type(Pid,\n                                {\u003c\u003c\"counter_bucket\"\u003e\u003e, \u003c\u003c\"users\"\u003e\u003e},\n                                \u003c\u003c\"page_visits\"\u003e\u003e,\n                                riakc_counter:to_op(Counter1)).\n\nThe `to_op` function transforms any Riak Data Type into the necessary set of operations required to successfully update the value in Riak.\n\nRetrieving the counter:\n\n    {ok, Counter2} = riakc_pb_socket:fetch_type(Pid,\n                                     {\u003c\u003c\"counter_bucket\"\u003e\u003e, \u003c\u003c\"users\"\u003e\u003e},\n                                     \u003c\u003c\"page_visits\"\u003e\u003e).\n\n#### Sets\n\nLike counters, sets can be created and have members added/subtracted prior to storing them:\n\n    Set = riakc_set:new(),\n    Set1 = riakc_set:add_element(\u003c\u003c\"foo\"\u003e\u003e, Set),\n    Set2 = riakc_set:add_element(\u003c\u003c\"bar\"\u003e\u003e, Set1),\n    Set3 = riakc_set:del_element(\u003c\u003c\"foo\"\u003e\u003e, Set2),\n    Set4 = riakc_set:add_element(\u003c\u003c\"baz\"\u003e\u003e, Set3),\n    riakc_set:dirty_value(Set4).\n    %% [\u003c\u003c\"bar\"\u003e\u003e, \u003c\u003c\"baz\"\u003e\u003e]\n\nOnce client-side updates are completed, updating sets in Riak works just like updating counters:\n\n    riakc_pb_socket:update_type(Pid,\n                                {\u003c\u003c\"set_bucket\"\u003e\u003e, \u003c\u003c\"all_my_sets\"\u003e\u003e},\n                                \u003c\u003c\"odds_and_ends\"\u003e\u003e,\n                                riakc_set:to_op(Set4)).\n\nNow, a set with the elements `bar` and `baz` will be stored in `/types/set_bucket/buckets/all_my_sets/keys/odds_and_ends`.\n\nThe functions `size/1`, `is_element/2`, and `fold/3` will work only on values stored in and retrieved from Riak. Any local modifications, including initial values when an object is created, will not be considered.\n\n    riakc_set:is_element(\u003c\u003c\"bar\"\u003e\u003e, Set4).\n    %% false\n\n#### Maps\n\nMaps are somewhat trickier because maps can contain any number of fields, each of which itself holds one of the five available Data Types: counters, sets, registers, flags, or even other maps.\n\nLike the other Data Types, you can start with a new map on the client side prior to storing the map in Riak:\n\n    Map = riakc_map:new().\n\nUpdating maps involves both specifying the map field that you wish to update (by both name and Data Type) and then specifying which transformation you wish to apply to that field. Let's say that you want to add a register `reg` with the value `foo` to the map `Map` created above, using an anonymous function:\n\n    Map1 = riakc_map:update({\u003c\u003c\"reg\"\u003e\u003e, register},\n                            fun(R) -\u003e riakc_register:set(\u003c\u003c\"foo\"\u003e\u003e, R) end,\n                            Map).\n\nFor more detailed instructions on maps, see the [documentation][kv_developing_data_types_maps].\n\nLinks\n=====\n\nLinks are also stored in the object metadata dictionary, and can be manipulated by using the `get_links/2`, `get_all_links/1`, `clear_links/1`, `delete_links/2`, `set_link/2` and `add_link/2` functions. When using these functions, a link is identified by a tag, and may therefore contain multiple record IDs.\n\nThese functions act upon the dictionary returned by the `get_metadata/1`, `get_metadatas/1` and `get_update_metadata/1` functions.\n\nThe following example illustrates setting and getting links.\n\n    %% Create new object\n    10\u003e Obj = riakc_obj:new(\u003c\u003c\"person\"\u003e\u003e, \u003c\u003c\"sarah\"\u003e\u003e, \u003c\u003c\"Sarah, 30\"\u003e\u003e).\n    {riakc_obj,\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"sarah\"\u003e\u003e,undefined,[],undefined,\n           \u003c\u003c\"Sarah, 30\"\u003e\u003e}\n    11\u003e MD1 = riakc_obj:get_update_metadata(Obj).\n    {dict,0,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}\n    12\u003e riakc_obj:get_all_links(MD1).\n    []\n    13\u003e MD2 = riakc_obj:set_link(MD1, [{\u003c\u003c\"friend\"\u003e\u003e, [{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"jane\"\u003e\u003e},{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"richard\"\u003e\u003e}]}]).\n    {dict,1,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],\n        [[\u003c\u003c\"Links\"\u003e\u003e,\n          {{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"jane\"\u003e\u003e},\u003c\u003c\"friend\"\u003e\u003e},\n          {{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"richard\"\u003e\u003e},\u003c\u003c\"friend\"\u003e\u003e}]],\n        [],[],[],[],[],[],[],[],[],[],[],[],[]}}}\n    14\u003e MD3 = riakc_obj:add_link(MD2, [{\u003c\u003c\"sibling\"\u003e\u003e, [{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"mark\"\u003e\u003e}]}]).\n    {dict,1,16,16,8,80,48,\n      {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},\n      {{[],[],\n        [[\u003c\u003c\"Links\"\u003e\u003e,\n          {{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"jane\"\u003e\u003e},\u003c\u003c\"friend\"\u003e\u003e},\n          {{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"richard\"\u003e\u003e},\u003c\u003c\"friend\"\u003e\u003e},\n          {{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"mark\"\u003e\u003e},\u003c\u003c\"sibling\"\u003e\u003e}]],\n        [],[],[],[],[],[],[],[],[],[],[],[],[]}}}\n    15\u003e riakc_obj:get_all_links(MD3).\n    [{\u003c\u003c\"friend\"\u003e\u003e,\n        [{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"jane\"\u003e\u003e},{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"richard\"\u003e\u003e}]},\n         {\u003c\u003c\"sibling\"\u003e\u003e,[{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"mark\"\u003e\u003e}]}]\n    16\u003e Obj2 = riakc_obj:update_metadata(Obj,MD3).\n    {riakc_obj,\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"sarah\"\u003e\u003e,undefined,[],\n           {dict,1,16,16,8,80,48,\n                 {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],...},\n                 {{[],[],\n                   [[\u003c\u003c\"Links\"\u003e\u003e,\n                     {{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"jane\"\u003e\u003e},\u003c\u003c\"friend\"\u003e\u003e},\n                     {{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"richard\"\u003e\u003e},\u003c\u003c\"friend\"\u003e\u003e},\n                     {{\u003c\u003c\"person\"\u003e\u003e,\u003c\u003c\"mark\"\u003e\u003e},\u003c\u003c\"sibling\"\u003e\u003e}]],\n                   [],[],[],[],[],[],[],[],[],[],...}}},\n           \u003c\u003c\"Sarah, 30\"\u003e\u003e}\n    17\u003e riakc_pb_socket:put(Pid, Obj2).\n    ok\n\nMapReduce\n=========\n\nMapReduce jobs can be executed using the `riakc_pb_socket:mapred` function. This takes an input specification as well as a list of mapreduce phase specifications as arguments. It also allows a non-default timeout to be specified if required.\n\nThe function `riakc_pb_socket:mapred` uses `riakc_pb_socket:mapred_stream` under the hood, and if results need to be processed as they are streamed to the client, this function can be used instead. The implementation of `riakc_pb_socket:mapred` provides a good example of how to implement this.\n\nIt is possible to define a wide range of inputs for a mapreduce job. Some examples are given below:\n\n**Bucket/Key list:** `[{\u003c\u003c\"bucket1\"\u003e\u003e,\u003c\u003c\"key1\"\u003e\u003e},{\u003c\u003c\"bucket1\"\u003e\u003e,\u003c\u003c\"key2\"\u003e\u003e}]`\n\n**Bucket Type/Bucket/Key list:** `[{{{\u003c\u003c\"type1\"\u003e\u003e,\u003c\u003c\"bucket1\"\u003e\u003e},\u003c\u003c\"key1\"\u003e\u003e},key_data1},{{{\u003c\u003c\"type1\"\u003e\u003e,\u003c\u003c\"bucket1\"\u003e\u003e},\u003c\u003c\"key2\"\u003e\u003e},key_data2}]`\n\n*Note*: due to [a bug](https://github.com/basho/riak_kv/issues/1623), you must include \"key data\" in the above input list to be able to include bucket type.\n\n**All keys in a bucket:** `\u003c\u003c\"bucket1\"\u003e\u003e`\n\n**All keys in a typed bucket:** `{\u003c\u003c\"type1\"\u003e\u003e,\u003c\u003c\"bucket1\"\u003e\u003e}`\n\n**Result of exact secondary index match:** `{index, \u003c\u003c\"bucket1\"\u003e\u003e, {binary_index, \"idx\"}, \u003c\u003c\"key\"\u003e\u003e}`, `{index, \u003c\u003c\"bucket1\"\u003e\u003e, \u003c\u003c\"idx_bin\"\u003e\u003e, \u003c\u003c\"key\"\u003e\u003e}`\n\n**Result of secondary index range query:** `{index, \u003c\u003c\"bucket1\"\u003e\u003e, {integer_index, \"idx\"}, 1, 100}`, `{index, \u003c\u003c\"bucket1\"\u003e\u003e, \u003c\u003c\"idx_int\"\u003e\u003e, \u003c\u003c\"1\"\u003e\u003e, \u003c\u003c\"100\"\u003e\u003e}`\n\nThe query is given as a list of `map`, `reduce` and `link` phases. Map and reduce phases are each expressed as tuples in the following form:\n\n`{Type, FunTerm, Arg, Keep}`\n\nType is an atom, either map or reduce. Arg is a static argument (any Erlang term) to pass to each execution of the phase. Keep is either true or false and determines whether results from the phase will be included in the final value of the query. Riak assumes the final phase will return results.\n\n`FunTerm` is a reference to the function that the phase will execute and takes any of the following forms:\n\n`{modfun, Module, Function}` where Module and Function are atoms that name an Erlang function in a specific module.\n\n`{qfun,Fun}` where Fun is a callable fun term (closure or anonymous function).\n\n`{jsfun,Name}` where Name is a binary that, when evaluated in Javascript, points to a built-in Javascript function.\n\n`{jsanon, Source}` where Source is a binary that, when evaluated in Javascript is an anonymous function.\n\n`{jsanon, {Bucket, Key}}` where the object at {Bucket, Key} contains the source for an anonymous Javascript function.\n\nBelow are a few examples of different types of mapreduce queries. These assume that the following test data has been created:\n\n**Test Data**\n\nCreate two test records in the `\u003c\u003c\"mr\"\u003e\u003e` bucket with secondary indexes and a link as follows:\n\n    12\u003e O1 = riakc_obj:new(\u003c\u003c\"mr\"\u003e\u003e, \u003c\u003c\"bob\"\u003e\u003e, \u003c\u003c\"Bob, 26\"\u003e\u003e).\n    13\u003e M0 = dict:new().\n    14\u003e M1 = riakc_obj:set_secondary_index(M0, {{integer_index,\"age\"}, [26]}).\n    15\u003e O2 = riakc_obj:update_metadata(O1, M1).\n    16\u003e riakc_pb_socket:put(Pid, O2).\n    17\u003e O3 = riakc_obj:new(\u003c\u003c\"mr\"\u003e\u003e, \u003c\u003c\"john\"\u003e\u003e, \u003c\u003c\"John, 23\"\u003e\u003e).\n    18\u003e M2 = riakc_obj:set_secondary_index(M0, {{integer_index,\"age\"}, [23]}).\n    19\u003e M3 = riakc_obj:set_link(M2, [{\u003c\u003c\"friend\"\u003e\u003e, [{\u003c\u003c\"mr\"\u003e\u003e,\u003c\u003c\"bob\"\u003e\u003e}]}]).\n    20\u003e O4 = riakc_obj:update_metadata(O3, M3).\n    21\u003e riakc_pb_socket:put(Pid, O4).\n\n**Example 1: Link Walk**\n\nGet all friends linked to *john* in the *mr* bucket.\n\n    6\u003e {ok, [{N1, R1}]} = riakc_pb_socket:mapred(Pid,[{\u003c\u003c\"mr\"\u003e\u003e, \u003c\u003c\"john\"\u003e\u003e}],[{link, \u003c\u003c\"mr\"\u003e\u003e, \u003c\u003c\"friend\"\u003e\u003e, true}]).\n    {ok,[{0,[[\u003c\u003c\"mr\"\u003e\u003e,\u003c\u003c\"bob\"\u003e\u003e,\u003c\u003c\"friend\"\u003e\u003e]]}]}\n\nAs expected, the link information for `bob` is returned.\n\n**Example 2: Determine total object size using a qfun**\n\nCreate a qfun that returns the size of the record and feed this into the existing reduce function `riak_kv_mapreduce:reduce_sum` to get total size.\n\n    6\u003e RecSize = fun(G, _, _) -\u003e [byte_size(riak_object:get_value(G))] end.\n    #Fun\u003cerl_eval.18.82930912\u003e\n    7\u003e {ok, [{N2, R2}]} = riakc_pb_socket:mapred(Pid,\n                {index, \u003c\u003c\"mr\"\u003e\u003e, {integer_index, \"age\"}, 20, 30},\n                [{map, {qfun, RecSize}, none, false},\n                 {reduce, {modfun, 'riak_kv_mapreduce', 'reduce_sum'}, none, true}]).\n    {ok,[{1,[15]}]}\n\n As expected, total size of data is 15 bytes.\n\n\nSecurity\n========\n\nIf you are using [Riak Security][kv_using_security_basics], you will need to configure your Riak Erlang client to use SSL when connecting to Riak. The required setup depends on the [security source][kv_using_security_managing_sources] that you choose. A general primer on Riak client security can be found in our [official docs][kv_developing_usage_security].\n\nRegardless of which authentication source you use, your client will need to have access to a certificate authority (CA) shared by your Riak server. You will also need to provide a username that corresponds to the username for the user or role that you have [created in Riak][kv_using_security_basics_user_mgmt].\n\nLet's say that your CA is stored in the `/ssl_dir` directory and bears the name `cacertfile.pem` and that you need provide a username of `riakuser` and a password of `rosebud`. You can input that information as a list of tuples when you create your process identifier (PID) for further connections to Riak:\n\n```erlang\nCertDir = \"/ssl_dir\",\nSecurityOptions = [\n                   {credentials, \"riakuser\", \"rosebud\"},\n                   {cacertfile, filename:join([CertDir, \"cacertfile.pem\"])}\n                  ],\n{ok, Pid} = riakc_pb_socket:start(\"127.0.0.1\", 8087, SecurityOptions).\n```\n\nThis setup will suffice for [password, PAM and trust][kv_using_security_basics] based authentication.\n\nIf you are using [certificate-based authentication][kv_using_security_basics_certs], you will also need to specify a cert and keyfile. The example below uses the same connection information from the sample above but also points to a cert called `cert.pem` and a keyfile called `key.pem` (both stored in the same `/ssl_dir` directory as the CA):\n\n```erlang\nCertDir = \"/ssl_dir\",\nSecurityOptions = [\n                   {credentials, \"riakuser\", \"rosebud\"},\n                   {cacertfile, filename:join([CertDir, \"cacertfile.pem\"])},\n                   {certfile, filename:join([CertDir, \"cert.pem\"])},\n                   {keyfile, filename:join([CertDir, \"key.pem\"])}\n                  ],\n{ok, Pid} = riakc_pb_socket:start(\"127.0.0.1\", 8087, SecurityOptions).\n```\n\nMore detailed information can be found in our [official documentation][kv_using_security_basics].\n\n\nTimeseries\n==========\n\nAssume the following table definition for the examples.\n\n```SQL\nCREATE TABLE GeoCheckin\n(\n   myfamily    varchar   not null,\n   myseries    varchar   not null,\n   time        timestamp not null,\n   weather     varchar   not null,\n   temperature double,\n   PRIMARY KEY (\n     (myfamily, myseries, quantum(time, 15, 'm')),\n     myfamily, myseries, time\n   )\n)\n```\n\n### Store TS Data\n\nTo write data to your table, put the data in a list, and use the `riakc_ts:put/3` function.  Please ensure the the order of the data is the same as the table definition, and note that each row is a tuple of values corresponding to the columns in the table.\n\n\n```erlang\n{ok, Pid} = riakc_pb_socket:start_link(\"myriakdb.host\", 10017).\nriakc_ts:put(Pid, \"GeoCheckin\", [{\u003c\u003c\"family1\"\u003e\u003e, \u003c\u003c\"series1\"\u003e\u003e, 1234567, \u003c\u003c\"hot\"\u003e\u003e, 23.5}, {\u003c\u003c\"family2\"\u003e\u003e, \u003c\u003c\"series99\"\u003e\u003e, 1234567, \u003c\u003c\"windy\"\u003e\u003e, 19.8}]).\n```\n\n### Query TS Data\n\nTo query TS data, simply use `riakc_ts:query/2` with a connection and a query string. All parts of a table's Primary Key must be included in the where clause.\n\n```erlang\n{ok, Pid} = riakc_pb_socket:start_link(\"myriakdb.host\", 10017).\n\nriakc_ts:query(Pid, \"select * from GeoCheckin where time \u003e 1234560 and time \u003c 1234569 and myfamily = 'family1' and myseries = 'series1'\").\n\nriakc_ts:query(Pid, \"select weather, temperature from GeoCheckin where time \u003e 1234560 and time \u003c 1234569 and myfamily = 'family1' and myseries = 'series1'\").\n\nriakc_ts:query(Pid, \"select weather, temperature from GeoCheckin where time \u003e 1234560 and time \u003c 1234569 and myfamily = 'family1' and myseries = 'series1' and temperature \u003e 27.0\").\n```\n\n\nTroubleshooting\n==================\n\nIf `start/2` or `start_link/2` return `{error,econnrefused}` the client could not connect to the server - make sure the protocol buffers interface is enabled on the server and the address/port is correct.\n\nContributors\n============\n\nThis is not a comprehensive list, please see the commit history.\n\n* [Aaron France](https://github.com/AeroNotix)\n* [Akash Manohar](https://github.com/HashNuke)\n* [Alex Moore](https://github.com/alexmoore)\n* [Andreas Hasselberg](https://github.com/anha0825)\n* [Andrei Zavada](https://github.com/hmmr)\n* [Andrew Thompson](https://github.com/Vagabond)\n* [Andrzej Kajetanowicz](https://github.com/kajetanowicz)\n* [Andy Gross](https://github.com/argv0)\n* [Anthony Molinaro](https://github.com/djnym)\n* [Bernard Duggan](https://github.com/bernardd)\n* [Brett Hazen](https://github.com/javajolt)\n* [Brian McClain](https://github.com/BrianMMcClain)\n* [Brian Roach](https://github.com/broach)\n* [Bryan Fink](https://github.com/beerriot)\n* [Bryce Kerley](https://github.com/bkerley)\n* [Christian Dahlqvist](https://github.com/cdahlqvist)\n* [Christopher Meiklejohn](https://github.com/cmeiklejohn)\n* [Daniel Fernandez](https://github.com/danielfernandez)\n* [Daniel Néri](https://github.com/dne)\n* [Daniel Reverri](https://github.com/dreverri)\n* [Daniel White](https://github.com/danielwhite)\n* [Dave Parfitt](https://github.com/metadave)\n* [Dave Smith](https://github.com/djsmith42)\n* [Dmitry Demeshchuk](https://github.com/doubleyou)\n* [Drew](https://github.com/drew)\n* [Drew Kerrigan](https://github.com/drewkerrigan)\n* [Eduardo Gurgel](https://github.com/edgurgel)\n* Engel A. Sanchez\n* [Eric Redmond](https://github.com/coderoshi)\n* Erik Leitch\n* Evan Vigil-McClanahan\n* [Fred Dushin](https://github.com/fadushin)\n* [Jared Morrow](https://github.com/jaredmorrow)\n* [Jeffrey Massung](https://github.com/massung)\n* [Jeremy Raymond](https://github.com/jeraymond)\n* [John Daily](https://github.com/macintux)\n* [Jon Meredith](https://github.com/jonmeredith)\n* [Joseph Blomstedt](https://github.com/jtuple)\n* [Kelly McLaughlin](https://github.com/kellymclaughlin)\n* [Kevin Smith](https://github.com/kevsmith)\n* [Luc Perkins](https://github.com/lucperkins)\n* [Luca Favatella](https://github.com/lucafavatella)\n* [Lukasz Milewski](https://github.com/milek)\n* [Luke Bakken](https://github.com/lukebakken)\n* [Mark Phillips](https://github.com/phips)\n* [Matt Heitzenroder](https://github.com/roder)\n* [Mikhail Sobolev](https://github.com/sa2ajj)\n* Olav Frengstad\n* [Paulo Almeida](https://github.com/pma)\n* [Paul Oliver](https://github.com/puzza007)\n* [Piotr Nosek](https://github.com/fenek)\n* [Reid Draper](https://github.com/reiddraper)\n* [Russell Brown](https://github.com/russelldb)\n* [Rusty Klophaus](https://github.com/rustyio)\n* [Ryan Zezeski](https://github.com/rzezeski)\n* [Sam Tavakoli](https://github.com/sata)\n* [Scott Fritchie](https://github.com/slfritchie)\n* [Sean Cribbs](https://github.com/seancribbs)\n* [Sebastian Probst Eide](https://github.com/sebastian)\n* [Srijan Choudhary](https://github.com/srijan)\n* [Steve Vinoski](https://github.com/vinoski)\n* [Tuncer Ayaz](https://github.com/tuncer)\n* [UENISHI Kota](https://github.com/kuenishi)\n* [Wade Mealing](https://github.com/wmealing)\n* [Zeeshan Lakhani](https://github.com/zeeshanlakhani)\n\n[basho_docs]: http://docs.basho.com/\n[kv_setup]: http://docs.basho.com/riak/kv/latest/setup/\n[erlang_client_edocs]: http://basho.github.com/riak-erlang-client/\n[kv_developing_data_types]: http://docs.basho.com/riak/kv/latest/developing/data-types/\n[kv_developing_data_types_setting_up]: http://docs.basho.com/riak/kv/latest/developing/data-types/#setting-up-buckets-to-use-riak-data-types\n[kv_developing_data_types_maps]: http://docs.basho.com/riak/kv/latest/developing/data-types/#maps\n[kv_configuring_reference_bucket_properties]: https://docs.basho.com/riak/kv/latest/configuring/reference/#default-bucket-properties\n[kv_learn_glossary_quorum]: http://docs.basho.com/riak/kv/latest/learn/glossary/#quorum\n[kv_using_security_managing_sources]: http://docs.basho.com/riak/kv/latest/using/security/managing-sources/\n[kv_using_security_basics]: https://docs.basho.com/riak/kv/latest/using/security/basics/\n[kv_developing_usage_security]: https://docs.basho.com/riak/kv/latest/developing/usage/security/\n[kv_using_security_basics_user_mgmt]: https://docs.basho.com/riak/kv/latest/using/security/basics/#user-management\n[kv_using_security_basics_certs]: https://docs.basho.com/riak/kv/latest/using/security/basics/#certificate-configuration\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoncalotomas%2Friakc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoncalotomas%2Friakc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoncalotomas%2Friakc/lists"}