| MongoDB supports [2d indexes|http://docs.mongodb.org/manual/core/2d/] that store points on a two-dimensional plane. |
| |
| It is possible to use a MongoDB 2d index by mapping a list or map property using the @geoIndex@ mapping: |
| |
| {code} |
| class Hotel { |
| String name |
| List location |
| |
| static mapping = { |
| location geoIndex:'2d' |
| } |
| } |
| {code} |
| |
| By default the index creation assumes latitude/longitude and thus is configured for a -180..180 range. If you are indexing something else you can customise this with @indexAttributes@ |
| |
| {code} |
| class Hotel { |
| String name |
| List location |
| |
| static mapping = { |
| location geoIndex:'2d', indexAttributes:[min:-500, max:500] |
| } |
| } |
| |
| {code} |
| |
| You can then save Geo locations using a two dimensional list: |
| |
| {code} |
| new Hotel(name:"Hilton", location:[50, 50]).save() |
| {code} |
| |
| Alternatively you can use a map with keys representing latitude and longitude: |
| |
| {code} |
| new Hotel(name:"Hilton", location:[lat: 40.739037d, long: 73.992964d]).save() |
| {code} |
| |
| {note} |
| You must specify whether the number of a floating point or double by adding a 'd' or 'f' at the end of the number eg. 40.739037d. Groovy's default type for decimal numbers is @BigDecimal@ which is not supported by MongoDB. |
| {note} |
| |
| Once you have your data indexed you can use Mongo specific dynamic finders to find hotels near a given a location: |
| |
| {code} |
| def h = Hotel.findByLocationNear([50, 60]) |
| assert h.name == 'Hilton' |
| {code} |
| |
| You can also find a location within a box (bound queries). Boxes are defined by specifying the lower-left and upper-right corners: |
| |
| {code} |
| def box = [[40.73083d, -73.99756d], [40.741404d, -73.988135d]] |
| def h = Hotel.findByLocationWithinBox(box) |
| {code} |
| |
| You can also find a location within a circle. Circles are specified using a center and radius: |
| |
| {code} |
| def center = [50, 50] |
| def radius = 10 |
| def h = Hotel.findByLocationWithinCircle([center, radius]) |
| {code} |
| |
| If you plan on querying a location and some other value it is recommended to use a compound index: |
| |
| {code} |
| class Hotel { |
| String name |
| List location |
| int stars |
| |
| static mapping = { |
| compoundIndex location:"2d", stars:1 |
| } |
| } |
| {code} |
| |
| In the example above you an index is created for both the location and the number of stars a @Hotel@ has. |