我正在使用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);
}
});
};
这是我的代码。运行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."
}
]
}
编辑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);
答案 0 :(得分:6)
所以最初我认为MongoDB在 radians 中工作,所以我一直在尝试为此进行所有这些转换。但经过这里的更多研究https://docs.mongodb.com/manual/reference/command/geoNear/#dbcmd.geoNear后,它说如果spherical: true
则使用米。
所以我只是写了一个新的转换方法,所以当我在查询中的 km 中设置maxDistance
时,我会转换它并使用 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;
};
特别感谢@Saleem和其他帮我解决问题的人。
答案 1 :(得分:2)
我怀疑您的文档结构存在问题。 2dsphere需要GeoJSON格式的文档。
您的文档应该是
"coords" : {
"type" : "Point",
"coordinates" : [
-84.135166,
34.190996
]
}
假设您的文件是:
{
"name": "Starcups",
"address": "125 High Street, Reading, RG6 1PS",
"rating": 3,
"facilities": [
"Hot drinks",
"Food",
"Premium wifi"
],
"location": {
"type": "Point",
"coordinates": [
-84.135166,
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."
}
]
}
并且您正尝试从点[ -84.105146 , 34.190096 ]
db.collection.aggregate(
[
{
'$geoNear': {
'near': {
'type': 'Point',
'coordinates': [ -84.105146 , 34.190096 ]
},
'spherical': true,
'distanceField': 'dist',
'maxDistance': 5000
}
}
]);
上面的查询将返回上面发布的文档,因为它在5000米范围内,只要您在2dsphere
上创建了location
索引
{
"_id" : ObjectId("57327c856b37a28ec9221392"),
"name" : "Starcups",
"address" : "125 High Street, Reading, RG6 1PS",
"rating" : 3.0,
"facilities" : [
"Hot drinks",
"Food",
"Premium wifi"
],
"location" : {
"type" : "Point",
"coordinates" : [
-84.135166,
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.0,
"timestamp" : "13 April 2016",
"reviewText" : "What a great place. I can't say enough good things about it."
},
{
"author" : "Charlie Chaplin",
"rating" : 3.0,
"timestamp" : "16 June 2015",
"reviewText" : "It was okay. Coffee wasn't great, but the wifi was fast."
}
],
"dist" : 2766.0558990550367
}
答案 2 :(得分:0)
检查mongod配置中的distanceMultiplier
:
您也可以使用geoNear的distanceMultiplier选项来转换mongod进程中的弧度,而不是应用程序代码中的弧度。见距离乘数。