关于Mongoose的geoNear方法的使用

背景

最近在学习MEAN,看的是Simon HelmesGetting MEAN with Mongo, Express, ANgular, and Node这本书。其中Chapter 8 Adding Angular components to an Express application中涉及到了MongoosegeoNear方法的使用。不过自己在按照作者的方法进行测试的时候,发现并不能输出想要的结果。通过相关研究找到了解决的方法,因此分享。

问题

作者在书中演示了通过浏览器的navigator.geolocation发送经纬度坐标到API接口,接着后台使用MongoosegeoNear方法,从数据库中将离目标坐标较近的数据推送出来。后台从Mongo中取数的大致代码如下:

/* 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);
  var point = {
    type: "Point",
    coordinates: [lng, lat]
  };
  var geoOptions = {
    spherical: true,
    maxDistance: theEarth.getRadsFromDistance(maxDistance),
    num: 10
  };
  if ((!lng && lng!==0) || (!lat && lat!==0) || ! maxDistance) {
    // ...
  }
  Loc.geoNear(point, geoOptions, function(err, results, stats) {
    // ...
  });
};

其中,作者的意思是maxDistance数据是按照公里进行输入,然后转换为弧度,并把弧度作为参数传入geoNear中。但是得到的结果,确实没有任何数据输出。

解决

经过查找后发现,Mongo中对此是如下的定义:

2dsphere Index

If using a 2dsphere index, you can specify either a GeoJSON point or a legacy coordinate pair for the near value.
You must include spherical: true in the syntax.
With spherical: true, if you specify a GeoJSON point, MongoDB uses meters as the unit of measurement:

db.runCommand( {
   geoNear: <collection> ,
   near: { type: "Point" , coordinates: [ <coordinates> ] } ,
   spherical: true,
   ...
} )

With spherical: true, if you specify a legacy coordinate pair, MongoDB
uses radians as the unit of measurement:

db.runCommand( {
   geoNear: <collection> ,
   near: [ <coordinates> ],
   spherical: true,
   ...
} )

书中的源代码确实是GeoJSON的格式,那为何作者使用了弧度,而没有使用米呢?原来Mongoose3.9.5版本才支持了Mongo的这个设置。原文如下:

3.9.5 / 2014-11-10
fixed; geoNear() no longer enforces legacy coordinate pairs - supports GeoJSON #1987 alabid

用可能是作者在写书的时候,还用的OK,后来版本更新后,设置就失效了。

解决

因此,按照作者原来的思路,代码应该改为:

/* GET list of locations */
module.exports.locationsListByDistance = function(req, res) {
    // ...
    var geoOptions = {
        spherical: true,
        maxDistance: maxDistance * 1000,    // <--
        num: 10
    };
    // ...
};

var buildLocationList = function(req, res, results, stats) {
    var locations = [];
    results.forEach(function(doc) {
        locations.push({
            distance: doc.dis / 1000,    // <--
            // ...
        });
    });
    return locations;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值