As of Couchbase 2.0, you can index and query entries using views. Views are functions you define and use to filter, extract and perform calculations on entries that are persisted in a given data bucket. The functions you create will provide a 'map' function, which can filter/extract items based on rules you specify, and may optionally perform a 'reduce' function, which can perform calculations and operations across a selected group of entries. There are a few possible ways you can initially store and use views functions as JSON documents:
Create and manage using Couchbase Admin Console, or
Create and manage using the REST API, or
Create, store, and query using your chosen Couchbase SDK.
Since this content is for the developer audience, we will focus here on using the SDKs to perform queries and describe the REST API as an alternative approach.
Imagine in our previous example that we also want to find all the names of users who are under 21. In this scenario we would use a view; in fact we would want to use views in any other scenario where we want to filter entries based on certain field values, or provide lists and tables of certain entries. For this example we provide the map function for you. If you are more familiar with views in Couchbase 2.0, you may notice some missing elements in our map function. For the sake of brevity here and for newcomers to views, we omitted some of the complexity for now:
function (doc) { if ( doc.age && doc.name ) { if ( doc.age < 21 ) { emit(doc.name, doc.age) }; } }
You may not have used JavaScript before, but if you have used
other programming languages such as C, Java, or PHP, this should
look familiar to you. This is a standard function definition with
one parameter, doc which is a JSON document
stored in Couchbase Server.
The key part of this function to understand is the conditional
statement if (doc.age < 21 ) .... . This is
how you specify the core logic of your map function. In this case,
we are saying that if age field has a value
less than 21, we want information from that record extracted and
put in the result set. The next part of the code,
emit(doc.name, doc.age) indicates when
Couchbase Server finds a matching record, it should include value
from the name field and should include value
from the age field in the result set.
As a best practice we want make sure that the fields we want to
include in our index actually exist. Therefore we have our map
function within a conditional: if (doc.age &&
doc.name). This ensures the fields exist in documents
when we query the view and we therefore avoid a view failure when
Couchbase Server generates the index.
For the sake of convenience, we can store our view in a 'design document' and then use a Couchbase SDK to store it from the file. Design documents are JSON documents where we store our views functions as strings; they are stored in Couchbase Server and are associated with a Couchbase Bucket. First we create the design document and include our view function in it:
{ "_id": "_design/students", "language": "javascript", "views": { "underage": { "map": "function(doc) {if (doc.age && doc.name) {if(doc.age < 21){emit(doc.name, doc.age);}}}" } } }
The first two fields indicate the JSON document is a design
document named students and it follows the
syntax used in JavaScript. The next field is a hash that contains
any views and in this case we have one view called
underage. Within the view we provide the map
function described above. We can store this to the file system as
students.json and then write the design
document to Couchbase Server using an SDK.
As a best practice we want make sure that the fields we want to
include in our index actually exist. Therefore we have our map
function within a conditional: if (doc.age &&
doc.name). This ensures the fields exist in documents
when we query the view and we therefore avoid a view failure when
Couchbase Server generates the index.
client = Couchbase.connect("http://localhost:8091/pools/default/buckets/newBucket") client.save_design_doc(File.open('students.json'))
We open the students.json file and then write
it to Couchbase Server with the
save_design_doc call. Couchbase Server
will store a new design document with the key
students which is available from our SDK. At
this point we can query the view and retrieve matching results:
students = client.design_docs['students'] students.views #=> ["underage"] students.underage
The first things we do is retrieve the design document from
Couchbase Server. We do this by first calling
design_docs with the named design
document students, and then call
views to get the views it contains.
Finally we perform the query by calling the view, in this case we
call underage. Couchbase Server will
execute the map function in our view and return this information
in the result set:
.... @id="doc1" @key="Aaron" @value=20 .... .... @id="doc3" @key="Peter" @value=16 .... .... @id="doc4" @key="Ralf" @value=12 ....
If you go back and look at our map function, we indicate we want
to extract doc.name and
doc.age. Couchbase Server provides the key for
the document containing a matching field value under 21, which is
docNum, as well as the name and age of the
student. As an alternate approach, you can also store a view in
Couchbase Server by using the REST API and then query it using a
REST request. To store the view, you would make a REST request as
follows:
curl -X PUT -u newBucket:password -H 'Content-Type: application/json' \ 'http://server_ip:8092/newBucket/_design/students' \ -d '{"views": {"underage":{"map":"function(doc) {if(doc.age && doc.name) \ {if(doc.age<21){emit(doc.name, doc.age);}}}"}}}'
We perform the REST request as a put and provide the bucket name
and password for that bucket. We indicate the content will be
JSON, and the rest endpoint is the Couchbase bucket along with
/_design/students. Finally we provide the view
as the request payload. After Couchbase Server successfully stores
the new design document students with the
underage view, it provides a response in JSON:
{"ok":true, "id":"_design/students"}Now we can query the view by performing a REST request as follows:
curl -X GET -u newBucket:password 'http://server_ip:8092/newBucket/_design/students/_view/underage?'Couchbase Server responds with the following results as JSON:
{"total_rows":3,"rows":[ {"id":"doc1", "key":"Aaron", "age":20}, {"id":"doc3", "key":"Peter", "age":16}, {"id":"doc4", "key":"Ralf", "age":12} ] }
This section is intended as a brief introduction to querying and indexing JSON documents with Couchbase SDKs. There is definitely much more to learn about the topic. For more detailed information about the topic, see Chapter 4, Finding Data with Views for using views with the SDKs, and Couchbase Server Manual, Views and Indexes for understanding indexing and querying in general with Couchbase Server 2.0.