In this tutorial, you will learn how to use Key Value operations to create, read, update and delete documents and how to use the CAS value to identify the current state of an item.
Key Value (also known as the Couchbase Data Service) offers the simplest way to retrieve or mutate data where you know the key. A key-value store is a type of NoSQL Database that uses a simple method to store data as a collection of key-value pairs in which a key serves as the unique identifier.
The core interface to Couchbase Server is simple KV operations on full documents. Make sure you’re familiar with the basics of authorization and connecting to a Cluster from the Start Using the SDK Section. We’re going to expand on the short Upsert example we used there, adding options as we move through the various CRUD operations. Here is the Insert operation at its simplest:
# Insert document
document = {"foo": "bar", "bar": "foo"}
result = collection.insert("document-key", document)
cas = result.cas
Options may be added to operations. It is best practice to use the *Options() class that matches the name of the operation (e.g. GetOptions(), InsertOptions(), etc.). However, keyword arguments can be used as an override to a corresponding value within the options. Options like timeout and expiry are timedelta objects.
# Insert document with options
document = {"foo": "bar", "bar": "foo"}
opts = InsertOptions(timeout=timedelta(seconds=5))
result = collection.insert("document-key-opts",
document,
opts,
expiry=timedelta(seconds=30))
Expiration sets an explicit time to live (TTL) for a document. We’ll discuss modifying Expiration
in more details below. For a discussion of item (Document) vs Bucket expiration, see the Expiration Overview page.
Using the get()
method with the document key, we can fetch the document:
result = collection.get("document-key")
print(result.content_as[dict])
Timeout can also be set:
opts = GetOptions(timeout=timedelta(seconds=5))
result = collection.get("document-key", opts)
print(result.content_as[dict])
An upsert operation inserts the document into a collection if they do not already exist, or updates them if they do.
content = {"foobar": "barfoo"}
result = cb_coll.upsert("document-key", content)
updated_doc = cb_coll.get("document-key")
upserted_doc = updated_doc.content
print(f"Upserted Document: {upserted_doc}")
document = {"foo": "bar", "bar": "foo"}
result = cb_coll.upsert("document-key-1", document)
# fetch the new document
inserted_doc = cb_coll.get("document-key-1")
upserted_doc = inserted_doc.content
print(f"Upserted Document: {upserted_doc}")
When removing a document, you will have the same concern for durability as with any additive modification to the Bucket:
# remove document with options
result = collection.remove(
"document-key",
RemoveOptions(
cas=12345,
durability=ServerDurability(
Durability.MAJORITY)))
To replace a document…
result = cb_coll.get("document-key")
print(f"Document Before Replace: {result.content}")
document = {"foo": "bar", "bar": "foo"}
result = cb_coll.replace("document-key", document)
result = cb_coll.get("document-key")
print(f"Document After Replace: {result.content}")
Writes in Couchbase are written to a single node, and from there the Couchbase Server will take care of sending that mutation to any configured replicas. The optional durability parameter, which all mutating operations accept, allows the application to wait until this replication (or persistence) is successful before proceeding.
The SDK exposes three durability levels:
The options are in increasing levels of safety. Note that nothing comes for free - for a given node, waiting for writes to storage is considerably slower than waiting for it to be available in-memory.
# Upsert with Durability level Majority
# The tradeoffs associated with durability levels may not be apparent in this example
# since we are using a single node cluster, but become much more clear on multi-node clusters
# The error is due to the single node setup
from couchbase.collection import UpsertOptions
from couchbase.durability import Durability, ServerDurability
document = dict(foo="bar", bar="foo")
opts = UpsertOptions(durability=ServerDurability(Durability.MAJORITY))
try:
result = cb_coll.upsert("document-key", document, opts)
except Exception as e:
print(e)
It is possible to perform scoped key-value operations on named Collections with Couchbase Server release 7.0. See the API docs for more information. Here is an example showing an upsert in the users
collection, which lives in the travel-sample.tenant_agent_00 keyspace
:
agent_scope = bucket.scope("tenant_agent_00");
users_collection = agent_scope.collection("users");
content = {"name": "John Doe", "preferred_email": "johndoe111@test123.test" }
result = users_collection.upsert("user-key", content);
The CAS is a value representing the current state of an item. Each time the item is modified, its CAS changes.
The CAS value itself is returned as part of a document’s metadata whenever a document is accessed. In the SDK, this is presented as the cas field in the result object from any operation which executes successfully.
CAS is an acronym for Compare And Swap, and is a form of optimistic locking. The CAS can be supplied as parameters to the replace and remove operations. When applications provide the CAS, server will check the application-provided version of CAS against the CAS of the document on the server: