使用不带点的地理空间查询获取一定距离内的文档 object
Get documents within a distance using Geospatial Query without Point object
我有一个地方 collection 将位置清楚地存储为
place = {
name : "",
latitude: "",
longitude:""
}
有什么方法可以使用 mongo shell 或 spring 数据 mongo 来查询这样的地方:
select all places with coordinates(places.longitude, place.latitude) near a point(x,y) and within a distance z . Something like:
db.places.find( {
{
"type" : "Point",
"coordinates" : [
places.longitude,
places.latitude
]
}:
{ $geoWithin:
{ $centerSphere: [ [ x, y ] ,z / 3963.2 ]
}
}
})
或者我必须将 collection 修改为
place = {
name : "",
"loc" : {
"type" : "Point",
"coordinates" : [
longitude,
latitude
]
}
}
你真的应该改变你的数据。 MongoDB 仅支持用于地理空间索引和查询的旧坐标对格式或 GeoJSON。您不能以任何方式对数据或 "transform" 使用不同的字段,因为使用 $near
or $nearSphere
.
进行操作所必需的 "index" 需要支持的字段格式
最好在 shell 中进行转换,因为不需要为 "one off" 操作编写其他 API 代码。是的,向前推进你真的应该使用 GeoJSON 格式:
var bulk = db.places.initializeUnorderedBulkOp(),
count = 0;
db.places.find().forEach(function(doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": {
"location": {
"type": "Point",
"coordinates": [parseFloat(doc.longitude),parseFloat(doc.latitude)]
}
},
"$unset": { "latitude": "", "longitude": "" }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.places.initializeUnorderedBulkOp();
}
});
if ( count % 1000 !=0 )
bulk.execute();
现在数据已固定且与索引兼容,请创建索引。 GeoJSON 数据在这里有意义的是 "2sphere" 索引:
db.places.createIndex({ "location": "2dsphere" })
之后就可以正常查询文档了:
db.places.find({
"location": {
"$geoWithin": {
"$centerSphere": [ [ x, y ] ,z]
}
}
})
我还应该注意到,$geoWithin
中的 $centreSphere
操作实际上与带有 $maxDistance
修饰符的 $nearSphere
相同。例外情况是后者应该同时处理 "faster" 并为 "nearest" 位置生成 "ordered" 结果,这是 $geoWithin
不做的事情:
db.places.find({
"$nearSphere": {
"$geometry": {
"type": "Point",
"coordinates": [x,y]
},
"$maxDistance": z
}
})
对现有数据执行此操作的唯一方法是仅针对 $geoWithin
。这是因为该操作 不 需要地理空间索引,因此您可以先 "transform" 文档。
您可以使用 .aggregate()
method and it's $project
pipeline stage along with the $map
运算符执行此操作:
db.places.aggregate([
{ "$project": {
"name": 1
"location": {
"type": "Point",
"coordinates": {
"$map": {
"input": ["A","B"],
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el", "A" ] },
"$longitude",
"$latitude"
]
}
}
}
}
}},
{ "$match": {
"location": {
"$geoWithin": {
"$centerSphere": [ [ x, y ] ,z]
}
}
}}
])
但是您的经度和纬度数据必须已经是数字,因为这是您无法在聚合框架中转换的内容。并且您必须记住,此 不能 用于 $nearSphere
等操作,因为在初始管道阶段后所需的索引不可用。
所以可以,但不可取。它会增加处理时间,如果您修复数据并添加适当的索引,事情会变得更好、更灵活和 "faster"。
另请注意,使用 GeoJSON 数据的所有距离都将以千米而不是弧度为单位。
我有一个地方 collection 将位置清楚地存储为
place = {
name : "",
latitude: "",
longitude:""
}
有什么方法可以使用 mongo shell 或 spring 数据 mongo 来查询这样的地方:
select all places with coordinates(places.longitude, place.latitude) near a point(x,y) and within a distance z . Something like:
db.places.find( {
{
"type" : "Point",
"coordinates" : [
places.longitude,
places.latitude
]
}:
{ $geoWithin:
{ $centerSphere: [ [ x, y ] ,z / 3963.2 ]
}
}
})
或者我必须将 collection 修改为
place = {
name : "",
"loc" : {
"type" : "Point",
"coordinates" : [
longitude,
latitude
]
}
}
你真的应该改变你的数据。 MongoDB 仅支持用于地理空间索引和查询的旧坐标对格式或 GeoJSON。您不能以任何方式对数据或 "transform" 使用不同的字段,因为使用 $near
or $nearSphere
.
最好在 shell 中进行转换,因为不需要为 "one off" 操作编写其他 API 代码。是的,向前推进你真的应该使用 GeoJSON 格式:
var bulk = db.places.initializeUnorderedBulkOp(),
count = 0;
db.places.find().forEach(function(doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": {
"location": {
"type": "Point",
"coordinates": [parseFloat(doc.longitude),parseFloat(doc.latitude)]
}
},
"$unset": { "latitude": "", "longitude": "" }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.places.initializeUnorderedBulkOp();
}
});
if ( count % 1000 !=0 )
bulk.execute();
现在数据已固定且与索引兼容,请创建索引。 GeoJSON 数据在这里有意义的是 "2sphere" 索引:
db.places.createIndex({ "location": "2dsphere" })
之后就可以正常查询文档了:
db.places.find({
"location": {
"$geoWithin": {
"$centerSphere": [ [ x, y ] ,z]
}
}
})
我还应该注意到,$geoWithin
中的 $centreSphere
操作实际上与带有 $maxDistance
修饰符的 $nearSphere
相同。例外情况是后者应该同时处理 "faster" 并为 "nearest" 位置生成 "ordered" 结果,这是 $geoWithin
不做的事情:
db.places.find({
"$nearSphere": {
"$geometry": {
"type": "Point",
"coordinates": [x,y]
},
"$maxDistance": z
}
})
对现有数据执行此操作的唯一方法是仅针对 $geoWithin
。这是因为该操作 不 需要地理空间索引,因此您可以先 "transform" 文档。
您可以使用 .aggregate()
method and it's $project
pipeline stage along with the $map
运算符执行此操作:
db.places.aggregate([
{ "$project": {
"name": 1
"location": {
"type": "Point",
"coordinates": {
"$map": {
"input": ["A","B"],
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el", "A" ] },
"$longitude",
"$latitude"
]
}
}
}
}
}},
{ "$match": {
"location": {
"$geoWithin": {
"$centerSphere": [ [ x, y ] ,z]
}
}
}}
])
但是您的经度和纬度数据必须已经是数字,因为这是您无法在聚合框架中转换的内容。并且您必须记住,此 不能 用于 $nearSphere
等操作,因为在初始管道阶段后所需的索引不可用。
所以可以,但不可取。它会增加处理时间,如果您修复数据并添加适当的索引,事情会变得更好、更灵活和 "faster"。
另请注意,使用 GeoJSON 数据的所有距离都将以千米而不是弧度为单位。