DATADOC-67 - Criteria API to support keywords for geo search

This commit is contained in:
Mark Pollack
2011-03-31 18:46:08 -04:00
parent 2b9b082978
commit 7e774428e4
8 changed files with 222 additions and 12 deletions

View File

@@ -49,7 +49,7 @@ public class MongoAdmin implements MongoAdminOperations {
*/
@ManagedOperation
public void dropDatabase(String databaseName) {
mongo.getDB(databaseName).dropDatabase();
getDB(databaseName).dropDatabase();
}
/* (non-Javadoc)
@@ -57,7 +57,7 @@ public class MongoAdmin implements MongoAdminOperations {
*/
@ManagedOperation
public void createDatabase(String databaseName) {
mongo.getDB(databaseName);
getDB(databaseName);
}
/* (non-Javadoc)
@@ -65,7 +65,7 @@ public class MongoAdmin implements MongoAdminOperations {
*/
@ManagedOperation
public String getDatabaseStats(String databaseName) {
return mongo.getDB("testAdminDb").getStats().toString();
return getDB(databaseName).getStats().toString();
}
/**
@@ -88,7 +88,7 @@ public class MongoAdmin implements MongoAdminOperations {
}
public DB getDb(String databaseName) {
DB getDB(String databaseName) {
return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray());
}
}

View File

@@ -92,9 +92,9 @@ public abstract class MongoDbUtils {
LOGGER.debug("Opening Mongo DB");
DB db = mongo.getDB(databaseName);
boolean creadentialsGiven = username != null && password != null;
boolean credentialsGiven = username != null && password != null;
if (creadentialsGiven && !db.authenticate(username, password)) {
if (credentialsGiven && !db.authenticate(username, password)) {
throw new CannotGetMongoDbConnectionException("Failed to authenticate with Mongo using the given credentials");
}

View File

@@ -18,9 +18,12 @@ package org.springframework.data.document.mongodb;
import com.mongodb.MongoException;
import com.mongodb.MongoException.DuplicateKey;
import com.mongodb.MongoException.Network;
import com.mongodb.MongoInternalException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.document.UncategorizedDocumentStoreException;
@@ -55,6 +58,9 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
if (ex instanceof MongoException) {
return new UncategorizedDocumentStoreException(ex.getMessage(), ex);
}
if (ex instanceof MongoInternalException) {
return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
}
// If we get here, we have an exception that resulted from user code,
// rather than the persistence provider, so we return null to indicate

View File

@@ -239,7 +239,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext
// Set the ID
PersistentProperty idProperty = entity.getIdProperty();
if (dbo.containsField("_id") || null != idProperty) {
if (dbo.containsField("_id") && null != idProperty) {
Object idObj = dbo.get("_id");
try {
MappingBeanHelper.setProperty(instance, idProperty, idObj, useFieldAccessOnly);

View File

@@ -0,0 +1,50 @@
/*
* 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.geo;
import java.util.Arrays;
/**
* Represents a geospatial circle value
* @author Mark Pollack
*
*/
public class Circle {
private double[] center;
private double radius;
public Circle(double centerX, double centerY, double radius) {
this.center = new double[] { centerX, centerY };
this.radius = radius;
}
public double[] getCenter() {
return center;
}
public double getRadius() {
return radius;
}
@Override
public String toString() {
return "Circle [center=" + Arrays.toString(center) + ", radius=" + radius
+ "]";
}
}

View File

@@ -17,11 +17,13 @@ package org.springframework.data.document.mongodb.query;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.springframework.data.document.InvalidDocumentStoreApiUsageException;
import org.springframework.data.document.mongodb.geo.Circle;
public class Criteria implements CriteriaDefinition {
@@ -225,6 +227,21 @@ public class Criteria implements CriteriaDefinition {
criteria.put("$regex", re);
return this;
}
/**
* Creates a geospatial criterion using a $
* @param circle
* @return
*/
public Criteria within(Circle circle) {
LinkedList list = new LinkedList();
list.addLast(circle.getCenter());
list.add(circle.getRadius());
//BasicDBObject dbo = new BasicDBObject("$within", new BasicDBObject("$center", list));
criteria.put("$within", new BasicDBObject("$center", list));
return this;
}
/**
* Creates a criterion using the $elemMatch operator
@@ -244,6 +261,8 @@ public class Criteria implements CriteriaDefinition {
public void or(List<Query> queries) {
criteria.put("$or", queries);
}
public String getKey() {
return this.key;

View File

@@ -1,30 +1,109 @@
/*
* 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;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import java.util.LinkedList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.document.mongodb.geo.Circle;
import org.springframework.data.document.mongodb.query.Criteria;
import org.springframework.data.document.mongodb.query.GeospatialIndex;
import org.springframework.data.document.mongodb.query.Query;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoException;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:geospatial.xml")
public class GeoSpatialTests {
@Autowired
MongoTemplate template;
@Before
public void setUp() {
template.dropCollection(template.getDefaultCollectionName());
template.ensureIndex(new GeospatialIndex("location"));
addVenues();
}
private void addVenues() {
// Data taken from https://github.com/deftlabs/mongo-java-geospatial-example
template.insert(new Venue("Penn Station", 73.99408, 40.75057));
template.insert(new Venue("10gen Office", -73.99171, 40.738868));
template.insert(new Venue("Flatiron Building", -73.988135, 40.741404));
template.insert(new Venue("Players Club", -73.997812, 40.739128));
template.insert(new Venue("City Bakery ", -73.992491, 40.738673));
template.insert(new Venue("Splash Bar", -73.992491, 40.738673));
template.insert(new Venue("Momofuku Milk Bar", -73.985839, 40.731698));
template.insert(new Venue("Shake Shack", -73.98820, 40.74164));
template.insert(new Venue("Penn Station", -73.99408, 40.75057));
template.insert(new Venue("Empire State Building", -73.98602, 40.74894));
template.insert(new Venue("Washington Square Park", -73.99756, 40.73083));
template.insert(new Venue("Ulaanbaatar, Mongolia", 106.9154, 47.9245));
template.insert(new Venue("Maplewood, NJ", -74.2713, 40.73137));
}
@Test
public void withinCircle() {
Circle circle = new Circle(-73.99171, 40.738868, 0.01);
List<Venue> venues = template.find(new Query(Criteria.where("location").within(circle)), Venue.class);
assertThat(venues.size(), equalTo(8));
}
@Test
public void indexCreated() {
assertThat(template, notNullValue());
Venue foundVenue = template.findOne(
new Query(Criteria.where("name").is("Penn Station")), Venue.class);
assertThat(foundVenue, notNullValue());
List<Venue> venues = template.getCollection(Venue.class);
assertThat(venues.size(), equalTo(13));
List<DBObject> indexInfo = getIndexInfo();
assertThat(indexInfo.size(), equalTo(2));
assertThat(indexInfo.get(1).get("name").toString(), equalTo("location_2d"));
assertThat(indexInfo.get(1).get("ns").toString(),
equalTo("geospatial.newyork"));
}
// TODO move to MongoAdmin
public List<DBObject> getIndexInfo() {
return template.execute(new CollectionCallback<List<DBObject>>() {
public List<DBObject> doInCollection(DBCollection collection)
throws MongoException, DataAccessException {
return collection.getIndexInfo();
}
});
}
@Test
public void geoIndex() {
assertThat(template, notNullValue());
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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;
import java.util.Arrays;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.document.mongodb.mapping.Document;
@Document
public class Venue {
private String id;
private String name;
private Double[] location;
@PersistenceConstructor
Venue(String name, Double[] location) {
super();
this.name = name;
this.location = location;
}
public Venue(String name, double x, double y) {
super();
this.name = name;
this.location = new Double[] { x, y };
}
public String getName() {
return name;
}
public Double[] getLocation() {
return location;
}
@Override
public String toString() {
return "Venue [id=" + id + ", name=" + name + ", location="
+ Arrays.toString(location) + "]";
}
}