One of the biggest barriers for anyone who wants to start using new technologies is usually the learning curve. Often while starting a new project, we end up choosing to use what we already know to avoid any friction right at the beginning of the project.

I have spent most of my career working as a Java developer, and in the last few years I fell in love with the JPA + Spring-Boot + Lombok + Spring Data combination, but the one thing that still annoyed me was mapping relationships.

JPA is known for loading unnecessary data from the database, and over time you are forced to revisit some of your entities to change a few relationships from EAGER to LAZY. It can improve significantly your performance as you will avoid a lot of unnecessary JOINS but it does not come for free. You will be required to do a lot of refactoring to load those new lazy objects whenever they are required.

This common pattern always bothered me and I was really happy when I found that Couchbase has a connector for Spring Data (full doc here). It is simply the best part of two worlds, I can program like I would in a relational database but still leveraging all the speed of Couchbase and the power of N1QL. Let’s see how to setup a simple project:


Setting-up Couchbase with Spring Boot and Spring Data



  • I will assume that you already have Couchbase installed, if you don’t, please download it here
  • I am also using Lombok, so you might need to install Lombok’s plugin on your IDE: Eclipse and IntelliJ IDEA


First, you can clone my project:

or simply go to Spring-Boot Initialzr and add Couchbase and Lombok as dependencies:

Note: Lombok is not a required dependency, but it helps to reduce significantly your code base.


Now, let’s define your bucket configuration in the file:

And that’s it! You are already able to start up your project using:


Mapping an Entity

So far, our project does not do anything. Let’s create and map our first entity:


    • @Document: Couchbase’s annotation which defines an entity, similar to @Entity in JPA. Couchbase will automatically add a property called _class in the document to use it as the document type.
    • @Data:  Lombok’s annotation, auto-generate getters and setters
    • @AllArgsConstructor: Lombok’s annotation, auto-generate a constructor using all fields of the class, this constructor is used in our tests.
    • @NoArgsConstructor: Lombok’s annotation, auto-generate a constructor with no args (required by Spring Data)
    • @EqualsAndHashCode: Lombok’s annotation, auto-generate equals and hashcode methods, also used in our tests.
    • @NotNull: Yes! You can use javax.validation with Couchbase.
    • @Id: The document’s key
    • @Field:  Couchbase’s annotations, similar to @Column


Mapping entities in Couchbase is really simple and straightforward, the biggest difference here is the @Field entity which is used in 3 different ways:

  • Simple property: In cases like id, name and companyId, the @Field acts pretty much like the @Column in JPA.  It will result in a simple property in the document:

  • Arrays: In the phoneNumbers’s case it will result in an array inside the document:

  • Entities: Finally, in the areas’s case, @Field acts like a @ManyToOne relationship, the main difference is that you are not required to map anything in the Area entity:




Your repositories will look very similar to standard Spring Data repositories but with a few extra annotations:


  • @N1qlPrimaryIndexed: This annotation makes sure that the bucket associated with the current repository will have a N1QL primary index
  • @ViewIndexed:  This annotation lets you define the name of the design document and View name as well as a custom map and reduce function.

In the repository above, we are extending CouchbasePagingAndSortingRepository, which allows you to paginate your queries by simply adding a Pageable param at the end of your method definition

As it is essentially a repository, you can leverage all Spring Data keywords like FindBy, Between, IsGreaterThan, Like, Exists, etc. So, you can start using Couchbase with almost no previous knowledge and still be very productive.

As you might have noticed, you can create full N1QL queries but with a few syntax-sugars:

  • #(#n1ql.bucket):  Use this syntax avoids hard-coding your bucket name in your query
  • #{#n1ql.selectEntity}: syntax-sugar to SELECT * FROM #(#n1ql.bucket):  
  • #{#n1ql.filter}: syntax-sugar to filter the document by type, technically it means class = ‘myPackage.MyClassName’ (_class is the attribute automatically added in the document to define its type when you are working with Couchbase on Spring Data )
  • #{#n1ql.fields} will be replaced by the list of fields (eg. for a SELECT clause) necessary to reconstruct the entity.
  • #{#n1ql.delete} will be replaced by the delete from statement.
  • #{#n1ql.returning} will be replaced by returning clause needed for reconstructing entity.

To demonstrate some of the cool capabilities of N1QL, let’s go a little deeper in two methods of our repository: findByPhoneNumber and findByCompanyAndAreaId:



In the case above we are simply searching for buildings by telephone numbers. In a relational world, you would normally need 2 tables to accomplish nearly the same thing. With Couchbase we can store everything in a single document, which makes loading a “building” much faster than what you would get using any RDBMS.

Additionally, you can speed up your query performance even more by adding an index on the phoneNumbers attribute.



In the query above we are basically trying to find the root node (Building) giving a random child node (Area). Our data is structured as a tree because an Area could also have a list of other areas:


This type of querying is one of the most expensive and complex operations when you are working with a relational database, in most of the cases you either find the root node by hand or using some big fat query with UNIONs and CONNECTED BYs.

Here you can solve this problem by using a magical keyword called WITHIN.



By default, you will inject and use your repositories in your Services like you normally would, but you can additionally access Couchbase’s specific repositories capabilities using the method getCouchbaseOperations()


Everything in Action


Using  services are to exactly what you would expect:


Check out the integration test class BuildingServiceIntegrationTest to see everything in action.

If you have any questions, tweet me at @deniswsrosa or ask a question on our forum


Posted by Denis Rosa, Developer Advocate, Couchbase

Denis Rosa is a Developer Advocate for Couchbase and lives in Munich - Germany. He has a solid experience as a software engineer and speaks fluently Java, Python, Scala and Javascript. Denis likes to write about search, Big Data, AI, Microservices and everything else that would help developers to make a beautiful, faster, stable and scalable app.