Writing Geospatial Queries for MongoDB in Java
Join the DZone community and get the full member experience.
Join For FreeMongoDB supports 2-dimensional geospatial indexes. You can watch MongoSF (May 2011) presentation to understand it at a basic level.
In this article, I will help you quickly write Geospatial queries described in above presentation using Java programming language. I assume you have MongoDB server up and running on your machine. Source code for this article is available at this Github project.
A repository of Gegraphical Places
Below Java class stores major cities in California, US in the form of String array. We’ll use this array in the next program.
public class Places { public static final String[] cities = new String[] { "Palos Verdes Estates", "Los Altos Hills", "Hillsborough", "Monte Sereno", "Villa Park", "Palo Alto", "Belvedere", "Los Altos", "Rolling Hills", "Montecito", "Piedmont", "Foster City", "Yorba Linda", "Mission Canyon", "Saratoga", "Orinda", "Manhattan Beach", "Pleasanton", "Imperial", "Goleta", "Tiburon", "Tustin Foothills", "Rancho Palos Verdes", "Mountain View", "La Habra Heights", "Newport Beach", "Toro Canyon", "Agoura Hills", "Redondo Beach", "Menlo Park", "Mill Valley", "Indian Wells", "Moraga", "Ross", "La Palma", "Kensington", "Hermosa Beach", "Thousand Oaks", "Belmont", "Rolling Hills Estates", "Loyola", "Summerland", "Santa Monica", "Rossmoor", "Irvine", "Lafayette", "Laguna Niguel", "Torrance", "Fairbanks Ranch", "Cupertino", "Santa Barbara", "Portola Valley", "Woodside", "San Ramon", "Santa Ynez", "Emerald Lake Hills", "Angwin", "El Segundo", "Orange", "West Menlo Park", "West Bishop", "Ladera Heights", "Huntington Beach", "Atherton", "Coronado", "Danville", "Diamond Bar", "Rancho Santa Fe", "Chino Hills", "Clayton", "Walnut", "San Anselmo", "Solvang", "Cerritos", "Blackhawk-Camino Tassajara", "Highlands-Baywood Park", "Fountain Valley", "Westlake Village", "Sunnyvale", "Poway", "Del Monte Forest", "Brea", "San Carlos", "Los Gatos", "Rancho Santa Margarita", "Camarillo", "Cypress", "Newport Coast", "San Joaquin Hills", "Folsom", "Arroyo Grande", "Malibu", "Sausalito", "Del Rio", "Green Valley", "Mission Viejo", "Aliso Viejo", "Stanford", "Encinitas", "Rancho Mirage" }; }
Geospatial Queries Program
This program run following methods in that order:
1. addPlaces() – Adds above listed 100 California cities on a 10X10 plane. Data is stored in MongoDB collection named “places”.
2. findWithinCircle() – Finds all cities in a circle whose center is (5,5) and are within a radius of 1 unit (of our imaginary plane)
3. findWithinBox() – Finds all cities within a rectangle formed between coordinates (4,4) and (6,6)
4. FindWithinPolygon() – Finds all cities within a polygon (triangle in this case) formed from 3 coordinates.
5. findCenterSphere() – Same as 2, but query is spherical in nature.
6. findNear() – Finds all cities near (4,4) having a maximum distance of 2 unit.
7. findNearSphere() – Same as above, but query is spherical in nature.
import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBAddress; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.mongodb.Mongo; import com.mongodb.MongoException; /** * Example code for Geospatial queries in MongoDB * @author amresh.singh */ public class GeospatialExample { public static final String dbName = "geospatial"; public static final String host = "127.0.0.1"; public static final int port = 27017; public static final String collectionName = "places"; public static final String indexName = "geospatialIdx"; Mongo mongo; DBCollection collection; private Mongo getMongo() { try { mongo = new Mongo(new DBAddress(host, port, dbName)); } catch (MongoException e) { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); } return mongo; } public static void main(String[] args) { new GeospatialExample().runExample(); } private void runExample() { collection = getMongo().getDB(dbName).getCollection(collectionName); collection.ensureIndex(new BasicDBObject("loc", "2d"), indexName); addPlaces(); findWithinCircle(); findWithinBox(); findWithinPolygon(); findCenterSphere(); findNear(); findNearSphere(); } private void findWithinCircle() { System.out.println("findWithinCircle\n----------------------\n"); List circle = new ArrayList(); circle.add(new double[] { 5, 5 }); // Centre of circle circle.add(1); // Radius BasicDBObject query = new BasicDBObject("loc", new BasicDBObject("$within", new BasicDBObject("$center", circle))); printOutputs(query); } private void findWithinBox() { System.out.println("findWithinBox\n----------------------\n"); List box = new ArrayList(); box.add(new double[] { 4, 4 }); //Starting coordinate box.add(new double[]{6,6}); // Ending coordinate BasicDBObject query = new BasicDBObject("loc", new BasicDBObject("$within", new BasicDBObject("$box", box))); printOutputs(query); } private void findWithinPolygon() { System.out.println("findWithinPolygon\n----------------------\n"); List polygon = new ArrayList(); polygon.add(new double[] { 3, 3 }); //Starting coordinate polygon.add(new double[]{8,3}); // Ending coordinate polygon.add(new double[]{6,7}); // Ending coordinate BasicDBObject query = new BasicDBObject("loc", new BasicDBObject("$within", new BasicDBObject("$polygon", polygon))); printOutputs(query); } private void findNear() { System.out.println("findNear\n----------------------\n"); BasicDBObject filter = new BasicDBObject("$near", new double[] { 4, 4 }); filter.put("$maxDistance", 2); BasicDBObject query = new BasicDBObject("loc", filter); printOutputs(query); } private void findNearSphere() { System.out.println("findNearSphere\n----------------------\n"); BasicDBObject filter = new BasicDBObject("$nearSphere", new double[] { 5, 5 }); filter.put("$maxDistance", 0.06); // Radius of the earth: 3959.8728 BasicDBObject query = new BasicDBObject("loc", filter); printOutputs(query); } private void findCenterSphere() { System.out.println("findCenterSphere\n----------------------\n"); List circle = new ArrayList(); circle.add(new double[] { 5, 5 }); // Centre of circle circle.add(0.06); // Radius BasicDBObject query = new BasicDBObject("loc", new BasicDBObject("$within", new BasicDBObject("$centerSphere", circle))); printOutputs(query); } public void printOutputs(BasicDBObject query) { DBCursor cursor = collection.find(query); List<BasicDBList> outputs = new ArrayList<BasicDBList>(); while (cursor.hasNext()) { DBObject result = cursor.next(); System.out.println(result.get("name") + "--->" + result.get("loc")); outputs.add((BasicDBList) result.get("loc")); } for (int y = 9; y >= 0; y--) { String s = ""; for (int x = 0; x < 10; x++) { boolean found = false; for (BasicDBList obj : outputs) { double xVal = (Double) obj.get(0); double yVal = (Double) obj.get(1); if (yVal == y && xVal == x) { found = true; } } if(found) { s = s + " @"; } else { s = s + " +"; } } System.out.println(s); } } private void addPlaces() { System.out.println("Adding places..."); for (int i = 0; i < 100; i++) { double x = i % 10; double y = Math.floor(i / 10); addPlace(collection, Places.cities[i], new double[] { x, y }); } System.out.println("All places added"); } private void addPlace(DBCollection collection, String name, final double[] location) { final BasicDBObject place = new BasicDBObject(); place.put("name", name); place.put("loc", location); collection.insert(place); } }
MongoDB Console (after running program)
amresh@ubuntu:/usr/local/mongodb-linux-i686-1.8.1/bin$ ./mongo MongoDB shell version: 1.8.1 connecting to: test > use geospatial; switched to db geospatial > db.places.find(); { "_id" : ObjectId("50747ebf44ae3dfd6b8eb40a"), "name" : "Palos Verdes Estates", "loc" : [ 0, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb40b"), "name" : "Los Altos Hills", "loc" : [ 1, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb40c"), "name" : "Hillsborough", "loc" : [ 2, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb40d"), "name" : "Monte Sereno", "loc" : [ 3, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb40e"), "name" : "Villa Park", "loc" : [ 4, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb40f"), "name" : "Palo Alto", "loc" : [ 5, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb410"), "name" : "Belvedere", "loc" : [ 6, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb411"), "name" : "Los Altos", "loc" : [ 7, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb412"), "name" : "Rolling Hills", "loc" : [ 8, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb413"), "name" : "Montecito", "loc" : [ 9, 0 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb414"), "name" : "Piedmont", "loc" : [ 0, 1 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb415"), "name" : "Foster City", "loc" : [ 1, 1 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb416"), "name" : "Yorba Linda", "loc" : [ 2, 1 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb417"), "name" : "Mission Canyon", "loc" : [ 3, 1 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb418"), "name" : "Saratoga", "loc" : [ 4, 1 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb419"), "name" : "Orinda", "loc" : [ 5, 1 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb41a"), "name" : "Manhattan Beach", "loc" : [ 6, 1 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb41b"), "name" : "Pleasanton", "loc" : [ 7, 1 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb41c"), "name" : "Imperial", "loc" : [ 8, 1 ] } { "_id" : ObjectId("50747ebf44ae3dfd6b8eb41d"), "name" : "Goleta", "loc" : [ 9, 1 ] } has more
Program Output
Adding places... All places added findWithinCircle ---------------------- Emerald Lake Hills--->[ 5.0 , 5.0] Lafayette--->[ 5.0 , 4.0] Emerald Lake Hills--->[ 5.0 , 5.0] Santa Ynez--->[ 4.0 , 5.0] Santa Ynez--->[ 4.0 , 5.0] Lafayette--->[ 5.0 , 4.0] Danville--->[ 5.0 , 6.0] Danville--->[ 5.0 , 6.0] Angwin--->[ 6.0 , 5.0] Angwin--->[ 6.0 , 5.0] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ + + + + + + + + @ @ @ + + + + + + + + @ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + findWithinBox ---------------------- Emerald Lake Hills--->[ 5.0 , 5.0] Lafayette--->[ 5.0 , 4.0] Emerald Lake Hills--->[ 5.0 , 5.0] Lafayette--->[ 5.0 , 4.0] Santa Ynez--->[ 4.0 , 5.0] Santa Ynez--->[ 4.0 , 5.0] Irvine--->[ 4.0 , 4.0] Irvine--->[ 4.0 , 4.0] Coronado--->[ 4.0 , 6.0] Coronado--->[ 4.0 , 6.0] Danville--->[ 5.0 , 6.0] Danville--->[ 5.0 , 6.0] Laguna Niguel--->[ 6.0 , 4.0] Laguna Niguel--->[ 6.0 , 4.0] Angwin--->[ 6.0 , 5.0] Angwin--->[ 6.0 , 5.0] Diamond Bar--->[ 6.0 , 6.0] Diamond Bar--->[ 6.0 , 6.0] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ @ @ + + + + + + + @ @ @ + + + + + + + @ @ @ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + findCenterSphere ---------------------- Emerald Lake Hills--->[ 5.0 , 5.0] Lafayette--->[ 5.0 , 4.0] Emerald Lake Hills--->[ 5.0 , 5.0] Lafayette--->[ 5.0 , 4.0] Kensington--->[ 5.0 , 3.0] Kensington--->[ 5.0 , 3.0] Santa Ynez--->[ 4.0 , 5.0] Santa Ynez--->[ 4.0 , 5.0] San Ramon--->[ 3.0 , 5.0] San Ramon--->[ 3.0 , 5.0] Irvine--->[ 4.0 , 4.0] Irvine--->[ 4.0 , 4.0] La Palma--->[ 4.0 , 3.0] La Palma--->[ 4.0 , 3.0] Rossmoor--->[ 3.0 , 4.0] Rossmoor--->[ 3.0 , 4.0] Ross--->[ 3.0 , 3.0] Ross--->[ 3.0 , 3.0] Newport Beach--->[ 5.0 , 2.0] Newport Beach--->[ 5.0 , 2.0] La Habra Heights--->[ 4.0 , 2.0] La Habra Heights--->[ 4.0 , 2.0] Woodside--->[ 2.0 , 5.0] Woodside--->[ 2.0 , 5.0] Santa Monica--->[ 2.0 , 4.0] Santa Monica--->[ 2.0 , 4.0] Huntington Beach--->[ 2.0 , 6.0] Huntington Beach--->[ 2.0 , 6.0] Atherton--->[ 3.0 , 6.0] Atherton--->[ 3.0 , 6.0] Cerritos--->[ 3.0 , 7.0] Cerritos--->[ 3.0 , 7.0] Coronado--->[ 4.0 , 6.0] Coronado--->[ 4.0 , 6.0] Blackhawk-Camino Tassajara--->[ 4.0 , 7.0] Blackhawk-Camino Tassajara--->[ 4.0 , 7.0] Rancho Santa Margarita--->[ 4.0 , 8.0] Rancho Santa Margarita--->[ 4.0 , 8.0] Danville--->[ 5.0 , 6.0] Danville--->[ 5.0 , 6.0] Highlands-Baywood Park--->[ 5.0 , 7.0] Highlands-Baywood Park--->[ 5.0 , 7.0] Camarillo--->[ 5.0 , 8.0] Camarillo--->[ 5.0 , 8.0] Toro Canyon--->[ 6.0 , 2.0] Toro Canyon--->[ 6.0 , 2.0] Hermosa Beach--->[ 6.0 , 3.0] Hermosa Beach--->[ 6.0 , 3.0] Laguna Niguel--->[ 6.0 , 4.0] Laguna Niguel--->[ 6.0 , 4.0] Thousand Oaks--->[ 7.0 , 3.0] Thousand Oaks--->[ 7.0 , 3.0] Torrance--->[ 7.0 , 4.0] Torrance--->[ 7.0 , 4.0] Angwin--->[ 6.0 , 5.0] Angwin--->[ 6.0 , 5.0] El Segundo--->[ 7.0 , 5.0] El Segundo--->[ 7.0 , 5.0] Fairbanks Ranch--->[ 8.0 , 4.0] Fairbanks Ranch--->[ 8.0 , 4.0] Orange--->[ 8.0 , 5.0] Orange--->[ 8.0 , 5.0] Diamond Bar--->[ 6.0 , 6.0] Diamond Bar--->[ 6.0 , 6.0] Fountain Valley--->[ 6.0 , 7.0] Fountain Valley--->[ 6.0 , 7.0] Rancho Santa Fe--->[ 7.0 , 6.0] Rancho Santa Fe--->[ 7.0 , 6.0] Westlake Village--->[ 7.0 , 7.0] Westlake Village--->[ 7.0 , 7.0] Cypress--->[ 6.0 , 8.0] Cypress--->[ 6.0 , 8.0] Chino Hills--->[ 8.0 , 6.0] Chino Hills--->[ 8.0 , 6.0] + + + + + + + + + + + + + + @ @ @ + + + + + + @ @ @ @ @ + + + + @ @ @ @ @ @ @ + + + @ @ @ @ @ @ @ + + + @ @ @ @ @ @ @ + + + + @ @ @ @ @ + + + + + + @ @ @ + + + + + + + + + + + + + + + + + + + + + + + findNear ---------------------- Irvine--->[ 4.0 , 4.0] Irvine--->[ 4.0 , 4.0] Santa Ynez--->[ 4.0 , 5.0] Santa Ynez--->[ 4.0 , 5.0] Lafayette--->[ 5.0 , 4.0] Lafayette--->[ 5.0 , 4.0] La Palma--->[ 4.0 , 3.0] La Palma--->[ 4.0 , 3.0] Rossmoor--->[ 3.0 , 4.0] Rossmoor--->[ 3.0 , 4.0] Emerald Lake Hills--->[ 5.0 , 5.0] Emerald Lake Hills--->[ 5.0 , 5.0] San Ramon--->[ 3.0 , 5.0] San Ramon--->[ 3.0 , 5.0] Kensington--->[ 5.0 , 3.0] Kensington--->[ 5.0 , 3.0] Ross--->[ 3.0 , 3.0] Ross--->[ 3.0 , 3.0] Santa Monica--->[ 2.0 , 4.0] Santa Monica--->[ 2.0 , 4.0] La Habra Heights--->[ 4.0 , 2.0] La Habra Heights--->[ 4.0 , 2.0] Coronado--->[ 4.0 , 6.0] Coronado--->[ 4.0 , 6.0] Laguna Niguel--->[ 6.0 , 4.0] Laguna Niguel--->[ 6.0 , 4.0] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ + + + + + + + + @ @ @ + + + + + + @ @ @ @ @ + + + + + + @ @ @ + + + + + + + + @ + + + + + + + + + + + + + + + + + + + + + + + + + findNearSphere ---------------------- Emerald Lake Hills--->[ 5.0 , 5.0] Emerald Lake Hills--->[ 5.0 , 5.0] Santa Ynez--->[ 4.0 , 5.0] Santa Ynez--->[ 4.0 , 5.0] Angwin--->[ 6.0 , 5.0] Angwin--->[ 6.0 , 5.0] Lafayette--->[ 5.0 , 4.0] Lafayette--->[ 5.0 , 4.0] Danville--->[ 5.0 , 6.0] Danville--->[ 5.0 , 6.0] Coronado--->[ 4.0 , 6.0] Coronado--->[ 4.0 , 6.0] Diamond Bar--->[ 6.0 , 6.0] Diamond Bar--->[ 6.0 , 6.0] Irvine--->[ 4.0 , 4.0] Irvine--->[ 4.0 , 4.0] Laguna Niguel--->[ 6.0 , 4.0] Laguna Niguel--->[ 6.0 , 4.0] San Ramon--->[ 3.0 , 5.0] San Ramon--->[ 3.0 , 5.0] El Segundo--->[ 7.0 , 5.0] El Segundo--->[ 7.0 , 5.0] Kensington--->[ 5.0 , 3.0] Kensington--->[ 5.0 , 3.0] Highlands-Baywood Park--->[ 5.0 , 7.0] Highlands-Baywood Park--->[ 5.0 , 7.0] Atherton--->[ 3.0 , 6.0] Atherton--->[ 3.0 , 6.0] Rancho Santa Fe--->[ 7.0 , 6.0] Rancho Santa Fe--->[ 7.0 , 6.0] Rossmoor--->[ 3.0 , 4.0] Rossmoor--->[ 3.0 , 4.0] Torrance--->[ 7.0 , 4.0] Torrance--->[ 7.0 , 4.0] Blackhawk-Camino Tassajara--->[ 4.0 , 7.0] Blackhawk-Camino Tassajara--->[ 4.0 , 7.0] Fountain Valley--->[ 6.0 , 7.0] Fountain Valley--->[ 6.0 , 7.0] La Palma--->[ 4.0 , 3.0] La Palma--->[ 4.0 , 3.0] Hermosa Beach--->[ 6.0 , 3.0] Hermosa Beach--->[ 6.0 , 3.0] Cerritos--->[ 3.0 , 7.0] Cerritos--->[ 3.0 , 7.0] Westlake Village--->[ 7.0 , 7.0] Westlake Village--->[ 7.0 , 7.0] Ross--->[ 3.0 , 3.0] Ross--->[ 3.0 , 3.0] Thousand Oaks--->[ 7.0 , 3.0] Thousand Oaks--->[ 7.0 , 3.0] Woodside--->[ 2.0 , 5.0] Woodside--->[ 2.0 , 5.0] Orange--->[ 8.0 , 5.0] Orange--->[ 8.0 , 5.0] Newport Beach--->[ 5.0 , 2.0] Newport Beach--->[ 5.0 , 2.0] Camarillo--->[ 5.0 , 8.0] Camarillo--->[ 5.0 , 8.0] Huntington Beach--->[ 2.0 , 6.0] Huntington Beach--->[ 2.0 , 6.0] Chino Hills--->[ 8.0 , 6.0] Chino Hills--->[ 8.0 , 6.0] Santa Monica--->[ 2.0 , 4.0] Santa Monica--->[ 2.0 , 4.0] Fairbanks Ranch--->[ 8.0 , 4.0] Fairbanks Ranch--->[ 8.0 , 4.0] Rancho Santa Margarita--->[ 4.0 , 8.0] Rancho Santa Margarita--->[ 4.0 , 8.0] Cypress--->[ 6.0 , 8.0] Cypress--->[ 6.0 , 8.0] La Habra Heights--->[ 4.0 , 2.0] La Habra Heights--->[ 4.0 , 2.0] Toro Canyon--->[ 6.0 , 2.0] Toro Canyon--->[ 6.0 , 2.0] + + + + + + + + + + + + + + @ @ @ + + + + + + @ @ @ @ @ + + + + @ @ @ @ @ @ @ + + + @ @ @ @ @ @ @ + + + @ @ @ @ @ @ @ + + + + @ @ @ @ @ + + + + + + @ @ @ + + + + + + + + + + + + + + + + + + + + + + +
Published at DZone with permission of Amresh Singh, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments