N1QL Queries Using the Java SDK with Couchbase Server

To issue N1QL queries, you should create a N1qlQuery object, and pass it to the query(N1qlQuery q) method in the Bucket class.
A few variants of such a query exist:

Simple queries, which are only strings and do not use placeholders;

Parameterized queries, which use numbered or named placeholders.

You can create each via the corresponding factory method on N1qlQuery, which you can create using a Statement produced by the N1QL DSL or using the statement directly as a String.

The return value from query() is the object N1qlQueryResult.
Iterating over the object will yield the rows returned by the server for the given query (as N1qlQueryRow).
Each row represents a row received for the query.

Additionally, you can get the List<N1qlQueryRow> from the allRows() method on the result.
Note that errors returned by the N1QL service during execution are represented as JsonObject accessible through the errors() method, rather than exceptions.
Here is the complete list of N1qlQueryResult methods:

parseSuccess: Returns true if the query could be parsed correctly.
This information is available immediately even if the actual list of results takes more time to be computed and streamed to the client.

finalSuccess: Returns true if the whole query could be executed successfully, including retrieving all the results and streaming them to the client.

allRows: Contains all rows returned by the query; it can be an empty list.

rows: Same as allRows but in an iterator form (the N1qlQueryResult itself is iterable).

requestId: The server-generated unique ID for this query (useful to find associated logs on the N1QL server).

clientContextId: User-provided identifier reflected in the server’s response.
The identifier can be useful for grouping several queries (for example, in a kind of in-house transaction) and find all associated queries.

info: Returns a N1qlMetrics object, which contains metrics for the query (such as the number of results or processing time).

errors: Returns a list of JsonObject describing errors or warnings (if any occurred during execution).

Each N1qlQueryRow exposes the JSON representation of the value() as a JsonObject.
It also gives the raw bytes for said value (byteValue()), in case you need them to apply your deserialization or SELECT RAW is used which cannot be turned into a JsonObject.

You can use N1QL placeholders in the query.
Placeholders allow you to specify variable constraints for an otherwise constant query.
A named or positional parameter is a placeholder for a value in the WHERE, LIMIT or OFFSET clause of a query.
To use placeholders, manually construct a N1QLQuery object with the base query string, and use a JsonObject of names -> keyword or a JsonArray of positional arguments for named or positional placeholders, respectively:

To construct statements, you can use the Expression class that comes in with a variety of factory methods to construct both tokens and literals programmatically.
Expressions can be combined and chained with operators (like gte for "greater than or equal to" comparison).

Use x to construct a token, s to construct a string literal, i to construct a token escaped with backticks (for example, the bucket name beer-sample must be escaped because it contains a dash).

If you find out that the DSL doesn’t support a particular statement, clause or keyword, you can always revert to providing your statement in plain String form.
Using the String form ensures that even if the DSL lags behind the evolutions of the language, users will always have a mean of using new language features.

Querying Asynchronously

To perform a query asynchronously, use the AsyncBucket interface that you obtain by calling bucket.async().
The API is pretty similar except everything is returned as an Observable.
Some of the components of the query result (an AsyncQueryResult) can also be delayed and so returned as Observables.
Only requestId, clientContextId and parseSuccess return immediately.

The following Java 8 code prints the found documents or errors as they come:

Second, line issues a Statement using the DSL (notice how "beer-sample" is escaped).

When receiving a result, first check if there are errors.
If there are any, the first one is converted to a CouchbaseException that will be propagated in the Observable.
If no errors are found (errors() is empty), switch to inspecting the rows, then map each received row to its JSON value.

Eventually, trigger the whole process by subscribing to the Observable you have built.
When a row JSON is received, print it; when an error is propagated, print the stack trace.

Note: All this is done asynchronously so it’s not suitable for a simple test (where the main thread would potentially exit before any result could have been displayed).

Long running Streaming Query

For a long-running N1QL query, you need a way of streaming the rows and correctly handling errors.
Use this helper function:

The corresponding mini-DSL are Case.caseSimple and Case.caseSearch.
Simple Case will compare the initial expression with each WHEN clause for equality, returning the corresponding THEN expression if a match is found.
Search Case allows for a different condition for each WHEN clause.

Let’s see two examples.
The first one could be used to map match results to a score:

The corresponding mini-DSL is Collections.arrayIn (or Collections.arrayWithin if you want to start with a WITHIN clause).
Let’s see two examples from the following statement, which extracts children and also lists the ones that are "teenagers":

SELECT tutorial.fname || ' ' || tutorial.lname AS adult,
ARRAY child FOR child IN tutorial.children END AS children,
ARRAY child.fname FOR child IN tutorial.children WHEN child.age >= 12 END AS teenagers
FROM tutorial WHERE tutorial.children IS NOT NULL;

In the previous example, you would see an entry for a parent that doesn’t have "teenagers" (its "teenagers" field would be empty), because the statement didn’t specify that the children should contain a "teenager".
You can fix that with ANY, by rewriting the WHERE clause: