Couchbase C++ SDK 1.0.4 (rev. 5355b0f)
Loading...
Searching...
No Matches
Couchbase C++ SDK
Note
You may read about related Couchbase software at https://docs.couchbase.com/

Start Using

The following example shows the most basic usage of the library. It performs the following operations:

  • [1] connect to local cluster (location and credentials given in program arguments),
  • [2] persists document to the collection using couchbase::collection::upsert(),
  • [3] retrieves document back with couchbase::collection::get(), extracts content as generic JSON value, and prints one of the fields,
  • [4] performs N1QL query with couchbase::scope::query() and prints the result.
  • [5] output results obtained in [4] using custom type defined in [6]
  • [7] closes the cluster and deallocate resources
75#include <couchbase/cluster.hxx>
77#include <couchbase/fmt/cas.hxx>
79
80#include <tao/json.hpp>
81#include <tao/json/contrib/traits.hpp>
82
83int
84main(int argc, const char* argv[])
85{
86 if (argc != 4) {
87 fmt::print("USAGE: ./start_using couchbase://127.0.0.1 Administrator password\n");
88 return 1;
89 }
90
91 std::string connection_string{ argv[1] }; // "couchbase://127.0.0.1"
92 std::string username{ argv[2] }; // "Administrator"
93 std::string password{ argv[3] }; // "password"
94 std::string bucket_name{ "travel-sample" };
95
96 auto options = couchbase::cluster_options(username, password);
97 // customize through the 'options'.
98 // For example, optimize timeouts for WAN
99 options.apply_profile("wan_development");
100
101 // [1] connect to cluster using the given connection string and the options
102 auto [connect_err, cluster] = couchbase::cluster::connect(connection_string, options).get();
103 if (connect_err) {
104 fmt::print("unable to connect to the cluster: {}\n", connect_err);
105 return 1;
106 }
107
108 // get a bucket reference
109 auto bucket = cluster.bucket(bucket_name);
110
111 // get a user-defined collection reference
112 auto scope = bucket.scope("tenant_agent_00");
113 auto collection = scope.collection("users");
114
115 { // [2] upsert document
116 std::string doc_id = "my-document";
117 auto [err, upsert_result] =
118 collection.upsert(doc_id, tao::json::value{ { "name", "mike" } }).get();
119 if (err.ec()) {
120 fmt::print("unable to upsert the document \"{}\": {}\n", doc_id, err);
121 return 1;
122 }
123 fmt::print("saved document \"{}\", cas={}, token={}\n",
124 doc_id,
125 upsert_result.cas(),
126 upsert_result.mutation_token().value());
127 }
128
129 { // [3] get document
130 std::string doc_id = "my-document";
131 auto [err, get_result] = collection.get(doc_id).get();
132 if (err.ec()) {
133 fmt::print("unable to get the document \"{}\": {}\n", doc_id, err);
134 return 1;
135 }
136 auto name = get_result.content_as<tao::json::value>()["name"].get_string();
137 fmt::print("retrieved document \"{}\", name=\"{}\"\n", doc_id, name);
138 }
139
140 { // [4] N1QL query
141 auto inventory_scope = bucket.scope("inventory");
142 // Select first 5 hotels from US or UK, that describe themselves as cheap
143 // and order them by overall rating.
144 std::string query{ R"(
145 SELECT META(h).id, h AS doc,
146 AVG(r.ratings.Overall) AS avg_rating
147 FROM hotel h
148 UNNEST h.reviews r
149 WHERE h.country IN $1 AND h.description LIKE "%cheap%"
150 GROUP BY META(h).id, h
151 ORDER BY avg_rating DESC
152 LIMIT 5;
153 )" };
154 auto query_options = couchbase::query_options{}.positional_parameters(
155 std::vector{ "United States", "United Kingdom" });
156 auto [error, query_result] = inventory_scope.query(query, query_options).get();
157 if (error) {
158 fmt::print("unable to perform query: {}\n", error.ctx().to_json());
159 return 1;
160 }
161 fmt::println("{:<15} {:<15} {:>10} {:<30}", "ID", "Country", "Rating", "Hotel");
162 for (auto& row : query_result.rows_as()) {
163 fmt::println("{:<15} {:<15} {:>10.2f} {:<30}",
164 row["id"].as<std::string>(),
165 row["doc"]["country"].as<std::string>(),
166 row["avg_rating"].as<double>(),
167 row["doc"]["title"].as<std::string>());
168 }
169
170 // [5] iterate over results using custom type
171 fmt::println("{:<15} {:<15} {:>10} {:<30}", "ID", "Country", "Rating", "Hotel");
172 for (const auto& row : query_result.rows_as<couchbase::codec::tao_json_serializer, hotel>()) {
173 fmt::println(
174 "{:<15} {:<15} {:>10.2f} {:<30}", row.id, row.country, row.average_rating, row.name);
175 }
176 }
177
178 // [7] close cluster connection
179 cluster.close().get();
180 return 0;
181}
182
183/*
184
185$ ./start_using couchbase://127.0.0.1 Administrator password
186saved document "my-document", cas=17ed9f687ee90000, token=travel-sample:110:101634532779186:101
187retrieved document "my-document", name="mike"
188ID Country Rating Hotel
189hotel_26169 United States 4.75 San Francisco/Twin Peaks-Lake Merced
190hotel_26499 United States 4.60 Santa Monica
191hotel_3616 United Kingdom 4.57 Birmingham (England)
192hotel_7387 United States 4.50 Death Valley National Park
193hotel_25588 United States 4.44 San Francisco/Civic Center-Tenderloin
194
195 */
48// [6] definition of the custom type and its decoder
49struct hotel {
50 std::string id{};
51 std::string name{};
52 std::string country{};
53 double average_rating{};
54};
55
56template<>
57struct tao::json::traits<hotel> {
58 template<template<typename...> class Traits>
59 static auto as(const tao::json::basic_value<Traits>& v) -> hotel
60 {
61 hotel result;
62 auto object = v.get_object();
63 result.id = object["id"].template as<std::string>();
64 result.average_rating = object["avg_rating"].template as<double>();
65 result.name = object["doc"]["title"].template as<std::string>();
66 result.country = object["doc"]["country"].template as<std::string>();
67 return result;
68 }
69};

Using Transactions

Next example shows transactions API. Read more details in couchbase::transactions::transactions

  • [1] connect to cluster using the given connection string and the options
  • [2] persist three documents to the default collection of bucket "default"
  • [3] blocking transaction
    • [3.1] closure argument to couchbase::transactions::transactions::run method encapsulates logic, that has to be run in transaction
    • [3.2] get document
    • [3.4] replace document's content
    • [3.5] check the overall status of the transaction
  • [4] asynchronous transaction
  • [5] close cluster connection
32#include <couchbase/cluster.hxx>
34#include <couchbase/fmt/cas.hxx>
35
36#include <tao/json.hpp>
37
38auto
39main(int argc, const char* argv[]) -> int
40{
41 if (argc != 4) {
42 fmt::print("USAGE: ./blocking-txn couchbase://127.0.0.1 Administrator password\n");
43 return 1;
44 }
45
46 int retval = 0;
47
48 const std::string connection_string{ argv[1] };
49 const std::string username{ argv[2] };
50 const std::string password{ argv[3] };
51
52 auto options = couchbase::cluster_options(username, password);
53 // customize through the 'options'.
54 // For example, optimize timeouts for WAN
55 options.apply_profile("wan_development");
56
57 // [1] connect to cluster using the given connection string and the options
58 auto [connect_err, cluster] = couchbase::cluster::connect(connection_string, options).get();
59 if (connect_err) {
60 fmt::print("unable to connect to the cluster: {}\n", connect_err);
61 return 1;
62 }
63
64 // [2] persist three documents to the default collection of bucket "default"
65 auto collection = cluster.bucket("default").default_collection();
66 constexpr auto id_1 = "my-doc_1";
67 constexpr auto id_2 = "my_doc_2";
68 constexpr auto id_3 = "my_doc_3";
69 const tao::json::value content = { { "some", "content" } };
70
71 for (const auto& id : { id_1, id_2, id_3 }) {
72 if (auto [err, res] = collection.upsert(id, content).get(); err.ec()) {
73 fmt::print(
74 stderr, "upsert \"{}\" failed before starting transaction: {}\n", id, err.ec().message());
75 return 1;
76 }
77 }
78
79 { // [3] blocking transaction
81 auto [tx_err, tx_res] = cluster.transactions()->run(
82 // [3.1] closure argument to run() method encapsulates logic, that has to be run in
83 // transaction
84 [=](std::shared_ptr<couchbase::transactions::attempt_context> ctx) -> couchbase::error {
85 // [3.2] get document
86 auto [err_ctx, doc] = ctx->get(collection, id_1);
87 if (err_ctx.ec()) {
88 fmt::print(stderr, "failed to get document \"{}\": {}\n", id_1, err_ctx.ec().message());
89 // [3.3] don't continue the transaction logic
90 return {};
91 }
92 // [3.4] replace document's content
93 ctx->replace(doc, tao::json::value{ { "some", "other content" } });
94 return {};
95 });
96 // [3.5] check the overall status of the transaction
97 if (tx_err.ec()) {
98 fmt::print(stderr,
99 "error in transaction {}, cause: {}\n",
100 tx_err.ec().message(),
101 tx_err.cause().has_value() ? tx_err.cause().value().ec().message() : "");
102 retval = 1;
103 } else {
104 fmt::print("transaction {} completed successfully\n", tx_res.transaction_id);
105 }
107 }
108
109 { // [4] asynchronous transaction
111 // [4.1] create promise to retrieve result from the transaction
112 auto barrier = std::make_shared<std::promise<std::error_code>>();
113 auto f = barrier->get_future();
114 cluster.transactions()->run(
115 // [4.2] closure argument to run() method encapsulates logic, that has to be run in
116 // transaction
117 [=](std::shared_ptr<couchbase::transactions::async_attempt_context> ctx) -> couchbase::error {
118 // [4.3] get document
119 ctx->get(collection, id_1, [=](auto err_ctx_1, auto doc) {
120 if (err_ctx_1.ec()) {
121 fmt::print(
122 stderr, "failed to get document \"{}\": {}\n", id_1, err_ctx_1.ec().message());
123 return;
124 }
125 // [4.4] replace document's content
126 ctx->replace(doc,
127 tao::json::value{ { "some", "other async content" } },
128 [=](auto err_ctx_2, auto /*res*/) {
129 if (err_ctx_2.ec()) {
130 fmt::print(stderr,
131 "error replacing content in doc {}: {}\n",
132 id_1,
133 err_ctx_2.ec().message());
134 } else {
135 fmt::print("successfully replaced: {}\n", id_1);
136 }
137 });
138 });
139 ctx->get(collection, id_2, [=](auto err_ctx_1, auto doc) {
140 if (err_ctx_1.ec()) {
141 fmt::print("error getting doc {}: {}", id_2, err_ctx_1.ec().message());
142 return;
143 }
144 ctx->replace(doc,
145 tao::json::value{ { "some", "other async content" } },
146 [=](auto err_ctx_2, auto /*res*/) {
147 if (err_ctx_2.ec()) {
148 fmt::print(stderr,
149 "error replacing content in doc {}: {}\n",
150 id_2,
151 err_ctx_2.ec().message());
152 } else {
153 fmt::print("successfully replaced: {}\n", id_2);
154 }
155 });
156 });
157 ctx->get(collection, id_3, [=](auto err_ctx_1, auto doc) {
158 if (err_ctx_1.ec()) {
159 fmt::print(stderr, "error getting doc {}: {}\n", id_3, err_ctx_1.ec().message());
160 return;
161 }
162 ctx->replace(doc,
163 tao::json::value{ { "some", "other async content" } },
164 [=](auto err_ctx_2, auto /*res*/) {
165 if (err_ctx_2.ec()) {
166 fmt::print(stderr,
167 "error replacing content in doc {}: {}\n",
168 id_3,
169 err_ctx_2.ec().message());
170 } else {
171 fmt::print("successfully replaced: {}\n", id_3);
172 }
173 });
174 });
175 return {};
176 },
177 // [4.5], second closure represents transaction completion logic
178 [barrier](auto tx_err, auto tx_res) {
179 if (tx_err.ec()) {
180 fmt::print(stderr,
181 "error in async transaction {}, {}\n",
182 tx_res.transaction_id,
183 tx_err.ec().message());
184 }
185 barrier->set_value(tx_err.ec());
186 });
187 if (auto async_err = f.get()) {
188 fmt::print(stderr, "received async error from future: message - {}\n", async_err.message());
189 retval = 1;
190 }
192 }
193
194 // [5], close cluster connection
195 cluster.close().get();
196 return retval;
197}
198

See also simple class that implements an operation in fictional game backend: game_server.cxx (and its asynchronous version in async_game_server.cxx)