CRUD Document Operations Using the PHP SDK with Couchbase Server

Operation Basics

Operations use basic PHP data types and most of the PHP data types that can be serialized via the JSON functions are supported by default. Recursive structures cannot be serialized. You may alternatively implement your own transcoders which modify the method by which your documents are serialized to Couchbase. See Transcoders for more details.

If an operation is successful, it will return CouchbaseMetaDoc that contains the value of the document (if returned by operation) as well as the cas value. If an operation fails, a CouchbaseException is thrown, which may then be caught.

Creating and Updating Full Documents

You can create documents by using the insert() or upsert() methods and update them using the replace() method. See Primitive Key-Value Operations for more details.

The following example shows how to create a new document with the insert() method:

$res = $myBucket->insert('document_name', array('some'=>'value'));

You can specify additional options as a third argument to the insert, upsert, and replace functions. The options are specified as an associative array:

$bucket->upsert($key, $doc, array("expiry" => 300));

Allowed options are:

  • cas: The CAS value for the document. If the CAS on the server does not match the CAS supplied to the method, the operation will fail with a CouchbaseException with a code of COUCHBASE_KEY_EEXISTS error. See Concurrent Document Mutations for more information on using the CAS values. Keep in mind that this case applies only to replace()

  • expiry: Specifies the expiry time for the document. If specified, the document will expire and no longer exist after the given number of seconds. See Expiration Overview for more information.

  • persist_to, replicate_to: Specifies durability requirements for the operations.

Retrieving Documents

You can retrieve documents by using the get() method.

var_dump($bucket->get("new_document"));

Sample output from the example is as follows:

object(CouchbaseMetaDoc)#6 (4) {
  ["error"]=>
  NULL
  ["value"]=>
  object(stdClass)#5 (1) {
    ["foo"]=>
    string(3) "bar"
  }
  ["flags"]=>
  int(33554438)
  ["cas"]=>
  string(9) "eh5m98g0k"
}

The get() method returns a CouchbaseMetaDoc object. To get the actual value, use the object’s value property. The CAS value is encoded as a string and accessible through cas property.

Items stored as associative arrays (such as $bucket->upsert(docid, array("prop1" => "value1")) are retrieved as PHP stdObject objects; you must reference fields using $result->value->property rather than $result->value["property"]

In some instances you may wish to read from a replica node when the active node is unavailable. This can be done using the getFromReplica().

Removing Documents

You can delete documents by using the remove() method.

$bucket->remove('document_name');

You may pass a second argument containing options to the remove() method. This is passed as an array with the option name as the key and the option value as the array value. Recognized options are:

  • cas: Specify the CAS value to use. This will ensure that the document is not removed if the CAS value differs. You may obtain the CAS value from CouchbaseMetaDoc::cas, as a return value of a successful operation.

  • persist_to, replicate_to: Specify durability requirements. In this case, the SDK will check that the items have been properly deleted from the replicas.

Modifying the Expiration

Setting Document expiration can be performed using the touch() and getAndTouch methods. These methods accept an expiry value as their second parameter:

$cb->upsert('expires', "i'm getting old...", array("expiry" => 5));
sleep(6)
$cb->get('expires');
PHP Fatal error:  Uncaught exception 'CouchbaseException' with message 'LCB_KEY_ENOENT: The key does not exist on the server' in [CouchbaseNative]/CouchbaseBucket.class.php:196
Stack trace:
#0 [CouchbaseNative]/CouchbaseBucket.class.php(196): _CouchbaseBucket->get('expires', Array)
#1 /private/tmp/dummy.php(7): CouchbaseBucket->get('expires')
#2 {main}
  thrown in [CouchbaseNative]/CouchbaseBucket.class.php on line 196

Document expiration can also be set using the upsert family of methods which accept an optional expiry key in their options arrays.

Batching Operations

Bulk operations may help you perform operations more efficiently and quicker by optimizing how commands are sent on the network.

Bulk operations may be performed by passing an array as the first argument to one of the get(), upsert(), insert(), replace() and other key-value methods.

When these methods are passed an array as input, they return an array as output, with the array containing document IDs as its keys and their respective CouchbaseMetaDoc objects as values.

This method works identically to its singular counterpart but instead accepts an array of keys to retrieve and returns an object where the object key matches your document ID and the object value is the result that you would normally expect to see from a singular operation.

For the upsert() family of methods, the top-level array value is a container for options. The most important option is value which contains the actual value to be used as the document.

The following example shows how to insert and retrieve multiple documents. The structure of each document is:

{
    "email": <....>
}
Storing multiple documents
$results = $bucket->upsert(array(
    'foo' => array('value' => array('email' => 'foo@foo.com')),
    'bar' => array('value' => array('email' => 'bar@bar.com')),
    'baz' => array('value' => array('email' => 'baz@baz.com'))
    ));
foreach ($results as $docid => $metadoc) {
    echo("$docid => $metadoc->cas\n");
}
Output
foo => 2gywu3yq6s
bar => 2hcxy0srv8
baz => 2hcxy0srv8
Retrieving multiple documents
$results = $bucket->upsert(array("foo", "bar", "baz"));
    foreach ($results as $docid => $metadoc) {
    // Each document itself has a 'propname'
    echo "Result for $docid\n";
    var_dump($metadoc->value);
    echo "\n";
}
Output
Result for foo
object(stdClass)#7 (1) {
  ["email"]=>
  string(11) "foo@foo.com"
}

Result for bar
object(stdClass)#9 (1) {
  ["email"]=>
  string(11) "bar@bar.com"
}

Result for baz
object(stdClass)#11 (1) {
  ["email"]=>
  string(11) "baz@baz.com"
}

Atomic Operations

The PHP Couchbase SDK supports several operations that allow one-step, atomic changes to documents. These operations include counter, prepend, and append functions.

The counter() method enables you to use an atomic counter. The first argument is the document ID, and the second argument is the delta indicating by what amount the counter should be changed. You may also pass an array of options as the third argument:

$result = $bucket->counter('counterId', 50, array('initial' => 100));
echo 'Current counter value is ' . $result->value . "\n";

Atomic byte concatenations can be performed using the append() and prepend() methods. These operations are potentially destructive. Refer to the API documentation for more information.

Operating with sub-documents

Sub-Document API is available starting Couchbase Server version 4.5. See Sub-Document Operations for an overview.

Sub-document operations save network bandwidth by allowing you to specify paths of a document to be retrieved or updated. The document is parsed on the server and only the relevant sections (indicated by paths) are transferred between client and server. You can execute sub-document operations in the PHP SDK using the retrieveIn, lookupIn, and mutateIn methods.

Each of these methods accepts an id as its mandatory first argument and return builders CouchbaseLookupInBuilder and CouchbaseMutateInBuilder

The builders have API to accumulate command specifications and run the full pipeline by the execute() call.

$res = $bucket->lookupIn('docid')
              ->get('path.to.get')
              ->exists('check.path.exists')
              ->execute();

$res = $bucket->mutateIn('docid')
              ->upsert('path.to.upsert', $value, true)
              ->remove('path.to.del')
              ->execute();

For simply retrieving a list of paths, you may use the retrieveIn convenience method:

$res = $bucket->retrieveIn('docid', 'path1', 'path2', 'path3')

All sub-document operations return a special CouchbaseDocumentFragment object. In contrast with a normal CouchbaseMetaDoc object, a CouchbaseDocumentFragment object contains multiple results with multiple statuses, one result/status pair for every input operation. You can access an individual result/status pair by addressing the value of CouchbaseDocumentFragment object as a mapping, and then using index position of the operation as the key:

$res = $bucket->lookupIn('docid')
              ->get('foo')
              ->exists('bar')
              ->exists('baz')
              ->execute();

# First result
$res->value[0]

Non-JSON Documents and Transcoders

See Non-JSON Documents for a general overview of using non-JSON documents with Couchbase

All PHP objects which can be represented as JSON may be passed unmodified to a storage function, and be received via the get method without any additional modifications, with only note that by default JSON encoder configured to produce stdClass instances instead of arrays. This behavior can be changed by modifying $COUCHBASE_DEFAULT_DECOPTS:

echo("default JSON decoder options: ");
var_dump($COUCHBASE_DEFAULT_DECOPTS);

$res = $bucket->get('foo');
var_dump($res->value);

echo("setting 'jsonassoc' to true\n");
$COUCHBASE_DEFAULT_DECOPTS['jsonassoc'] = true;

$res = $bucket->get('foo');
var_dump($res->value);

Output:

default JSON decoder options: array(1) {
  ["jsonassoc"]=>
  bool(false)
}
object(stdClass)#4 (1) {
  ["email"]=>
  string(11) "foo@foo.com"
}
setting 'jsonassoc' to true
array(1) {
  ["email"]=>
  string(11) "foo@foo.com"
}

You can modify the default JSON encoders used by the PHP SDK using the setTranscoders function. This function accepts a pair of encode and decode functions which are expected transform the raw document depending on the document flags.

The following is an example of a transcoder which will unconditionally transcode all documents as UTF-8 encoded JSON documents.

$bucket->setTranscoders(
  function($value) {
    return array(json_encode($value), 0, 0);
  },
  function($value, $flags, $datatype) {
    return json_decode($value, true);
  }
);

To make migration from 1.x SDK easier, use the JSON serializer. You may do this with settings in php.ini:

; make sure that the JSON extension is loaded before couchbase
extension=json.so
extension=couchbase.so
; select default serializer
couchbase.serializer = json

Also, the serializer may be selected programmatically:

$bucket = new Couchbase("localhost:8091", "", "", "default");
$bucket->setOption(COUCHBASE::OPT_SERIALIZER, COUCHBASE::SERIALIZER_JSON);