From c47c7deeeba436b1966c2dc054d5b2c8a31c3fbe Mon Sep 17 00:00:00 2001 From: Thomas Risberg Date: Sat, 12 Feb 2011 16:12:51 -0500 Subject: [PATCH] added indexing features to MongoTemplate --- .../document/mongodb/MongoOperations.java | 18 ++++ .../data/document/mongodb/MongoTemplate.java | 21 +++++ .../mongodb/query/GeospatialIndex.java | 77 +++++++++++++++ .../data/document/mongodb/query/Index.java | 94 +++++++++++++++++++ .../data/document/mongodb/query/Order.java | 25 +++++ .../data/document/mongodb/query/Sort.java | 19 ++-- .../mongodb/repository/QueryUtils.java | 4 +- .../document/mongodb/MongoTemplateTests.java | 37 ++++++++ .../document/mongodb/query/IndexTests.java | 51 ++++++++++ .../document/mongodb/query/SortTests.java | 2 +- 10 files changed, 337 insertions(+), 11 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/GeospatialIndex.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Index.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Order.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/IndexTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOperations.java index f753e7bd0..f615ac63f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoOperations.java @@ -18,6 +18,7 @@ package org.springframework.data.document.mongodb; import java.util.List; import java.util.Set; +import org.springframework.data.document.mongodb.query.Index; import org.springframework.data.document.mongodb.query.Query; import org.springframework.data.document.mongodb.query.Update; @@ -204,6 +205,23 @@ public interface MongoOperations { */ List getCollection(String collectionName, Class targetClass, MongoReader reader); + + /** + * Ensure that an index for the specified {@link Index} specification exists for the default collection. + * If not is will be created. + * + * @param index + */ + void ensureIndex(Index index); + + /** + * Ensure that an index for the specified {@link Index} specification exists. If not is will be + * created. + * + * @param collectionName + * @param index + */ + void ensureIndex(String collectionName, Index index); /** * Map the results of an ad-hoc query on the default MongoDB collection to a List of the specified type. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java index 6d703d02a..f67a259b1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java @@ -30,6 +30,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.data.document.mongodb.MongoPropertyDescriptors.MongoPropertyDescriptor; +import org.springframework.data.document.mongodb.query.Index; import org.springframework.data.document.mongodb.query.Query; import org.springframework.data.document.mongodb.query.Update; import org.springframework.jca.cci.core.ConnectionCallback; @@ -406,6 +407,26 @@ public class MongoTemplate implements InitializingBean, MongoOperations { }, collectionName); } + // Indexing methods + + public void ensureIndex(Index index) { + ensureIndex(getDefaultCollectionName(), index); + } + + public void ensureIndex(String collectionName, final Index index) { + execute(new CollectionCallback() { + public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { + DBObject indexOptions = index.getIndexOptions(); + if (indexOptions != null) { + collection.ensureIndex(index.getIndexObject(), indexOptions); + } + else { + collection.ensureIndex(index.getIndexObject()); + } + return null; + } + }, collectionName); + } // Find methods that take a Query to express the query. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/GeospatialIndex.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/GeospatialIndex.java new file mode 100644 index 000000000..0e74185ef --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/GeospatialIndex.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.document.mongodb.query; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; + + +public class GeospatialIndex { + + private String keyField; + + private String name; + + private Integer min = null; + + private Integer max = null; + + public GeospatialIndex() { + } + + public GeospatialIndex(String key) { + keyField = key; + } + + public GeospatialIndex named(String name) { + this.name = name; + return this; + } + + public GeospatialIndex withMin(int min) { + this.min = Integer.valueOf(min); + return this; + } + + public GeospatialIndex withMax(int max) { + this.max = Integer.valueOf(max); + return this; + } + + public DBObject getIndexObject() { + DBObject dbo = new BasicDBObject(); + dbo.put(keyField, "2d"); + return dbo; + } + + public DBObject getIndexOptions() { + if (name == null && min == null && max == null) { + return null; + } + DBObject dbo = new BasicDBObject(); + if (name != null) { + dbo.put("name", name); + } + if (min != null) { + dbo.put("min", min); + } + if (max != null) { + dbo.put("max", max); + } + return dbo; + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Index.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Index.java new file mode 100644 index 000000000..8c76b8303 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Index.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.document.mongodb.query; + +import java.util.HashMap; +import java.util.Map; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; + + +public class Index { + + public enum Duplicates { + RETAIN, + DROP + } + + private Map fieldSpec = new HashMap(); + + private String name; + + private boolean unique = false; + + private boolean dropDuplicates = false; + + public Index() { + } + + public Index(String key, Order order) { + fieldSpec.put(key, order); + } + + public Index on(String key, Order order) { + fieldSpec.put(key, order); + return this; + } + + public Index named(String name) { + this.name = name; + return this; + } + + public Index unique() { + this.unique = true; + return this; + } + + public Index unique(Duplicates duplicates) { + if (duplicates == Duplicates.DROP) { + this.dropDuplicates = true; + } + return unique(); + } + + public DBObject getIndexObject() { + DBObject dbo = new BasicDBObject(); + for (String k : fieldSpec.keySet()) { + dbo.put(k, (fieldSpec.get(k).equals(Order.ASCENDING) ? 1 : -1)); + } + return dbo; + } + + public DBObject getIndexOptions() { + if (name == null && !unique) { + return null; + } + DBObject dbo = new BasicDBObject(); + if (name != null) { + dbo.put("name", name); + } + if (unique) { + dbo.put("unique", true); + } + if (dropDuplicates) { + dbo.put("drop_dups", true); + } + return dbo; + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Order.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Order.java new file mode 100644 index 000000000..8dbd7a198 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Order.java @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.document.mongodb.query; + +/** + * An enum that specifies the ordering for sort or index specifications + * + * @author trisberg + */ +public enum Order { + ASCENDING, DESCENDING +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Sort.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Sort.java index 426dea5c2..a20c318bc 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Sort.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Sort.java @@ -24,21 +24,24 @@ import com.mongodb.DBObject; public class Sort { - public enum Order { - ASCENDING, DESCENDING + private Map fieldSpec = new HashMap(); + + public Sort() { } - - private Map criteria = new HashMap(); - + + public Sort(String key, Order order) { + fieldSpec.put(key, order); + } + public Sort on(String key, Order order) { - criteria.put(key, order); + fieldSpec.put(key, order); return this; } public DBObject getSortObject() { DBObject dbo = new BasicDBObject(); - for (String k : criteria.keySet()) { - dbo.put(k, (criteria.get(k).equals(Order.ASCENDING) ? 1 : -1)); + for (String k : fieldSpec.keySet()) { + dbo.put(k, (fieldSpec.get(k).equals(Order.ASCENDING) ? 1 : -1)); } return dbo; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/QueryUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/QueryUtils.java index 4c4b2386c..3ca3eae66 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/QueryUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/repository/QueryUtils.java @@ -78,8 +78,8 @@ abstract class QueryUtils { for (Order order : sort) { bSort.on( order.getProperty(), - order.isAscending() ? org.springframework.data.document.mongodb.query.Sort.Order.ASCENDING - : org.springframework.data.document.mongodb.query.Sort.Order.DESCENDING); + order.isAscending() ? org.springframework.data.document.mongodb.query.Order.ASCENDING + : org.springframework.data.document.mongodb.query.Order.DESCENDING); } return query; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateTests.java index cfdaef21f..ce9dd41da 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoTemplateTests.java @@ -32,11 +32,16 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.data.document.mongodb.query.Criteria; +import org.springframework.data.document.mongodb.query.Index; +import org.springframework.data.document.mongodb.query.Index.Duplicates; +import org.springframework.data.document.mongodb.query.Order; import org.springframework.data.document.mongodb.query.Query; import org.springframework.data.document.mongodb.query.Update; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import com.mongodb.DBCollection; +import com.mongodb.DBObject; import com.mongodb.WriteConcern; /** @@ -92,6 +97,38 @@ public class MongoTemplateTests { } + @Test + public void testEnsureIndex() throws Exception { + + Person p1 = new Person("Oliver"); + p1.setAge(25); + template.insert(p1); + Person p2 = new Person("Sven"); + p2.setAge(40); + template.insert(p2); + + template.ensureIndex(new Index().on("age", Order.DESCENDING).unique(Duplicates.DROP)); + + DBCollection coll = template.getCollection(template.getDefaultCollectionName()); + List indexInfo = coll.getIndexInfo(); + + assertThat(indexInfo.size(), is(2)); + String indexKey = null; + boolean unique = false; + boolean dropDupes = false; + for (DBObject ix : indexInfo) { + System.out.println(ix); + if ("age_-1".equals(ix.get("name"))) { + indexKey = ix.get("key").toString(); + unique = (Boolean) ix.get("unique"); + dropDupes = (Boolean) ix.get("drop_dups"); + } + } + assertThat(indexKey, is("{ \"age\" : -1}")); + assertThat(unique, is(true)); + assertThat(dropDupes, is(true)); + } + @Test public void simpleQuery() throws Exception { new Query(where("name").is("Mary")).and(where("age").lt(33).gt(22)).skip(22).limit(20); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/IndexTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/IndexTests.java new file mode 100644 index 000000000..8c88db8d5 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/IndexTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.document.mongodb.query; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.data.document.mongodb.query.Index.Duplicates; + +public class IndexTests { + + @Test + public void testWithAscendingIndex() { + Index i = new Index().on("name", Order.ASCENDING); + Assert.assertEquals("{ \"name\" : 1}", i.getIndexObject().toString()); + } + + @Test + public void testWithDescendingIndex() { + Index i = new Index().on("name", Order.DESCENDING); + Assert.assertEquals("{ \"name\" : -1}", i.getIndexObject().toString()); + } + + @Test + public void testNamedMultiFieldUniqueIndex() { + Index i = new Index().on("name", Order.ASCENDING).on("age", Order.DESCENDING); + i.named("test").unique(); + Assert.assertEquals("{ \"age\" : -1 , \"name\" : 1}", i.getIndexObject().toString()); + Assert.assertEquals("{ \"name\" : \"test\" , \"unique\" : true}", i.getIndexOptions().toString()); + } + + @Test + public void testWithDropDuplicates() { + Index i = new Index().on("name", Order.ASCENDING); + i.unique(Duplicates.DROP); + Assert.assertEquals("{ \"name\" : 1}", i.getIndexObject().toString()); + Assert.assertEquals("{ \"unique\" : true , \"drop_dups\" : true}", i.getIndexOptions().toString()); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/SortTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/SortTests.java index beff0650f..e3b2d762b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/SortTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/query/SortTests.java @@ -18,7 +18,7 @@ package org.springframework.data.document.mongodb.query; import org.junit.Assert; import org.junit.Test; import org.springframework.data.document.mongodb.query.Sort; -import org.springframework.data.document.mongodb.query.Sort.Order; +import org.springframework.data.document.mongodb.query.Order; public class SortTests {