Поиск ближайших точек к определенной точке с учетом ее координат и максимального расстояния - результат запроса Undefined с использованием Mongoose с MEAN Stack

У меня проблема, с которой я не мог решить через несколько дней, даже глядя на связанные с ним переполнение стека Q/A.

Я занимаюсь разработкой повторного использования приложения Скотч Создайте учебное приложение MEAN Stack Google Map от Ahmed Haque.

Я пытаюсь реализовать приложение, которое использует API Карт Google для рисования Points, LineStrings и Polygons, координаты которого содержатся в файлах GeoJson которые хранятся в экземпляре MongoDB.

Я использую Mongoose для создания схемы для моих данных и запроса моей базы данных MongoDB.

Я хотел бы найти ближайшие точки CP для определенных точек P0учитывая P0 latitude and longitude и заданный максимальный радиус distance используется для поиска интересующих точек.

введите описание изображения здесь

Учитывая изображение, мне хотелось бы, например, если я вложу 2000 (километров), мой запрос найдет все точки, расположенные максимум в 2000 километрах от P0. В этом примере он должен, вероятно, дать мне 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 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:

От Скотч Создание приложений MEAN с помощью Google Maps (часть II) Ахмеда Хэка

Параметры поиска MongoDB $near и связанные с ним свойства maxDistance и сферические, чтобы указать диапазон, были направлены на покрытие. Умножали расстояние нашего тела запроса на 1609.34, потому что мы хотим, чтобы наши пользователи вводили (в милях) и конвертировали их в единиц MongoDB ожидает (в метрах).

  • Почему я получаю undefined?
  • Возможно ли, что эта проблема вызвана моей схемой?
  • Как я могу это исправить?

Если вы хотите получить некоторые пояснения, просто опубликуйте комментарий ниже.

Спасибо в Advance.

Ответ 1

Мне удалось решить эту проблему.

По сути, проблема была вызвана схемой, так как 2dIndex ссылался на неправильное поле (type and coordinates).

Я решил использовать следующую схему:

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 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);
        });
    });

Я надеюсь, что это поможет кому-то!

ИЗМЕНИТЬ

Схема, на которую я положил, вызывает несколько проблем с LineStrings и Polygons.

Вот правильные схемы, которые позволяют использовать 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);

Многоугольник-model.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] 
                           ]
                         ]
    }
}

Ответ 2

Я не понимаю, что ниже всего вашего кода, но я знаю вещь:
Если вы используете Google Radar Search, вы должны принять во внимание, что

Максимально допустимый радиус составляет 50 000 метров.

Просто взгляните на их Documentation

Это означает, что если вы попытаетесь с более высоким радиусом, результаты могут быть нулевыми