1. Introduction
In this third tutorial on Spring Data Couchbase, we demonstrate the configuration required to support a Couchbase data model that spans multiple buckets, and we introduce the use of Spatial views for querying multi-dimensional data.
2. Data Model
In addition to the Person entity from our first tutorial and the Student entity from our second tutorial, we define a Campus entity for this tutorial:
@Document public class Campus { @Id private String id; @Field @NotNull private String name; @Field @NotNull private Point location; // standard getters and setters }
3. Java Configuration for Multiple Couchbase Buckets
In order to use multiple buckets in your project, you will need to use version 2.0.0 or later of the Spring Data Couchbase module, and you will need to use a Java-based configuration, because the XML-bsaed configuration supports only single-bucket scenarios.
Here is the dependency that we include in our Maven pom.xml file:
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-couchbase</artifactId> <version>2.1.1.RELEASE</version> </dependency>
3.1. Defining the Bucket Bean
In our Introduction to Spring Data Couchbase tutorial, we designated “baeldung” as the name of our default Couchbase bucket for use with Spring Data.
We will store Campus entities in the “baeldung2” bucket.
To make use of a second bucket, we first must define a @Bean for the Bucket itself in our Couchbase configuration class:
@Bean public Bucket campusBucket() throws Exception { return couchbaseCluster().openBucket("baeldung2", ""); }
3.2. Configuring the Template Bean
Next, we define a @Bean for the CouchbaseTemplate to be used with this bucket:
@Bean public CouchbaseTemplate campusTemplate() throws Exception { CouchbaseTemplate template = new CouchbaseTemplate( couchbaseClusterInfo(), campusBucket(), mappingCouchbaseConverter(), translationService()); template.setDefaultConsistency(getDefaultConsistency()); return template; }
3.3. Mapping the Repositories
Finally, we define a custom mapping of Couchbase repository operations so that the Campus entity class will use the new template and bucket, while other entity classes will continue to use the default template and bucket:
@Override public void configureRepositoryOperationsMapping( RepositoryOperationsMapping baseMapping) { try { baseMapping.mapEntity(Campus.class, campusTemplate()); } catch (Exception e) { //custom Exception handling } }
4. Querying Spatial or Multi-Dimensional Data
Couchbase provides native support for running bounding box queries against two-dimensional data, such as geographical data, using a special type of view known as a Spatial view.
A bounding box query is a range query that uses the southwestern-most [x,y] point of the box as its startRange parameter and the northwestern-most [x,y] point as its endRange parameter.
Spring Data extends Couchbase’s native bounding box query feature to queries involving circles and polygons using an algorithm that seeks to eliminate false positive matches, and it also provides support for queries involving more than two dimensions.
Spring Data simplifies the creation of multi-dimensional queries through a set of keywords that can be used to define derived queries in Couchbase repositories.
4.1. Supported Data Types
Spring Data Couchbase repository queries support data types from the org.springframework.data.geo package, including Point, Box, Circle, Polygon, and Distance.
4.2. Derived Query Keywords
In addition to the standard Spring Data repository keywords, Couchbase repositories support the following keywords in derived queries involving two dimensions:
- Within, InWithin (takes two Point parameters defining a bounding box)
- Near, IsNear (takes a Point and Distance as parameters)
And the following keywords may be used for queries involving more than two dimensions:
- Between (for adding a single numerical value to both the startRange and endRange)
- GreaterThan, GreaterThanEqual, After (for adding a single numerical value to the startRange)
- LessThan, LessThanEqual, Before (for adding a single numerical value to the endRange)
Here are some examples of derived query methods using these keywords:
- findByLocationNear
- findByLocationWithin
- findByLocationNearAndPopulationGreaterThan
- findByLocationWithinAndAreaLessThan
- findByLocationNearAndTuitionBetween
5. Defining the Repository
Repository methods backed by Spatial views must be decorated with the @Dimensional annotation, which specifies the design document name, view name, and number of dimensions used to define the view’s key (default 2 if not otherwise specified).
5.1. The CampusRespository Interface
Here in our CampusRepository interface, we declare two methods — one that uses traditional Spring Data keywords, backed by a MapReduce view, and one that uses dimensional Spring Data keywords, backed by a Spatial view:
public interface CampusRepository extends CrudRepository<Campus, String> { @View(designDocument="campus", viewName="byName") Set<Campus> findByName(String name); @Dimensional(dimensions=2, designDocument="campus_spatial", spatialViewName="byLocation") Set<Campus> findByLocationNear(Point point, Distance distance); }
5.2. Spatial Views
Spatial views are written as JavaScript functions, much like MapReduce views. Unlike MapReduce views, which consist of both a map function and a reduce function, Spatial views consist of only a spatial function and may not coexist in the same Couchbase design document as MapReduce views.
For our Campus entities, we will create a design document named “campus_spatial” containing a Spatial view named “byLocation” with the following function:
function (doc) { if (doc.location && doc._class == "org.baeldung.spring.data.couchbase.model.Campus") { emit([doc.location.x, doc.location.y], null); } }
As this example demonstrates, when you write a Spatial view function, the key used in the emit function call must be an array of two or more values.
5.3. MapReduce Views
To provide full support for our repository, we must create a design document named “campus” containing two MapReduce views: “all” and “byName”.
Here is the map function for the “all” view:
function (doc, meta) { if(doc._class == "org.baeldung.spring.data.couchbase.model.Campus") { emit(meta.id, null); } }
And here is the map function for the “byName” view:
function (doc, meta) { if(doc._class == "org.baeldung.spring.data.couchbase.model.Campus" && doc.name) { emit(doc.name, null); } }
6. Conclusion
We showed how to configure your Spring Data Couchbase project to support the use of multiple buckets, and we demonstrated how to use the repository abstraction to write spatial view queries against multi-dimensional data.
You can view the complete source code for this tutorial in the github project.
To learn more about Spring Data Couchbase, visit the official Spring Data Couchbase project site.