Are your legacy databases holding up application development and slowing down performance?
With Couchbase you can:
- Use SQL for familiar query access
- Store data as JSON and avoid a restrictive relational data model
- SQL and JSON allow you to build new features using our built-in multi-model services, including full-text search, analytics, eventing, and key-value
Java - Upsert
import com.couchbase.client.core.error.subdoc.PathNotFoundException;
import com.couchbase.client.java.*;
import com.couchbase.client.java.kv.*;
import com.couchbase.client.java.kv.MutationResult;
import com.couchbase.client.java.json.JsonObject;
import com.couchbase.client.java.kv.LookupInResult;
import static com.couchbase.client.java.kv.LookupInSpec.get;
import static com.couchbase.client.java.kv.MutateInSpec.upsert;
import java.util.Collections;
class Program {
public static void main(String[] args) {
var cluster = Cluster.connect(
"couchbase://127.0.0.1", "username", "password"
);
var bucket = cluster.bucket("travel-sample");
var collection = bucket.defaultCollection();
JsonObject content = JsonObject.create()
.put("country", "Iceland")
.put("callsign", "ICEAIR")
.put("iata", "FI")
.put("icao", "ICE")
.put("id", 123)
.put("name", "Icelandair")
.put("type", "airline");
collection.upsert("airline_123", content);
try {
LookupInResult lookupResult = collection.lookupIn(
"airline_123", Collections.singletonList(get("name"))
);
var str = lookupResult.contentAs(0, String.class);
System.out.println("New Document name = " + str);
} catch (PathNotFoundException ex) {
System.out.println("Document not found!");
}
}
}
NodeJS - Upsert
const couchbase = require('couchbase')
const main = async () => {
const cluster = await couchbase.connect('couchbase://127.0.0.1', {
username: 'username', password: 'password'
})
const bucket = cluster.bucket('travel-sample')
const collection = bucket.defaultCollection()
const airline = {
country: 'Iceland', callsign: 'ICEAIR',
iata: 'FI', icao: 'ICE', id: 123,
name: 'Icelandair', type: 'airline',
}
const upsertDocument = async (type, id, doc) => {
try {
const upsertResult = await collection.upsert(`${type}_${id}`, doc);
console.log('Upsert Result: ')
console.log(upsertResult)
} catch (err) {
console.error(err)
}
}
const getSubDocument = async (key, field) => {
try {
var result = await collection.lookupIn(key, [
couchbase.LookupInSpec.get(field),
])
var fieldValue = result.content[0].value
console.log('LookupIn Result: ')
console.log(result)
console.log('Field Value: ')
console.log(fieldValue)
} catch (error) {
console.error(error)
}
}
upsertDocument(airline.type, airline.id, airline)
.then(
getSubDocument('airline_123', 'name')
.then(() => process.exit(0))
)
}
main()
Python - Upsert
#!/usr/bin/python3
import sys
import couchbase.collection
import couchbase.subdocument as SD
from couchbase.cluster import Cluster, ClusterOptions
from couchbase.auth import PasswordAuthenticator
from couchbase.durability import ServerDurability, Durability
from datetime import timedelta
pa = PasswordAuthenticator('username', 'password')
cluster = Cluster('couchbase://127.0.0.1', ClusterOptions(pa))
bucket = cluster.bucket('travel-sample')
collection = bucket.default_collection()
try:
document = dict(
country="Iceland", callsign="ICEAIR", iata="FI", icao="ICE",
id=123, name="Icelandair", type="airline"
)
result = collection.upsert(
'airline_123',
document,
expiry=timedelta(minutes=1)
)
print("UPSERT SUCCESS")
print("cas result:", result.cas)
except:
print("exception:", sys.exc_info())
try:
result = collection.lookup_in('airline_123', [SD.get('name')])
name = result.content_as[str](0) # "United Kingdom"
print("name:", name)
except:
print("exception:", sys.exc_info()[0])
.NET - Upsert
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Couchbase;
using Couchbase.Core.Exceptions.KeyValue;
using Couchbase.KeyValue;
namespace CouchbaseDotNetExample
{
class Program
{
static async Task Main(string[] args)
{
var cluster = await Cluster.ConnectAsync(
"couchbase://127.0.0.1", "username", "password"
);
var bucket = await cluster.BucketAsync("travel-sample");
var scope = await bucket.ScopeAsync("_default");
var collection = await scope.CollectionAsync("_default");
var content = new
{
Country = "Iceland",
Callsign = "ICEAIR",
Iata = "FI",
Icao = "ICE",
Id = 123,
Name = "Icelandair",
Type = "airline"
};
await collection.UpsertAsync("airline_123", content);
try
{
var lookupResult = await collection.LookupInAsync("airline_123",
new List<LookupInSpec>
{
LookupInSpec.Get("name")
});
var name = lookupResult.ContentAs<string>(0);
Console.WriteLine($"New Document name = {name}");
}
catch (PathNotFoundException)
{
Console.WriteLine("Document not found!");
}
await cluster.DisposeAsync();
}
}
}
PHP - Upsert
<?php
$connectionString = "couchbase://127.0.0.1";
$options = new \Couchbase\ClusterOptions();
$options->credentials("username", "password");
$cluster = new \Couchbase\Cluster($connectionString, $options);
$bucket = $cluster->bucket("travel-sample");
$collection = $bucket->defaultCollection();
$content = ["country" => "Iceland",
"callsign" => "ICEAIR",
"iata" => "FI",
"icao" => "ICE",
"id" => 123,
"name" => "Icelandair",
"type" => "airline"];
$collection->upsert("airline_123", $content);
try {
$result = $collection->lookupIn("airline_123", [new \Couchbase\LookupGetSpec("name")]);
$name = $result->content(0);
print("New Document name = $name");
} catch (\Couchbase\PathNotFoundException $pnfe) {
print("Sub-doc path not found!");
} catch (\Couchbase\BaseException $ex) {
print("Exception $ex\n");
}
?>
Ruby - Upsert
require "couchbase"
include Couchbase
options = Cluster::ClusterOptions.new
options.authenticate("username", "password")
cluster = Cluster.connect("couchbase://127.0.0.1", options)
bucket = cluster.bucket("travel-sample")
collection = bucket.default_collection
begin
content = {"country" => "Iceland",
"callsign" => "ICEAIR",
"iata" => "FI",
"icao" => "ICE",
"id" => 123,
"name" => "Icelandair",
"type" => "airline"}
collection.upsert("airline_123", content)
result = collection.lookup_in("airline_123", [ LookupInSpec.get("name")])
puts "New Document name: #{result.content(0)}"
rescue Couchbase::Error::PathNotFound => pnfe
puts "Sub-doc path not found!"
rescue Couchbase::Error::DocumentNotFound => ex
puts "Document not found!"
end
Scala - Upsert
package com.couchbase
import com.couchbase.client.core.error.{CouchbaseException, DocumentNotFoundException}
import com.couchbase.client.core.error.subdoc.{PathExistsException,PathNotFoundException}
import com.couchbase.client.scala.Cluster
import com.couchbase.client.scala.json.{JsonObject, JsonObjectSafe}
import com.couchbase.client.scala.kv.LookupInSpec._
import com.couchbase.client.scala.kv.{LookupInResult, _}
import scala.util.{Failure, Success, Try}
object Program extends App {
val cluster = Cluster.connect("127.0.0.1", "username", "password").get
var bucket = cluster.bucket("travel-sample");
val collection = bucket.defaultCollection
val content = JsonObject("country" -> "Iceland",
"callsign"-> "ICEAIR",
"iata" -> "FI",
"icao" -> "ICE",
"id" -> 123,
"name" -> "Icelandair",
"type" -> "airline")
collection.upsert("airline_123", content) match {
case Success(result) =>
case Failure(exception) => println("Error: " + exception)
}
val result = collection.lookupIn("airline_123", Array(get("name")))
result match {
case Success(r) =>
val str: Try[String] = r.contentAs[String](0)
str match {
case Success(s) => println(s"New document name: ${s}")
case Failure(err) => println(s"Error: ${err}")
}
case Failure(err: DocumentNotFoundException) => println("Document not found")
case Failure(err: PathNotFoundException) => println("Sub-doc path not found!")
case Failure(err: CouchbaseException) => println("Couchbase error: " + err)
case Failure(err) => println("Error getting document: " + err)
}
}
Golang - Upsert
package main
import (
"fmt"
"log"
"time"
"github.com/couchbase/gocb/v2"
)
func main() {
cluster, err := gocb.Connect("couchbase://127.0.0.1", gocb.ClusterOptions{
Authenticator: gocb.PasswordAuthenticator{
Username: "username",
Password: "password",
},
})
if err != nil {
log.Fatal(err)
}
bucket := cluster.Bucket("travel-sample")
err = bucket.WaitUntilReady(5*time.Second, nil)
if err != nil {
log.Fatal(err)
}
collection := bucket.DefaultCollection()
type Doc struct {
Id int `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
Iata string `json:"iata"`
Icao string `json:"icao"`
Callsign string `json:"callsign"`
Country string `json:"country"`
}
document := Doc {
Country: "Iceland",
Callsign: "ICEAIR",
Iata: "FI",
Icao: "ICE",
Id: 123,
Name: "Icelandair",
Type: "airline",
}
_, err = collection.Upsert("airline_123", &document, nil)
if err != nil {
log.Fatal(err)
}
options := []gocb.LookupInSpec{
gocb.GetSpec("name", &gocb.GetSpecOptions{}),
}
results, err := collection.LookupIn("airline_123", options, &gocb.LookupInOptions{})
if err != nil {
log.Fatal(err)
}
var country string
err = results.ContentAt(0, &country)
if err != nil {
log.Fatal(err)
}
fmt.Printf("New document name: %s\n", country)
}
C++ - Upsert
#include <vector>
#include <string>
#include <iostream>
#include <libcouchbase/couchbase.h>
static void
check(lcb_STATUS err, const char* msg)
{
if (err != LCB_SUCCESS) {
std::cerr << "[ERROR] " << msg << ": " << lcb_strerror_short(err) << "\n";
exit(EXIT_FAILURE);
}
}
struct Result {
std::string value{};
lcb_STATUS status{ LCB_SUCCESS };
};
struct SubdocResults {
lcb_STATUS status{ LCB_SUCCESS };
std::vector<Result> entries{};
};
static void
sdget_callback(lcb_INSTANCE*, int, const lcb_RESPSUBDOC* resp)
{
SubdocResults* results = nullptr;
lcb_respsubdoc_cookie(resp, reinterpret_cast<void**>(&results));
results->status = lcb_respsubdoc_status(resp);
if (results->status != LCB_SUCCESS) {
return;
}
std::size_t number_of_results = lcb_respsubdoc_result_size(resp);
results->entries.resize(number_of_results);
for (size_t idx = 0; idx < number_of_results; ++idx) {
results->entries[idx].status = lcb_respsubdoc_result_status(resp, idx);
const char* buf = nullptr;
std::size_t buf_len = 0;
lcb_respsubdoc_result_value(resp, idx, &buf, &buf_len);
if (buf_len > 0) {
results->entries[idx].value.assign(buf, buf_len);
}
}
}
int
main()
{
std::string username{ "username" };
std::string password{ "password" };
std::string connection_string{ "couchbase://127.0.0.1" };
std::string bucket_name{ "travel-sample" };
lcb_CREATEOPTS* create_options = nullptr;
check(lcb_createopts_create(&create_options, LCB_TYPE_BUCKET), "build options object for lcb_create");
check(lcb_createopts_credentials(create_options, username.c_str(), username.size(), password.c_str(), password.size()),
"assign credentials");
check(lcb_createopts_connstr(create_options, connection_string.c_str(), connection_string.size()), "assign connection string");
check(lcb_createopts_bucket(create_options, bucket_name.c_str(), bucket_name.size()), "assign bucket name");
lcb_INSTANCE* instance = nullptr;
check(lcb_create(&instance, create_options), "create lcb_INSTANCE");
check(lcb_createopts_destroy(create_options), "destroy options object");
check(lcb_connect(instance), "schedule connection");
check(lcb_wait(instance, LCB_WAIT_DEFAULT), "wait for connection");
check(lcb_get_bootstrap_status(instance), "check bootstrap status");
std::string key{ "airline_123" };
{
std::string value{ R"({"country":"Iceland", "callsign":"ICEAIR", "iata":"FI", "icao":"ICE", "id":123, "name":"Icelandair", "type":"airline"})" };
lcb_CMDSTORE* cmd = nullptr;
check(lcb_cmdstore_create(&cmd, LCB_STORE_UPSERT), "create UPSERT command");
check(lcb_cmdstore_key(cmd, key.c_str(), key.size()), "assign ID for UPSERT command");
check(lcb_cmdstore_value(cmd, value.c_str(), value.size()), "assign value for UPSERT command");
check(lcb_store(instance, nullptr, cmd), "schedule UPSERT command");
check(lcb_cmdstore_destroy(cmd), "destroy UPSERT command");
lcb_wait(instance, LCB_WAIT_DEFAULT);
}
lcb_install_callback(instance, LCB_CALLBACK_SDLOOKUP, reinterpret_cast<lcb_RESPCALLBACK>(sdget_callback));
{
SubdocResults results;
lcb_SUBDOCSPECS* specs = nullptr;
check(lcb_subdocspecs_create(&specs, 1), "create SUBDOC operations container");
std::vector<std::string> paths{
"name",
};
check(lcb_subdocspecs_get(specs, 0, 0, paths[0].c_str(), paths[0].size()), "create SUBDOC-GET operation");
lcb_CMDSUBDOC* cmd = nullptr;
check(lcb_cmdsubdoc_create(&cmd), "create SUBDOC command");
check(lcb_cmdsubdoc_key(cmd, key.c_str(), key.size()), "assign ID to SUBDOC command");
check(lcb_cmdsubdoc_specs(cmd, specs), "assign operations to SUBDOC command");
check(lcb_subdoc(instance, &results, cmd), "schedule SUBDOC command");
check(lcb_cmdsubdoc_destroy(cmd), "destroy SUBDOC command");
check(lcb_subdocspecs_destroy(specs), "destroy SUBDOC operations");
lcb_wait(instance, LCB_WAIT_DEFAULT);
check(results.status, "status of SUBDOC operation");
std::size_t idx = 0;
for (const auto& entry : results.entries) {
if (entry.status == LCB_SUCCESS) {
std::cout << "New Document name: " << (entry.value.empty() ? "(no value)" : entry.value) << "\n";
} else {
std::cout << "code=" << lcb_strerror_short(entry.status) << "\n";
}
++idx;
}
}
lcb_destroy(instance);
return 0;
}
Stay ahead of tomorrow’s database challenges
Challenge 1
Rigid data models slow down dev cycles
Legacy databases
- Rigid data models make agile development difficult
- Application objects are split into tables and need to be reassembled
Couchbase
- JSON data supports agile development through flexible data models
- Application objects can be directly serialized or deserialized
Challenge 2
Apps perform poorly
Legacy databases
- Relational modeling often requires a high number of writes and reads
- No built-in managed cache available
Couchbase
- Caching delivers highly responsive user experiences and lower latency
- Built-in managed cache provides sub-millisecond latency
Challenge 3
New functionality requires new tools
Legacy databases
- Bolted on tools and time-consuming integrations are required to handle caching, analytics, eventing, and mobile syncing
- Data access is limited to only SQL
- More bolt-ons equal more work and more maintenance
Couchbase
- Delivers the familiarity of SQL (with SQL++)
- Provides multi-model capabilities (full-text search, query, key/value, analytics, and more, all on the same data set)
- Automatically syncs your mobile and edge data in real time
Challenge 4
It’s hard to scale deployments with HA
Legacy databases
- Optimized for single server deployments and expensive vertical scaling
- Horizontal scaling is expensive and difficult
- Upgrades and maintenance equal downtime equal 2 a.m. weekend office hours
Couchbase
- Core distributed data architecture
- Masterless, shared-nothing automatic horizontal scaling
- No shard or partition keys to manage
- Automatic replication
- Automatic failover recovery and rebalancing
- Maintenance and upgrades don't require downtime