查询半径内的位置

Pau*_*aul 15 mongodb mongodb-query

如果我有以下形式的文件:

{
    pos:  { lat: 0, lon: 30 }
}
Run Code Online (Sandbox Code Playgroud)

在收集用户(请假装这些是真正的lat/lon :-))

在所说的半径范围内获取所有值的正确方法是什么:50英里?

Lar*_*tle 61

这是一个3步骤的过程.

  • 步骤1)在文档中嵌入GeoJSON Point.
  • 步骤2)使用指数指向点的路径2dsphere.
  • 步骤3)使用$geoWithin和查询文档中的点$centerSphere.

要执行地理空间查询,您需要更改文档结构以匹配GeoJSON点.看起来像这样.

loc : {
    type : "Point",
    coordinates : [lng, lat]
}
Run Code Online (Sandbox Code Playgroud)

用于将集合转换为Point格式的示例代码.

// sample setup code.
// use test; 
// db.positions.drop();
// db.positions.insert({
    // pos : {
        // lat : 0,
        // lon : 30
    // }
// });
db.positions.find().forEach(function (doc) {
    var point = {
        _id : doc._id,
        loc : {
            type : "Point",
            coordinates : [doc.pos.lon, doc.pos.lat]
        }
    };
    db.positions.update(doc, point);
});
db.positions.find().pretty();
Run Code Online (Sandbox Code Playgroud)

之后,您可以在查询中使用$geoWithin$near运算符,如下例所示.

建立

var createLandmarkDoc = function (name, lng, lat) {
    return {
        name : name,
        loc : {
            type : "Point",
            coordinates : [lng, lat]
        }
    };
};
var addNewLandmark = function(name, lng, lat){
    db.landmarks.insert(createLandmarkDoc(name, lng, lat));
};

db.landmarks.drop();
// Step 1: Add points.
addNewLandmark("Washington DC", 38.8993487, -77.0145665);
addNewLandmark("White House", 38.9024593, -77.0388266);
addNewLandmark("Library of Congress", 38.888684, -77.0047189);
addNewLandmark("Patuxent Research Refuge", 39.0391718, -76.8216182);
addNewLandmark("The Pentagon", 38.871857, -77.056267);
addNewLandmark("Massachusetts Institute of Technology", 42.360091, -71.09416);

// Step 2: Create index
db.landmarks.ensureIndex({
    loc : "2dsphere"
});
Run Code Online (Sandbox Code Playgroud)

查询:查找5英里范围内的地标.

var milesToRadian = function(miles){
    var earthRadiusInMiles = 3959;
    return miles / earthRadiusInMiles;
};
var landmark = db.landmarks.findOne({name: "Washington DC"});
var query = {
    "loc" : {
        $geoWithin : {
            $centerSphere : [landmark.loc.coordinates, milesToRadian(5) ]
        }
    }
};
// Step 3: Query points.
db.landmarks.find(query).pretty();
Run Code Online (Sandbox Code Playgroud)

产量

{
        "_id" : ObjectId("540e70c96033ed0d2d9694fa"),
        "name" : "Washington DC",
        "loc" : {
                "type" : "Point",
                "coordinates" : [
                        38.8993487,
                        -77.0145665
                ]
        }
}
{
        "_id" : ObjectId("540e70c96033ed0d2d9694fc"),
        "name" : "Library of Congress",
        "loc" : {
                "type" : "Point",
                "coordinates" : [
                        38.888684,
                        -77.0047189
                ]
        }
}
{
        "_id" : ObjectId("540e70c96033ed0d2d9694fb"),
        "name" : "White House",
        "loc" : {
                "type" : "Point",
                "coordinates" : [
                        38.9024593,
                        -77.0388266
                ]
        }
}
{
        "_id" : ObjectId("540e70c96033ed0d2d9694fe"),
        "name" : "The Pentagon",
        "loc" : {
                "type" : "Point",
                "coordinates" : [
                        38.871857,
                        -77.056267
                ]
        }
}
Run Code Online (Sandbox Code Playgroud)

更多信息:

  • 谢谢,仍然对mongo 3.4有效。刚添加了“ kms”,则var kmsToRadian = function(kms){var earthRadiusInkms = 6371; 返回kms / earthRadiusInkms; }; (2认同)

Dev*_*vWL 5

使用 MongoDB 逐步进行径向位置查询

MongoDB 非常适合使用地理空间数据计算地理位置

基本上,您可以在具有 **2dsphere** 索引的集合上使用“$geoWithin:”和“$centerSphere:”。但让我们一步一步来。

场景:假设用户正在浏览他所在区域的酒店...他想要显示距离他当前位置 50 英里范围内的酒店,并且您的数据库应用程序充满了酒店数据。您可能会使用一些 MAP API 将它们显示在地图上(如果这就是您想要的,请务必查看底部的链接),但对于此示例,我们只想获取距离酒店位置 50 英里范围内的酒店数据在您的 MongoDB 数据库中。

首先创建测试文档集合“hotels”

coordinates*如果您希望此代码在半径距离没有任何变化的情况下工作,您可能需要编辑那些与您附近的位置相匹配的代码。

// Your 'hotels' collection could look something like this:
db.hotels.insertMany([
  {
    'name': 'Golebiewski',
    'address': 'Poland, Mikolajki',
    'location': { type: "Point", coordinates: [ 40, 5.000001 ] },
    'tel': '000 000 000'
  },
  {
    'name': 'Baltazar',
    'address': 'Poland, Pultusk 36',
    'location': { type: "Point", coordinates: [ 40, 5.000002 ] },
    'tel': '000 000 000'
  },
  {
    'name': 'Zamek',
    'address': 'Poland, Pultusk',
    'location': { type: "Point", coordinates: [ 40, 5.000003 ] },
    'tel': '000 000 000'
  },
])
Run Code Online (Sandbox Code Playgroud)

然后location用2dsphere索引

db.places.createIndex( { location : "2dsphere" } )
Run Code Online (Sandbox Code Playgroud)

现在根据里程范围和您的位置进行查询。

首先准备好工具:
// custom function - convert miles to radian
let milesToRadian = function(miles){
    var earthRadiusInMiles = 3963;
    return miles / earthRadiusInMiles;
};

// or custom function - convert km to radian
let kmToRadian = function(miles){
    var earthRadiusInMiles = 6378;
    return miles / earthRadiusInMiles;
};


// custom function - returns array with current user geolocation points - [latitude, longitude]
function getUserLocation() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function (position) {
      let geoPoints = [position.coords.latitude, position.coords.longitude];
      console.log(geoPoints);
      return geoPoints;
    });
  } else { 
    console.log("Geolocation is not supported by this browser.");
  }
}
Run Code Online (Sandbox Code Playgroud)

现在使用新工具为 MongoDB 地理空间数据创建查询。

var query = {'location' : {$geoWithin: { $centerSphere:  getUserLocation(), milesToRadian(50) ]}}}

// MongoDB example query could look something like:
// {'location': {$geoWithin: { $centerSphere: [ [ 40.000000001, 5.000000001 ], 0.012616704516780217 ]}}}

db.hotels.find(query);
Run Code Online (Sandbox Code Playgroud)

MongoDB 返回距用户位置 50 英里范围内的文档(酒店)列表。请记住,您的文档需要实现 GeoJSON 结构来存储位置,并且索引必须为2dsphere。结果将按照与用户 ASC 的距离排序。

输出

{ "_id" : ObjectId("5d3130f810050424d26836d6"), "name" : "Golebiewski", "address" : "Poland, Mikolajki", "location" : { "type" : "Point", "coordinates" : [ 40, 5.000001 ] }, "tel" : "000 000 000" }
{ "_id" : ObjectId("5d3130f810050424d26836d7"), "name" : "Baltazar", "address" : "Poland, Pultusk 36", "location" : { "type" : "Point", "coordinates" : [ 40, 5.000002 ] }, "tel" : "000 000 000" }
{ "_id" : ObjectId("5d3130f810050424d26836d8"), "name" : "Zamek", "address" : "Poland, Pultusk", "location" : { "type" : "Point", "coordinates" : [ 40, 5.000003 ] }, "tel" : "000 000 000" }
Run Code Online (Sandbox Code Playgroud)

观看/阅读更多

MongoDB - 地理空间查询:https://docs.mongodb.com/manual/geospatial-queries/ https://www.youtube.com/watch?v=3xP-gzh2ck0

走得更远!

将您的数据显示到地图上。这里有一些非常酷的教程。

使用 MapBox API 打开街道地图: https://docs.mapbox.com/help/tutorials/building-a-store-locator/

带有 Google JavaScript API 的 Google 地图: https://developers.google.com/maps/documentation/javascript/marker-clustering

如果要将地址转换为地理编码点,可以使用Nominatim gui 或Nominatim API

例如,在浏览器中搜索“Poland Pultusk”或通过添加字符串参数来请求 json 响应&format=json

https://nominatim.openstreetmap.org/search.php?q=Poland+Pultusk https://nominatim.openstreetmap.org/search.php?q=Poland+Pultusk&format=json

诗。MapBox 每月最多免费加载 50,000 次,然后每 1000 次 API 调用收费 5 美元。Google 为您提供 200 美元的每月信用免费使用量,其中包括 28k 次免费 API 调用,然后每 1000 次 api 调用 7 美元。选择你的武器并享受乐趣:>。

工具:MongoDB Compass(*不是社区版) https://www.mongodb.com/blog/post/visualizing-your-data-with-mongodb-compass