mongodb支持空间索引,其内部是B-Tree实现(是的,并不是R-Tree),本文展示常用的操作及spring访问的例子。

导入样例数据

从github上下载数据并导入,你可能需要使用-u-p 参数指定用户名和密码。

wget https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json && \
    mongoimport neighborhoods.json -c neighborhoods
wget https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json && \
    mongoimport restaurants.json -c restaurants

创建空间索引

db.restaurants.createIndex({ location: "2dsphere" })
db.neighborhoods.createIndex({ geometry: "2dsphere" })

样例数据中包含一个点集和(restaurants)和一个多边形集合(neighborhoods), 内容如下

> db.restaurants.findOne()                                                                                                                                                        
{                                                                                                                                                                                 
        "_id" : ObjectId("55cba2476c522cafdb053ae0"),                                                                                                                             
        "location" : {                                                                                                                                                            
                "coordinates" : [                                                                                                                                                 
                        -73.8601152,                                                                                                                                              
                        40.7311739                                                                                                                                                
                ],                                                                                                                                                                
                "type" : "Point"                                                                                                                                                  
        },                                                                                                                                                                        
        "name" : "Tov Kosher Kitchen"                                                                                                                                             
}  
> db.neighborhoods.findOne()
{
    "_id" : ObjectId("55cb9c666c522cafdb053a1a"),
    "geometry" : {
        "coordinates" : [
            [
                [
                    -73.94193078816193,
                    40.70072523469547
                ],
                ...
                [
                    -73.94193078816193,
                    40.70072523469547
                ]
            ]
        ],
        "type" : "Polygon"
    },
    "name" : "Bedford"
}

查询操作

查询500米以内的所有餐厅(点),并从近到远排序返回

db.restaurants.find({
    location: {
        $near: {
            $geometry: {
                type: "Point",
                coordinates: [-73.93414657, 40.82302903]
            },
            $maxDistance: 500
        }
    }
})
Point point = new Point(-73.93414657, 40.82302903);
Distance distance = new Distance(0.5, Metrics.KILOMETERS);

List<Restaurant> restaurants = restaurantRepository.findByLocationNear(point, distance);

查询经纬度偏差0.001度以内所有的餐厅(点),返回是无序的

db.restaurants.find({
    location: {
        $geoWithin: { $center: [ [-74, 40.74], 0.001 ] }
    }
})
Circle circle = new Circle(
            new Point(-74, 40.74),
            new Distance(0.001)
);
List<Restaurant> restaurants = restaurantRepository.findByLocationWithin(circle);

查询当前点所在小区(多边形),再查找在小区内的所有餐厅(点)

var neighborhood = db.neighborhoods.findOne({
    geometry: {
        $geoIntersects: {
            $geometry: {
                type: "Point",
                coordinates: [-73.93414657, 40.82302903]
            }
        }
    }
})
db.restaurants.find({location: {$geoWithin: {$geometry: neighborhood.geometry}}}).count()
GeoJsonPoint point = new GeoJsonPoint( -73.93414657, 40.82302903);
Neighborhood neighborhood = mongoTemplate.findOne(
        new Query(Criteria.where("geometry").intersects(point)),
        Neighborhood.class);

System.out.println("find:" + 
    restaurantRepository.findByLocationWithin(neighborhood.getGeometry()).size());

Spring 访问例子下载

References

  1. mongodb manual
  2. geojson-spec
  3. spring-data-mongodb