CouchDB for PHP developers – CRUD

Apache CouchDB™ commonly referred to as just CouchDB is an open source NoSQL database that uses JSON for storing data in form of documents, JavaScript as its query language using MapReduce queries, and regular HTTP for an API.
There is an excellent, free book called CouchDB The Definitive Guide available online at http://guide.couchdb.org. If you haven’t read it, I strongly advise doing so.
Working with JavaScript Object Notation (aka JSON) in PHP is a breeze. The best thing about JSON in PHP is that there is no required installation of external libraries needed, as JSON support is part of the PHP core:
- json_decode – Decodes a JSON string
- json_encode – Returns the JSON representation of a value
When it comes to API communication through HTTP, you are also pretty well covered here. PHP supports libcurl, a library that allows you to connect and communicate to many different types of servers with many different types of protocols. Among other protocols, libcurl supports supports http and https. cURL functions is probably more familiar term for this. Although this is such a frequently used library, some servers might not have it installed, so be sure to check if cURL is installed (for example, function_exists(‘curl_version’)).
The Futon
Another great thing about CouchDB is that it comes with a native web-based interface built into it, sort of like phpMyAdmin for MySQL. This interface is called Futon. It provides a basic interface to the majority of the functionality, including the ability to create, update, delete and view documents and views. Reason why we are bringing this up, is to that you can check the results of all of the API calls we have run so far. For more information on Futon itself, check out the official documentation page http://docs.couchdb.org/en/latest/intro.html#using-futon.
You should be able to access Futon via the following URL http://127.0.0.1:5984/_utils/.
So now that we have a support JSON handling, HTTP communication and a interface to check our results, we can move on with some practical examples.
Note: In most of the following examples, I am assuming that you used the Futon to set the username/password on a database. If you haven’t, you can comment out the line of code with CURLOPT_USERPWD.
Now, lets jump on to some practical examples.
Check if CouchDB is running
You can check if CouchDB is running just by executing HTTP GET request at http://127.0.0.1:5984 URL. If all is OK, you should be able to see a “Welcome” message as a part of larger JSON object.
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1:5984/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
$response = curl_exec($ch);
curl_close($ch);
/* JSON string
{
"couchdb": "Welcome",
"uuid": "fd53dde57b4f2ead04267c54139358a7",
"version": "1.3.1",
"vendor": {
"version": "1.3.1",
"name": "The Apache Software Foundation"
}
}
*/
Get a list of databases
Try not to get confused with terminology “CouchDB” vs “databases”. CouchDB is a database management system (DMS), which means it can hold multiple databases. A database is a bucket that holds “related data”, such as products.
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1:5984/_all_dbs');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
$response = curl_exec($ch);
curl_close($ch);
/*
string(36) "["_replicator","_users","products"] "
*/
Create a database
In this example we will create an empty database called customers. For this, we need to use HTTP PUT request.
<?php
$table = ‘customers’;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1:5984/'.$table);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, 'myDBusername:myDBpass');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
$response = curl_exec($ch);
curl_close($ch);
/*
string(12) "{"ok":true} "
*/
Get an UUID from CouchDB
If you find it impractical to generate your own UUID’s, you can ask CouchDB to give you one. If you need more than one UUID, you can pass in the ?count=5 HTTP parameter to request 5 UUIDs, or any other number you need.
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1:5984/_uuids');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
curl_setopt($ch, CURLOPT_USERPWD, 'myDBusername:myDBpass');
$response = curl_exec($ch);
$_response = json_decode($response, true);
$UUID = $_response['uuids'];
curl_close($ch);
/*
$UUID: string(32) "c2449e8c6cb8cb938ee507e281003348"
*/
Create a document
To create new document you can either use a POST operation or a PUT operation.
In this example we are creating a document (an entry, a row, a record) within the customers database.
Each document in CouchDB has an ID. This ID is unique per database. You are free to choose any string to be the ID, although CouchDB recommends a UUID (or GUID). In the example above I showed you how to fetch the UUID from CouchDB itself. Since ID is a required parameter that needs to be passed with create a document request, we can either:
request it from CouchDB
use some other unique string for it.
For our customers table, we will use username field for ID as shown in the example below. Please note that this is not the best decision, as it is recommended to use the UUID for ID. However, for the sake of simplicity and easier overview we will use username.
<?php
$ch = curl_init();
$customer = array(
'firstname' => 'Branko',
'lastname' => 'Ajzele',
'username' => 'ajzele',
'email' => 'branko.ajzele@example.com',
'pass' => md5('myPass123')
);
$payload = json_encode($customer);
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1:5984/customers/'.$customer['username']);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); /* or PUT */
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
curl_setopt($ch, CURLOPT_USERPWD, 'myDBusername:myDBpass');
$response = curl_exec($ch);
curl_close($ch);
/*
string(69) "{"ok":true,"id":"ajzele","rev":"1-c3fde3a56fe3c3490448a8e34166b4ec"} "
*/
Get a document
To retrieve a document, simply perform a GET operation at the document’s URL like shown below. Here we are using $documentID = ‘ajzele’; to fetch the document we just created in previous example.
<?php
$ch = curl_init();
$documentID = 'ajzele';
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1:5984/customers/'.$documentID);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
curl_setopt($ch, CURLOPT_USERPWD, 'myDBusername:myDBpass');
$response = curl_exec($ch);
curl_close($ch);
/*
string(200) "{"_id":"ajzele","_rev":"1-c3fde3a56fe3c3490448a8e34166b4ec","firstname":"Branko","lastname":"Ajzele","username":"ajzele","email":"branko.ajzele@example.com","pass":"433484b5317340f5c28e085bfffc78be"} "
*/
Update existing document
Note the _rev value 1-c3fde3a56fe3c3490448a8e34166b4ec in Create a document example. Prefix 1 means first revision. If you try to execute the same create a document request multiple times, you would get Document update conflict. error message. This is because CouchDB sees your request as update. If you want to update or delete a document, CouchDB expects you to include the _rev field of the revision you wish to change. When CouchDB accepts the change, it will generate a new revision number.
In order to update our previously create document, we need to pass it the _rev number we got from CouchDB when we created the document. Below is an example of such request, note how it is almost identical.
<?php
$ch = curl_init();
$customer = array(
'firstname' => 'Branko_2',
'lastname' => 'Ajzele_2',
'username' => 'ajzele',
'email' => 'branko.ajzele@example.com',
'pass' => md5('myPass123')
);
$customer['_rev'] = '1-c3fde3a56fe3c3490448a8e34166b4ec';
$payload = json_encode($customer);
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1:5984/customers/'.$customer['username']);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); /* or PUT */
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
curl_setopt($ch, CURLOPT_USERPWD, 'myDBusername:myDBpass');
$response = curl_exec($ch);
curl_close($ch);
/*
string(69) "{"ok":true,"id":"ajzele","rev":"2-6a7e68954964a35d9415eb10142d17fc"} "
*/
Creating a document with attachment
CouchDB documents can have attachments. They can be any data (pdf, image, music, video…). It is important to know that attachments are added only to an existing documents. Process of adding an attachment is considered a document update. Since each document update requires a revision number, so does the process of adding attachment.
<?php
$ch = curl_init();
$database = 'customers';
$documentID = 'ajzele';
$revision = '2-6a7e68954964a35d9415eb10142d17fc';
$attachment = 'inkscape-0.48.4-1-win32.exe';
$repository = 'C:/Users/branko/Downloads/';
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$contentType = finfo_file($finfo, $repository.$attachment);
$payload = file_get_contents($repository.$attachment);
curl_setopt($ch, CURLOPT_URL, sprintf('http://127.0.0.1:5984/%s/%s/%s?rev=%s', $database, $documentID, $attachment, $revision));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
//curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: '.$contentType,
'Accept: */*'
));
curl_setopt($ch, CURLOPT_USERPWD, 'myDBusername:myDBpass');
$response = curl_exec($ch);
curl_close($ch);
/*
string(69) "{"ok":true,"id":"ajzele","rev":"3-4b53bf95181e2461cc4b417507cf1e45"} "
*/
Attachments are stored under the root _attachments key of a JSON document, in a form like shown below.
"_attachments": {
"inkscape-0.48.4-1-win32.exe": {
"content_type": "application/x-dosexec",
"revpos": 5,
"digest": "md5-4lZleB3ePMxCaF7QraQEQg==",
"length": 34702513,
"stub": true
},
"Magento_Community_1-7_User_Guide.zip": {
"content_type": "application/zip",
"revpos": 3,
"digest": "md5-j9E1m4ejrc7LtlRuKgq8cA==",
"length": 9034796,
"stub": true
}
}
Delete a document
To delete a document you need to perform a HTTP DELETE operation at the document’s location, passing the rev parameter with the document’s current revision.
<?php
$ch = curl_init();
$database = 'customers';
$documentID = 'ajzele';
$revision = '7-6f74f3f827fa594ef7bf3293490e5d79';
curl_setopt($ch, CURLOPT_URL, sprintf('http://127.0.0.1:5984/%s/%s?rev=%s', $database, $documentID, $revision));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Accept: */*'
));
curl_setopt($ch, CURLOPT_USERPWD, 'myDBusername:myDBpass');
$response = curl_exec($ch);
curl_close($ch);
/*
string(69) "{"ok":true,"id":"ajzele","rev":"8-80af68b3814813ebc57bb70e73b8524a"} "
*/
Interesting enough that the DELETE action, besides just deleting the document from database, also returns the increased revision number.
Summary
In this article we covered several basic but essential CRUD use cases, based on which you can start building your own application. Even doe there are already several PHP libraries out there available for working with CouchDB, we focused on doing the same with basic cURL as this is something every PHP developer should know how to do.
The next follow up article CouchDB for PHP developers – Searching/Querying will cover CouchDB Map/Reduce functions that we will use for Searching/Querying the database.
17 comments
Do we need to write all the field parameters in order to update the document. I mean to say, to update the last name only, we need to send the full Object along with the changes to reflect it??
not running even any of the function
can you help me, i want create bulk document whith this example, but i cant
class ….
Is there a link to the follow up article you mentioned on searching/querying… I was unable to get a hit on that with google or see it in your dev-talk feed… Thanks! Enjoyed this article.
Hi 🙂 can you help me? I use XAMPP on my Windows 7 O.S and I’ve just installed couchdb for windows.
How can I create a connection between xampp php and couchdb server?
i need help too
Nice blog…Very useful information is providing by ur blog.Very clear and helpful for beginners.
Hi!
Thanks for the tutorial!
It’s very helpful for beginners like me : )
HeadCouch – CouchDB PHP client
http://zinoui.com/blog/headcouch-couchdb-php-client
That is a PHP library written by me, for working with CouchDB. It requires PHP5.x and cURL.
Robert… it’s pretty easy to update a document w/ the wrapper I linked. Assuming that you have a “relax” object, it’s:
$document = $db->get_doc( whatever your id is );
$document[key to change’] = “value”;
$db->save($document);
How can I delete a single field in a document in couchdb with PHP.
Hi there …
if you want to update an document with other values with php … just do the following … get rev id firom the document … and change the value in the json array and put it up …
public function update_data($doc, $jsonkey, $jsonvalue) {
$resp = $this->couch->send(“GET”, “/somedb/”.$doc);
$arr = json_decode($resp, true);
$arr[$jsonkey] = $jsonvalue;
$update = json_encode($arr);
$this->couch->send(“PUT”, “/somedb/”.$doc, $update);
}
and here the class :
class CouchSimple {
function CouchSimple($options) {
foreach($options AS $key => $value) {
$this->$key = $value;
}
}
function send($method, $url, $post_data = NULL) {
$s = fsockopen($this->host, $this->port, $errno, $errstr);
if(!$s) {
echo “$errno: $errstr\n”;
return false;
}
$request = “$method $url HTTP/1.0\r\nHost: $this->host\r\n”;
if($post_data) {
$request .= “Content-Length: “.strlen($post_data).”\r\n\r\n”;
$request .= “$post_data\r\n”;
}
else {
$request .= “\r\n”;
}
fwrite($s, $request);
$response = “”;
while(!feof($s)) {
$response .= fgets($s);
}
list($this->headers, $this->body) = explode(“\r\n\r\n”, $response);
return $this->body;
}
}
https://github.com/barnjamin/relax/blob/master/relax.php is a simply PHP wrapper for Couchdb. It’s something that I use very frequently and handles a majority of things. There are a couple of errors in the repo that I’ll need to push out there, but nothing that isn’t easy to fix (e.g.: “Etag” vs “ETag”). If you’ve got and questions about using the wrapper, let me know.
is there an usage example somewhere? As small as it may be.. Looking for the way to properly initialise the class and basic usage of get/put..?
Not likely there will be a reply soon (thread from 2013?) so will post if I find out myself 😉
@MagePsycho
Thanks for the feedback.
Regarding the “CouchDB vs MongoDB”, we actually haven’t chose anything, if your asking us as company. Its just me personally playing with CouchDB 🙂 Reason why I like it slightly/tiny more than CouchDB is the HTTP/REST approach.
Regarding the possible PHP extension/wrapper class, yes there are plenty out there. None does not seem to be absolute #1, so I played with the basic cURL approach (given that every PHP developer should know how to handle it like that).
So basically this is just me playing/studying 🙂
Just wondering why you guys choose couchDB instead of MongoDB.
Also if it’s possible to use PHP extension or wrapper class for couchDB, it would be better.