Spring Data Couchbase

Spring Data for Couchbase is part of the umbrella Spring Data project which aims to provide a familiar and consistent Spring-based programming model for new datastores while retaining store-specific features and capabilities.

Quick Start
Fork me on GitHub

The Spring Data Couchbase project provides integration with the Couchbase Server database. Key functional areas of Spring Data Couchbase are a POJO centric model for interacting with Couchbase Buckets and easily writing a Repository style data access layer.

Features

  • Spring configuration support using Java based @Configuration classes or an XML namespace for the Couchbase driver (Java SDK version 2.x).
  • CouchbaseTemplate helper class that increases productivity performing common Couchbase operations. Includes integrated object mapping between documents and POJOs.
  • Exception translation into Spring’s portable Data Access Exception hierarchy.
  • Feature Rich Object Mapping integrated with Spring’s Conversion Service.
  • Annotation based mapping metadata but extensible to support other metadata formats.
  • Automatic implementation of Repository interfaces including support for custom finder methods (backed by Couchbase’s query language, N1QL) and PagingAndSortingRepository.
  • For Couchbase server versions < 4.0, repositories can still be backed by Couchbase Views.
  • Support for geospatial and multidimensional querying (backed by Couchbase Spatial Views)
  • JMX administration and monitoring
  • Can serve as the backend for @Cacheable support, to cache any objects you need for high performance access (see sibling Spring Cache project in Couchbase’s github, couchbaselabs/couchbase-spring-cache).

Quick Start

Download

The recommended way to get started using spring-data-couchbase in your project is with a dependency management system – the snippet below can be copied and pasted into your build. Need help? See our getting started guides on building with Maven and Gradle.

Configuration

The minimal configuration requires you to set the name and password of the main Bucket into which Spring Data Couchbase will store the data: getBucketName() and getBucketPassword().

The other required information is a list of IPs or hostnames to bootstrap from (at least one, preferably two): getBootstrapHosts(). These are just used to initiate connection to the cluster, after which the client will discover all nodes and keep the cluster map up to date.

package foo;

import foo;

@Configuration
@EnableCouchbaseRepositories
public class Config extends AbstractCouchbaseConfiguration {

    @Override
    protected List<String> getBootstrapHosts() {
        return Arrays.asList("host1", "host2");
    }

    @Override
    protected String getBucketName() {
        return "default";
    }

    @Override
    protected String getBucketPassword() {
        return "";
    }
}

Sample Repository

public interface UserRepository extends CrudRepository<User, String> {

    /**
     * Additional custom finder method, backed by an auto-generated
     * N1QL query.
     */
    List<User> findByLastnameAndAgeBetween(String lastName, int minAge,
        int maxAge);

    /**
     * Additional custom finder method, backed by a View that indexes
     * the names.
     */
    @View(designDocument = "user", viewName = "byName")
    List<User> findByLastname(String lastName);

    /**
     * Additional custom finder method, backed by a geospatial view and
     * allowing multi-dimensional queries.
     * You can also query within a Circle or a Polygon.
     */
    @Dimensional(designDocument = "userGeo", spatialViewName = "byLocation")
    List<User> findByLocationWithin(Box cityBoundingBox);
}

Server-side Setup

Note that some CRUD operations like findAll and count, as well as view-based custom finders each require you to set up a corresponding View on the server side:

For findByLastname:

function (doc, meta) {
  if(doc._class == "com.example.entity.User" && doc.firstname) {
    emit(doc.firstname, null);
  }
}

For findAll and count (also add a reduce _count):

function (doc, meta) {
  if(doc._class == "com.example.entity.User") {
    emit(null, null);
  }
}

For findByLocationWithin:

function (doc, meta) {
    if(doc._class == "com.example.entity.User" && doc.location) {
        emit([doc.location.x, doc.location.y], null);
    }
}

For more information on server side setup and how it can be partially automated in development environments, see the Backing Views and Automatic Index Management sections of the documentation.

Usage

@Service
public class MyService {

    private final UserRepository userRepository;

    @Autowired
    public MyService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void doWork() {
        userRepository.deleteAll();

        User user = new User();
        user.setLastname("Jackson");
        user.setLocation(new Point(123, 456));

        user = userRepository.save(user);

        List<User> jacksonChildren =
            userRepository.findByLastNameAndAgeBetween("Jackson", 0, 18);

        List<User> jacksonFamily =
            userRepository.findByLastName("Jackson");

        //bounding box is lower-left, upper-right corners
        Box cityBounds = new Box(new Point(100, 100), new Point(150, 500));
        List<User> jacksonsInSomeCity =
            userRepository.findByLocationWithin(cityBounds);
    }
}