使用 GeoJSON
¥Using GeoJSON
地理 JSON 是一种存储地理点和多边形的格式。GeoJSON 对象上的 MongoDB 对地理空间查询有出色的支持。让我们看看如何使用 Mongoose 来存储和查询 GeoJSON 对象。
¥GeoJSON is a format for storing geographic points and polygons. MongoDB has excellent support for geospatial queries on GeoJSON objects. Let's take a look at how you can use Mongoose to store and query GeoJSON objects.
点结构
¥Point Schema
GeoJSON 中最简单的结构是点。下面是代表 旧金山 大致位置的示例点。请注意,在 GeoJSON 坐标数组中,经度排在第一位,而不是纬度。
¥The most simple structure in GeoJSON is a point. Below is an example point representing the approximate location of San Francisco. Note that longitude comes first in a GeoJSON coordinate array, not latitude.
{
"type" : "Point",
"coordinates" : [
-122.5,
37.7
]
}
下面是 Mongoose 结构的示例,其中 location
是一个点。
¥Below is an example of a Mongoose schema where location
is a point.
const citySchema = new mongoose.Schema({
name: String,
location: {
type: {
type: String, // Don't do `{ location: { type: String } }`
enum: ['Point'], // 'location.type' must be 'Point'
required: true
},
coordinates: {
type: [Number],
required: true
}
}
});
使用 subdocuments,你可以定义一个通用的 pointSchema
并在你想要存储 GeoJSON 点的任何地方重用它。
¥Using subdocuments, you can define a common pointSchema
and reuse it everywhere you want to store a GeoJSON point.
const pointSchema = new mongoose.Schema({
type: {
type: String,
enum: ['Point'],
required: true
},
coordinates: {
type: [Number],
required: true
}
});
const citySchema = new mongoose.Schema({
name: String,
location: {
type: pointSchema,
required: true
}
});
多边形结构
¥Polygon Schema
GeoJSON 多边形允许你在映射上定义任意形状。例如,下面的多边形是一个 GeoJSON 矩形,近似于科罗拉多州的边界。
¥GeoJSON polygons let you define an arbitrary shape on a map. For example, the below polygon is a GeoJSON rectangle that approximates the border of the state of Colorado.
{
"type": "Polygon",
"coordinates": [[
[-109, 41],
[-102, 41],
[-102, 37],
[-109, 37],
[-109, 41]
]]
}
多边形很棘手,因为它们使用三重嵌套数组。下面是如何创建 Mongoose 结构,其中 coordinates
是三重嵌套数字数组。
¥Polygons are tricky because they use triple nested arrays. Below is
how you create a Mongoose schema where coordinates
is a triple nested
array of numbers.
const polygonSchema = new mongoose.Schema({
type: {
type: String,
enum: ['Polygon'],
required: true
},
coordinates: {
type: [[[Number]]], // Array of arrays of arrays of numbers
required: true
}
});
const citySchema = new mongoose.Schema({
name: String,
location: polygonSchema
});
使用 Mongoose 进行地理空间查询
¥Geospatial Queries with Mongoose
Mongoose 查询支持与 MongoDB 驱动程序相同的 地理空间查询运算符。例如,以下脚本保存 city
文档,其中 location
属性是代表科罗拉多州丹佛市的 GeoJSON 点。然后,它使用 MongoDB $geoWithin
运算符 查询代表科罗拉多州的多边形内的所有文档。
¥Mongoose queries support the same geospatial query operators
that the MongoDB driver does. For example, the below script saves a
city
document those location
property is a GeoJSON point representing
the city of Denver, Colorado. It then queries for all documents within
a polygon representing the state of Colorado using
the MongoDB $geoWithin
operator.

const City = db.model('City', new Schema({
name: String,
location: pointSchema
}));
const colorado = {
type: 'Polygon',
coordinates: [[
[-109, 41],
[-102, 41],
[-102, 37],
[-109, 37],
[-109, 41]
]]
};
const denver = { type: 'Point', coordinates: [-104.9903, 39.7392] };
return City.create({ name: 'Denver', location: denver }).
then(() => City.findOne({
location: {
$geoWithin: {
$geometry: colorado
}
}
})).
then(doc => assert.equal(doc.name, 'Denver'));
Mongoose 还有一个 within()
帮手,它是 $geoWithin
的简写。
¥Mongoose also has a within()
helper
that's a shorthand for $geoWithin
.
const denver = { type: 'Point', coordinates: [-104.9903, 39.7392] };
return City.create({ name: 'Denver', location: denver }).
then(() => City.findOne().where('location').within(colorado)).
then(doc => assert.equal(doc.name, 'Denver'));
地理空间索引
¥Geospatial Indexes
MongoDB 支持 2dsphere 索引 来加速地理空间查询。以下是在 GeoJSON 点上定义 2dsphere 索引的方法:
¥MongoDB supports 2dsphere indexes for speeding up geospatial queries. Here's how you can define a 2dsphere index on a GeoJSON point:
const denver = { type: 'Point', coordinates: [-104.9903, 39.7392] };
const City = db.model('City', new Schema({
name: String,
location: {
type: pointSchema,
index: '2dsphere' // Create a special 2dsphere index on `City.location`
}
}));
return City.create({ name: 'Denver', location: denver }).
then(() => City.findOne().where('location').within(colorado)).
then(doc => assert.equal(doc.name, 'Denver'));
你还可以使用 Schema#index()
功能 定义地理空间索引,如下所示。
¥You can also define a geospatial index using the Schema#index()
function
as shown below.
citySchema.index({ location: '2dsphere' });
MongoDB 的 $near
查询运算符 和 $geoNear
聚合阶段 需要 2dsphere 索引。
¥MongoDB's $near
query operator
and $geoNear
aggregation stage
require a 2dsphere index.