Reactive Java: Different flavors of querying the Couchbase using Spring Web Flux Reactive Couchbase API

Reading Time: 3 minutes

As I am exploring Spring Web flux these days so I got an opportunity to explore the different ways of interacting with couch base using reactive APIs. We will not discuss how we can make a crud application in Spring Web flux. My main focus will be on, in how many different ways, we can query the couchbase with reactive couchbase API in Spring Web flux. So let’s start.

I will be showing 3 different ways of querying the couchbase:

  1. Using auto-generated methods
  2. Using @Query annotation
  3. Using Joins

Using auto-generated methods:

I am using UserRespository here.

public interface UserRepository extends ReactiveCouchbaseRepository<User, String> {

    Mono<User> findByFirstNameAndCity(String firstName, String city);

As the repository interface extends the ReactiveCouchbaseRepository, we get the autogenerated methods to query the document on the basis of the defined model’s fields.

As you can see in UserRepository, findByFirstNameAndCity is an auto-generated method which will return a single document on the basis of FirstName and City. You will get more such methods.

Using @Query annotation:

Sometimes, we get the use case where the auto-generated method doesn’t fit. In these scenarios, we can use @Query annotation where we can provide our custom query and can get query the document.

public interface ClubMemberProfileRepository extends ReactiveCouchbaseRepository<ClubMemberProfile, String> {

    @Query("select META().id AS _ID, META().cas AS _CAS, * from #{#n1ql.bucket} where clubCode = $1 and joiningDate = $2")
    Flux<ClubMemberProfile> getClubMembers(String clubCode, String joiningDate);

    @Query("select clubCode from #{#n1ql.bucket} where location = $1 and brand = $2")
    Flux<String> getAllClubCodes(String location, String brand);


getClubMembers: This method is for getting all documents based on the where clause.

getAllClubCodes: This method is just to get all the club code based on the where clause.

You would have a question here that in getClubMembers(), what is the use of _ID and _CAS. So the answer is: If we do not add this _ID and _CAS, we get the following exception:

Unable to retrieve enough metadata for N1QL to entity mapping, have you selected _ID and _CAS?; nested exception is rx.exceptions.OnErrorThrowable$OnNextValue: OnError while emitting onNext value:

So, to avoid the above exception we need to add _ID and _CAS in the query.

There is one more use case where we would require to use @Query annotation.

When we add any document using spring reactive couchbase API, then an extra field which is _class gets added in the document which is generally used to deserialize the document. See below the User document:

“firstName”: “Virat”,
“lastName”: “Kohli”,
“_class”: “com.knoldus.couchbase.model.User”,
“phone”: “123”,
“userId”: “c1”

But when we use a non-reactive couch base API, then it does not get added.

So we can have 2 types of data: 1) with _class field and 2) without _ class field,

Also, when we query the document from the reactive couch base API with auto-generated methods, then it expects the _class field to be in the document. If it is not there, then reactive couchbase API is not able to deserialize the document and returns nothing.

So in this particular use case, to handle both types of data, we would require to use @Query annotation where we would write our query and then we would be able to get the result.

Using Joins

This is not a different way of a query actually, I just want to show here that how we can apply joins in couchbase.

This is not different than SQL. It’s just we need to provide the join query in @Query annottaion. That’s it.

public interface ClubDataRepository extends ReactiveCouchbaseRepository<ClubData, String> {

    String query = "select cmp.clubCode, cmp.joiningDate, cmp.userId, u.firstName, u.lastName," +
            " META(cmp).id AS _ID, META(cmp).cas AS _CAS from #{#n1ql.bucket} cmp" +
            " INNER JOIN #{#n1ql.bucket} u on KEYS cmp.userId" +
            " where cmp.clubCode = $1 and cmp.joiningDate = $2";

    Flux<ClubData> getClubData(String clubCode, String joiningDate);

The above query is the example of joins in couchbase. I have applied Join on u (User) and cmp (ClubMemberProfile) document on the basis of document id of User and userId of ClubMemberProfile where clubCode and joinindDate should be matched with the given values.

There are a few things to notice that:

  • I have used #{#n1ql.bucket} here which actually will read the bucket name from the couchbase configuration. You do not need to provide it explicitly.
  • I have used META(cmp).id AS _ID, META(cmp).cas AS _CAS here. It is for the same reason which we have already discussed above (to avoid the exception)
  • To get the variable’s value, I have used $1 and $2. $1 is for clubCode and $2 is for joiningDate.

That’s it for now. I will be sharing more information in further blogs whenever I will get some useful things. Full code, you can get here.

I hope, this blog will help you to understand the Spring Reactive couchbase API more


Written by 

Rishi is a tech enthusiast with having around 10 years of experience who loves to solve complex problems with pure quality. He is a functional programmer and loves to learn new trending technologies. His leadership skill is well prooven and has delivered multiple distributed applications with high scalability and availability by keeping the Reactive principles in mind. He is well versed with Scala, Akka, Akka HTTP, Akka Streams, Java8, Reactive principles, Microservice architecture, Async programming, functional programming, distributed systems, AWS, docker.