在给定坐标和最大距离的情况下查找到某个点的最近点 - 使用 Mongoose 和 MEAN 堆栈查询结果未定义

Posted

技术标签:

【中文标题】在给定坐标和最大距离的情况下查找到某个点的最近点 - 使用 Mongoose 和 MEAN 堆栈查询结果未定义【英文标题】:Finding Closest Points to a certain Point Given its Coordinates and Maximum Distance - Query Result Undefined using Mongoose with MEAN Stack 【发布时间】:2016-10-10 12:34:21 【问题描述】:

我有一个问题在几天内都无法解决,即使查看相关的 Stack Overflow Q/A。

我正在开发一个重用 Scotch's Create a MEAN Stack Google Map App Tutorial by Ahmed Haque 方法的应用程序。

我正在尝试实现一个使用 Google Maps API 绘制 PointsLineStringsPolygons 的应用程序,这些坐标包含在 GeoJson 文件中存储在 MongoDB 实例中。

我正在使用Mongoose 为我的数据构建架构并查询我的MongoDB 数据库。

我想找到最接近某个点 CP 的点 P0 给定P0's latitude and longitude 并给定最大半径 distance用于查找感兴趣的点。

鉴于图像结束,我希望这样,例如,如果我插入 2000(公里),我的查询将找到距离 P0 最大 2000 公里的所有点。在这个例子中,它可能应该给我 P1 和 P2。

当我的Mongoose Schema 中只有积分时,我能够做到这一点。

我有这个Schema,只有标记(点)

// Pulls Mongoose dependency for creating schemas
var mongoose    = require('mongoose');
var Schema      = mongoose.Schema;

// Creates a User Schema. 
var MarkerSchema = new Schema(
    username: type: String, required: true,
    location: type: [Number], required: true, // [Long, Lat]
    created_at: type: Date, default: Date.now,
    updated_at: type: Date, default: Date.now
);

// Indexes this schema in 2dsphere format
MarkerSchema.index(location: '2dsphere');

module.exports = mongoose.model('mean-markers', MarkerSchema);

这是我的Old Query for only Markers

var User = require('./model.js');

app.post('/query/', function(req, res) 

        // Grab all of the query parameters from the body.
        var lat = req.body.latitude;
        var long = req.body.longitude;
        var distance = req.body.distance;
        var reqVerified = req.body.reqVerified;

        // Opens a generic Mongoose Query
        var query = User.find();

        // ...include filter by Max Distance (converting miles to meters)
        if (distance) 

            // Using MongoDB's geospatial querying features
            query = query.where('location').near(
                center: 
                    type: 'Point',
                    coordinates: [long, lat]
                ,

                // Converting meters to miles
                maxDistance: distance * 1609.34,
                spherical: true
            );
        
);

效果非常好,我能够获得接近分数。

然后,我将我的Schema 更改为更具动态性并支持Polylines and Polygons

我可以使用以下Schema 插入和绘制新的点、折线和多边形:

var mongoose = require('mongoose');
var GeoJSON  = require('geojson');
var Schema   = mongoose.Schema;

// Creates a Location Schema.
var LocationSchema = new Schema(
                                    name: type: String, required: true,
                                    location: 
                                      type: type : String, required: true,
                                      coordinates : [Schema.Types.Mixed]
                                    ,
                                    created_at: type: Date, default: Date.now,
                                    updated_at: type: Date, default: Date.now
);

LocationSchema.index(location: '2dsphere');
module.exports = mongoose.model('mean-locations', LocationSchema);

这是我的Mongoose Query

var GeoObjects = require('./model.js');

app.post('/query/', function(req, res) 

    // Grab all of the query parameters from the body.
    var lat = req.body.latitude;
    var long = req.body.longitude;
    var distance = req.body.distance;

    var query;

    if (distance) 
        query = GeoObjects.find('location.type':'Point')
                    .where('location.coordinates').near(
                      center: 
                        type: 'Point',
                        coordinates: [lat, long]
                      ,
                      // Converting meters to miles
                      maxDistance: distance * 1609.34,
                      spherical: true
        );
    

    // Execute Query and Return the Query Results
    query.exec(function(err, users) 
        if (err)
            res.send(err);
        console.log(users);
        // If no errors, respond with a JSON of all users that meet the criteria
        res.json(users);
    );
);

console.log(users); 给我undefined.

在我的 queryCtrl.js 中记录查询结果给我以下错误消息:

name: "MongoError", message: "error processing query: ns=MeanMapApp.mean-locatio…ed error: unable to find index for $geoNear query", waitedMS: 0, ok: 0, errmsg: "error processing query: ns=MeanMapApp.mean-locatio…ed error: unable to find index for $geoNear query"

相同但略有不同:

app.post('/query/', function(req, res) 

    // Grab all of the query parameters from the body.
    var lat = req.body.latitude;
    var long = req.body.longitude;
    var distance = req.body.distance;

    console.log(lat,long,distance);

    var points = GeoObjects.find('location.type':'Point');

    var loc = parseFloat(points.location.coordinates);
    console.log(JSON.stringify(loc));

    if (distance) 
        var query = points.near(loc, 
                      center: 
                        type: 'Point',
                        coordinates: [parseFloat(lat), parseFloat(long)]
                      ,
                      // Converting meters to miles
                      maxDistance: distance * 1609.34,
                      spherical: true
        );
    
);

这是一个标记示例:


  "name": "user01",
  "location": 
                "type":"Point",
                "coordinates": [102.0, 0.0]

  

$near 运算符如何处理距离和 maxDistance:

来自Scotch's Making MEAN Apps with Google Maps (Part II) by Ahmed Haque

MongoDB 搜索参数 $near 及其相关属性 maxDistance 和球面来指定我们要覆盖的范围。 我们将查询主体的距离乘以 1609.34,因为 我们想要获取用户的输入(以英里为单位)并将其转换为 MongoDB 期望的单位(以米为单位)。

    为什么我会收到undefined 这个问题有可能是我的 Schema 引起的吗? 我该如何解决这个问题?

如果您想获得一些澄清,请在下面发表评论。

提前致谢。

【问题讨论】:

嘿@AndreaM16。你有没有机会在 GitHub 或其他地方有此代码,以便我们将其拉下来仔细查看? 嗨,艾哈迈德,你看了吗? 【参考方案1】:

我不明白你所有的代码下面是什么,但我知道一件事: 如果您使用 Google 的雷达搜索,则必须考虑到

最大允许半径为 50 000 米。

看看他们的Documentation

意味着如果您尝试使用更大的半径,结果可能为零

【讨论】:

您好,非常感谢您的回答。我没有使用谷歌的雷达搜索,我正在尝试使用 MongoDb 的 near 和 geoNear 运算符。事实是,正如我在上面所写的,当我有一个不同的 Mongoose 模式(只有标记)时,我的查询可以正常工作。 MongoDB 搜索参数 $near 及其相关属性 maxDistance 和spherical 来指定我们要覆盖的范围。我们将查询主体的距离乘以 1609.34,因为我们希望获取用户的输入(以英里为单位)并将其转换为 MongoDB 期望的单位(以米为单位)。 关于您的console.log(users) 行,一旦我遇到类似问题。问题是 JS 的非阻塞特性,它执行日志比响应更快。就我而言,承诺或回调解决了这个问题。你试过这种方法吗? 是的,我已经尝试过了,但它总是不确定。我认为这个问题是由我的新模式和 near 运算符引起的。【参考方案2】:

我终于设法解决了这个问题。

本质上,问题是由架构引起的,因为 2dIndex 被引用到错误的字段 (type and coordinates)

我使用以下 Schema 解决了:

var mongoose = require('mongoose');
var GeoJSON  = require('geojson');
var Schema   = mongoose.Schema;

var geoObjects = new Schema(
                               name : type: String,
                               type: 
                                       type: String,
                                       enum: [
                                               "Point",
                                               "LineString",
                                               "Polygon"
                                             ]
                                      ,
                                coordinates: [Number],
                                created_at: type: Date, default: Date.now,
                                updated_at: type: Date, default: Date.now
);

// Sets the created_at parameter equal to the current time
geoObjects.pre('save', function(next)
   now = new Date();
   this.updated_at = now;
   if(!this.created_at) 
      this.created_at = now
   
   next();
);

geoObjects.index(coordinates: '2dsphere');

module.exports = mongoose.model('geoObjects', geoObjects);

还有以下查询

app.post('/query/', function(req, res) 

        // Grab all of the query parameters from the body.
        var lat = req.body.latitude;
        var long = req.body.longitude;
        var distance = req.body.distance;

        var query = GeoObjects.find('type':'Point');

        // ...include filter by Max Distance 
        if (distance) 

            // Using MongoDB's geospatial querying features. 
            query = query.where('coordinates').near(
                center: 
                    type: 'Point',
                    coordinates: [lat, long]
                ,

                // Converting meters to miles
                maxDistance: distance * 1609.34,
                spherical: true
            );
        

        // Execute Query and Return the Query Results
        query.exec(function(err, geoObjects) 
            if (err)
                res.send(err);

            // If no errors, respond with a JSON 
            res.json(geoObjects);
        );
    );

希望对大家有所帮助!

编辑

我放置的架构导致LineStringsPolygons 出现一些问题。

这里是允许使用geoQueries的正确模式

linestring-model.js:

var mongoose = require('mongoose');
var Schema   = mongoose.Schema;

// Creates a LineString Schema.
var linestrings = new Schema(
    name: type: String, required : true,
    geo : 
        type : type: String,
            default: "LineString",
        coordinates : Array
    ,
    created_at: type: Date, default: Date.now,
    updated_at: type: Date, default: Date.now
);

// Sets the created_at parameter equal to the current time
linestrings.pre('save', function(next)
    now = new Date();
    this.updated_at = now;
    if(!this.created_at) 
        this.created_at = now
    
    next();
);

linestrings.index(geo : '2dsphere');
module.exports = mongoose.model('linestrings', linestrings);

多边形模型.js

var mongoose = require('mongoose');
var Schema   = mongoose.Schema;

// Creates a Polygon Schema.
var polygons = new Schema(
    name: type: String, required : true,
    geo : 
        type : type: String,
            default: "Polygon",
        coordinates : Array
    ,
    created_at: type: Date, default: Date.now,
    updated_at: type: Date, default: Date.now
);

// Sets the created_at parameter equal to the current time
polygons.pre('save', function(next)
    now = new Date();
    this.updated_at = now;
    if(!this.created_at) 
        this.created_at = now
    
    next();
);

polygons.index(geo : '2dsphere');
module.exports = mongoose.model('polygons', polygons);

线串插入

  
    "name" : "myLinestring", 
    "geo" : 
        "type" : "LineString", 
        "coordinates" : [
            [
                17.811, 
                12.634
            ], 
            [
                12.039, 
                18.962
            ], 
            [
                15.039, 
                18.962
            ], 
            [
                29.039, 
                18.962
            ]
        ]
    

多边形插入:

  
    "name" : "Poly", 
    "geo" : 
        "type" : "Polygon", 
        "coordinates" :  [
                           [ 
                             [25.774, -80.190], [18.466, -66.118], 
                             [32.321, -64.757], [25.774, -80.190] 
                           ]
                         ]
    

【讨论】:

以上是关于在给定坐标和最大距离的情况下查找到某个点的最近点 - 使用 Mongoose 和 MEAN 堆栈查询结果未定义的主要内容,如果未能解决你的问题,请参考以下文章

基于与给定点的距离的最近 GPS 坐标

在给定点、方位角和距离的情况下计算 gps 坐标

平面最近点对

平面最近点对(分治)

使用 C++ 查找最小和最大点坐标

Luogu 1429 平面最近点对 | 平面分治