Mongoose geoNear maxDistance结果

Ken*_*nny 1 mongoose mongodb node.js

我正在使用node.js和mongoose.我的数据库中有4个带lng/lat坐标的对象.在现实生活中,这些位置彼此相差1或2英里.

module.exports.locationsListByDistance = function(req, res) {
    var lng = parseFloat(req.query.lng);
    var lat = parseFloat(req.query.lat);
    var point = {
        type: "Point",
        coordinates: [lng, lat]
    };
    var geoOptions =  {
        spherical: true,
        maxDistance: 20 / 3963,
        num: 10
    };
    Loc.geoNear(point, geoOptions, function(err, results, stats) {
        var locations;
        console.log('Geo Results', results);
        console.log('Geo stats', stats);
        if (err) {
            console.log('geoNear error:', err);
            sendJsonResponse(res, 404, err);
        } else {
            locations = buildLocationList(req, res, results, stats);
            sendJsonResponse(res, 200, locations);
        }
    });
};
Run Code Online (Sandbox Code Playgroud)

这是我的代码.当Loc.geoNear运行时,在回调函数results返回一个空数组.我可以让它实际返回对象的唯一方法是通过设置maxDistance: 2500然后它将检索具有荒谬距离的 2个对象.

现在显然,2500是一个巨大的数字,这是没有道理的.我需要彼此相距20英里,这就是为什么我转换为弧度通过20 / 3963,但结果maxDistance是如此之小,以至于mongo什么都不返回.有任何想法吗?

编辑1 (添加文档)

{
    "_id": {
        "$oid": "5714204af42b2b9004313d7c"
    },
    "name": "Starcups",
    "address": "125 High Street, Reading, RG6 1PS",
    "rating": 3,
    "facilities": [
        "Hot drinks",
        "Food",
        "Premium wifi"
    ],
    "coords": {
        "lng": -84.135166,
        "lat": 34.190996
    },
    "openingTimes": [
        {
            "days": "Monday - Friday",
            "opening": "7:00am",
            "closing": "7:00pm",
            "closed": false
        },
        {
            "days": "Saturday",
            "opening": "8:00am",
            "closing": "5:00pm",
            "closed": false
        },
        {
            "days": "Sunday",
            "closed": true
        }
    ],
    "reviews": [
        {
            "author": "Kenny Hall",
            "rating": 5,
            "timestamp": "13 April 2016",
            "reviewText": "What a great place. I can't say enough good things about it."
        },
        {
            "author": "Charlie Chaplin",
            "rating": 3,
            "timestamp": "16 June 2015",
            "reviewText": "It was okay. Coffee wasn't great, but the wifi was fast."
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

编辑2(添加模型/架构)

var mongoose = require('mongoose');

var reviewSchema = new mongoose.Schema({
    author: String,
    rating: {
        type: Number,
        required: true,
        min: 0,
        max: 5
    },
    reviewText: String,
    createdOn: {
        type: Date,
        "default": Date.now
    }
});

var openingTimeSchema = new mongoose.Schema({
    days: {
        type: String,
        required: true
    },
    opening: String,
    closing: String,
    closed: {
        type: Boolean,
        required: true
    }
});

var locationSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true
    },
    address: String,
    rating: {
        type: Number,
        "default": 0,
        min: 0,
        max: 5
    },
    facilities: [String],
    // Always store coordinates longitude, latitude order
    coords: {
        type: [Number],
        index: '2dsphere'
    },
    openingTimes: [openingTimeSchema],
    reviews: [reviewSchema]
});

mongoose.model('Location', locationSchema);
Run Code Online (Sandbox Code Playgroud)

Ken*_*nny 6

所以最初我认为MongoDB是以弧度工作的,所以我一直在尝试为此进行所有这些转换.但经过更多的研究,https://docs.mongodb.com/manual/reference/command/geoNear/#dbcmd.geoNear,它说,如果spherical: true那时它使用米.

所以我只是写了一个新的转换方法,所以当我maxDistance在查询中设置km时,我会转换它并使用m代替,现在一切都很好!

var meterConversion = (function() {
    var mToKm = function(distance) {
        return parseFloat(distance / 1000);
    };
    var kmToM = function(distance) {
        return parseFloat(distance * 1000);
    };
    return {
        mToKm : mToKm,
        kmToM : kmToM
    };
})();

/* GET list of locations */
module.exports.locationsListByDistance = function(req, res) {
    var lng = parseFloat(req.query.lng);
    var lat = parseFloat(req.query.lat);
    var maxDistance = parseFloat(req.query.maxDistance);
    if ((!lng && lng !== 0) || (!lat && lat !== 0) || !maxDistance) {
        console.log('locationsListByDistance missing params');
        sendJsonResponse(res, 404, {
            "message" : "lng, lat and maxDistance query parameters are all required"
        });
        return;
    }
    var point = {
        type: "Point",
        coordinates: [lng, lat]
    };
    var geoOptions =  {
        spherical: true,
        maxDistance: meterConversion.kmToM(maxDistance),
        num: 10
    };
    Loc.geoNear(point, geoOptions, function(err, results, stats) {
        var locations;
        console.log('Geo Results', results);
        console.log('Geo stats', stats);
        if (err) {
            console.log('geoNear error:', err);
            sendJsonResponse(res, 404, err);
        } else {
            locations = buildLocationList(req, res, results, stats);
            sendJsonResponse(res, 200, locations);
        }
    });
};

var buildLocationList = function(req, res, results, stats) {
    var locations = [];
    results.forEach(function(doc) {
        locations.push({
            distance: meterConversion.mToKm(doc.dis), 
            name: doc.obj.name,
            address: doc.obj.address,
            rating: doc.obj.rating,
            facilities: doc.obj.facilities,
            _id: doc.obj._id
        });
    });
    return locations;
};
Run Code Online (Sandbox Code Playgroud)

特别感谢@Saleem和其他帮我解决问题的人.