Search code examples
couchbaserx-javacouchbase-viewcouchbase-java-api

Do Couchbase reactive clients guarantee order of rows in view query result


I use Couchbase Java SDK 2.2.6 with Couchbase server 4.1.

I query my view with the following code

public <T> List<T> findDocuments(ViewQuery query, String bucketAlias, Class<T> clazz) {
    // We specifically set reduce false and include docs to retrieve docs
    query.reduce(false).includeDocs();
    log.debug("Find all documents, query = {}", decode(query));
    return getBucket(bucketAlias)
            .query(query)
            .allRows()
            .stream()
            .map(row -> fromJsonDocument(row.document(), clazz))
            .collect(Collectors.toList());
}

private static <A> A fromJsonDocument(JsonDocument saved, Class<A> clazz) {
    log.debug("Retrieved json document -> {}", saved);
    A object = fromJson(saved.content(), clazz);
    return object;
}

In the logs from the fromJsonDocument method I see that rows are not always sorted by the row key. Usually they are, but sometimes they are not.

If I just run this query in browser couchbase GUI, I always receive results in expected order. Is it a bug or expected that view query results are not sorted when queried with async client? What is the behaviour in different clients, not java?


Solution

  • This is due to the asynchronous nature of your call in the Java client + the fact that you used includeDocs.

    What includeDocs will do is that it will weave in a call to get for each document id received from the view. So when you look at the asynchronous sequence of AsyncViewRow with includeDocs, you're actually looking at a composition of a row returned by the view and an asynchronous retrieval of the whole document.

    If a document retrieval has a little bit of latency compared to the one for the previous row, it could reorder the (row+doc) emission.

    But good news everyone! There is a includeDocsOrdered alternative in the ViewQuery that takes exactly the same parameters as includeDocs but will ensure that AsyncViewRow come in the same order returned by the view.

    This is done by eagerly triggering the get retrievals but then buffering those that arrive out of order, so as to maintain the original order without sacrificing too much performance.

    That is quite specific to the Java client, with its usage of RxJava. I'm not even sure other clients have the notion of includeDocs...