流星:用两点搜索最近的游乐设施
Meteor: Search the nearest ride with two points
我正在构建一个汽车共享应用程序并设置游乐设施,我的数据库中有这种插入:
{
"_id": "YyPpkCDhTKStGw6CL",
"authorId": "W6zvbcqit4Mw6a2iK",
"stages": [
{
"caption": "Paris, France",
"type": "Point",
"coordinates": [
2.3522219000000177,
48.856614
]
},
{
"caption": "Lyon, France",
"type": "Point",
"coordinates": [
4.835659,
45.764043
]
},
{
"caption": "Toulouse, France",
"type": "Point",
"coordinates": [
1.4442090000000007,
43.604652
]
}
],
}
阶段按要求的顺序列出(巴黎 -> 里昂 -> 图卢兹)。
然后我有一个带有两个输入的简单表单(start 和 end)。
我的问题是:如何找到最近的乘车点?
看来我必须做那样的事情:
在以下位置查找游乐设施:
- stages.X 附近 开始
- stages.Y 接近 结束
- X < Y
你知道如何进行这样的查询吗?
我发现了一个奇怪的方法来完成这项工作,这里是:
// Set up of arguments and scope
var from = [2.3522219000000177, 48.856614];
var to = [4.835659, 45.764043];
var maxDistance = 2000; // in meters
// First, find ids where rides are near my "from" point
var ids = Rides.find({
stages: {
$near: {
$geometry: {
type: 'Point',
coordinates: from,
},
$maxDistance: maxDistance,
}
}
}, {
fields:{
_id:1
}
}).map(function(item){return item._id;});
// Then, find rows which are near my "to" point BUT restricting it to my ids found above
var results = Rides.find({
_id: {$in: ids},
stages: {
$near: {
$geometry: {
type: 'Point',
coordinates: to,
},
$maxDistance: maxDistance,
}
}
});
// Foreach the rows to filter the case where I match the points in the wrong order
var filtered = [];
results.forEach(function(row){
var distFrom = [];
var distTo = [];
_(row.stages).each(function(stage){
distFrom.push(calcDistance(stage.coordinates, from));
distTo.push(calcDistance(stage.coordinates, to));
});
var nearestFrom = _.indexOf(distFrom, _.min(distFrom));
var nearestTo = _.indexOf(distTo, _.min(distTo));
if(nearestFrom < nearestTo)
filtered.push(row);
});
// My final results!
console.log(filtered);
以及计算两点间距离的函数:
calcDistance = function(p1, p2){
var R = 6378137; // Earth’s mean radius in meter
var dLat = rad(p2[0] - p1[0]);
var dLong = rad(p2[1] - p1[1]);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(rad(p1[0])) * Math.cos(rad(p2[0])) *
Math.sin(dLong / 2) * Math.sin(dLong / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return Math.round(d); // returns the distance in meter
}
我正在构建一个汽车共享应用程序并设置游乐设施,我的数据库中有这种插入:
{
"_id": "YyPpkCDhTKStGw6CL",
"authorId": "W6zvbcqit4Mw6a2iK",
"stages": [
{
"caption": "Paris, France",
"type": "Point",
"coordinates": [
2.3522219000000177,
48.856614
]
},
{
"caption": "Lyon, France",
"type": "Point",
"coordinates": [
4.835659,
45.764043
]
},
{
"caption": "Toulouse, France",
"type": "Point",
"coordinates": [
1.4442090000000007,
43.604652
]
}
],
}
阶段按要求的顺序列出(巴黎 -> 里昂 -> 图卢兹)。 然后我有一个带有两个输入的简单表单(start 和 end)。 我的问题是:如何找到最近的乘车点?
看来我必须做那样的事情:
在以下位置查找游乐设施:
- stages.X 附近 开始
- stages.Y 接近 结束
- X < Y
你知道如何进行这样的查询吗?
我发现了一个奇怪的方法来完成这项工作,这里是:
// Set up of arguments and scope
var from = [2.3522219000000177, 48.856614];
var to = [4.835659, 45.764043];
var maxDistance = 2000; // in meters
// First, find ids where rides are near my "from" point
var ids = Rides.find({
stages: {
$near: {
$geometry: {
type: 'Point',
coordinates: from,
},
$maxDistance: maxDistance,
}
}
}, {
fields:{
_id:1
}
}).map(function(item){return item._id;});
// Then, find rows which are near my "to" point BUT restricting it to my ids found above
var results = Rides.find({
_id: {$in: ids},
stages: {
$near: {
$geometry: {
type: 'Point',
coordinates: to,
},
$maxDistance: maxDistance,
}
}
});
// Foreach the rows to filter the case where I match the points in the wrong order
var filtered = [];
results.forEach(function(row){
var distFrom = [];
var distTo = [];
_(row.stages).each(function(stage){
distFrom.push(calcDistance(stage.coordinates, from));
distTo.push(calcDistance(stage.coordinates, to));
});
var nearestFrom = _.indexOf(distFrom, _.min(distFrom));
var nearestTo = _.indexOf(distTo, _.min(distTo));
if(nearestFrom < nearestTo)
filtered.push(row);
});
// My final results!
console.log(filtered);
以及计算两点间距离的函数:
calcDistance = function(p1, p2){
var R = 6378137; // Earth’s mean radius in meter
var dLat = rad(p2[0] - p1[0]);
var dLong = rad(p2[1] - p1[1]);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(rad(p1[0])) * Math.cos(rad(p2[0])) *
Math.sin(dLong / 2) * Math.sin(dLong / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return Math.round(d); // returns the distance in meter
}