我有一个mongodb $geoWithin
查询,如下所示
db.test.find(
{
'loc': {
$geoWithin: {
$geometry: {
type : "Polygon" ,
coordinates: [[list of co-ordinates]]
}
}
}
}
);
所以此处查询在loc
字段上运行,该字段是lng
,lat
值的数组,但幸运的是,我的数据lat
和lng
值在2个不同的字段中,如
{
lat:12,
long:122
}
在这种情况下,我该如何运行上述查询?
答案 0 :(得分:4)
您可以做的最好的事情是转换文档以更好地存储数据。您可能应该选择GeoJSON格式。但更晚些时候。
幸运的是,$geoWithin
实际上并不需要"一个索引(但它确实是更好的选择)你可以实际进行转换"在飞行中"而是使用聚合框架:
希望你至少拥有 MongoDB 2.6 ,有$map
:
db.collection.aggregate([
// Tranform to array
{ "$project": {
"location": {
"$map": {
"input": ["lng","lat"],
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el", "lng" ] },
"$long",
"$lat"
}
}
}
}
}},
// Then match
{ "$match": {
"location": {
"$geoWithin": {
"$geometry": {
"type": "Polygon" ,
"coordinates": [[list of co-ordinates]]
}
}
}
}}
])
MongoDB 3.2 有一个更简单的语法:
db.collection.aggregate([
// Tranform to array - pretty simple huh!
{ "$project": {
"location": ["$long","$lat"]
}},
// Then match
{ "$match": {
"location": {
"$geoWithin": {
"$geometry": {
"type": "Polygon" ,
"coordinates": [[list of co-ordinates]]
}
}
}
}}
])
或者如果你还有 MongoDB 2.4 - 升级!好的,然后使用它:
db.collection.aggregate([
// Add an array field
{ "$project": {
"long": 1,
"lat": 1
"location": { "$const": [ "A", "B" ] }
}},
// Unwind it
{ "$unwind": "$location" },
// Group back and map it!
{ "$group": {
"_id": "$_id",
"location": {
"$push": {
"$cond": [
{ "$eq": [ "$location", "A" ] },
"$long",
"$lat"
]
}
}
}},
// Then match
{ "$match": {
"location": {
"$geoWithin": {
"$geometry": {
"type": "Polygon" ,
"coordinates": [[list of co-ordinates]]
}
}
}
}}
])
但实际上最好的情况是永久改变文档结构。现代的方法是bulk,例如:
var ops = [];
db.collection.find({}).forEach(function(doc) {
ops.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": {
"$set": {
"location": {
"type": "Point",
"coordinates": [doc.long,doc.lat]
}
},
"$unset": { "long": "", "lat": "" }
}
}
});
// Send once in 1000 only
if ( ops.length % 1000 == 0 ) {
db.collection.bulkWrite(ops);
ops = [];
}
})
// Clear remaining queue
if ( ops.length > 0 )
db.collection.bulkWrite(ops);
但一般来说,循环源文档并更新每个文档以创建新的"位置"领域。然后当然"索引"它:
db.collection.createIndex({ "location": "2dsphere" })
现在文档看起来像这样并且实际上有一个索引,您可以直接使用常规$geoWithin
查询,这也可以从当前索引数据中更快地运行。