通过$ near过滤文档中存储的距离的文档 [英] Filter Documents by Distance Stored in Document with $near

查看:75
本文介绍了通过$ near过滤文档中存储的距离的文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下示例来更好地解释我的需求.

I am using the following example to better explain my need.

我在地图上有一组点(用户),收集模式如下

I have a set of points(users) on a map and collection schema is as below

{
  location:{
    latlong:[long,lat]
  },
  maxDistance:Number
}

我有另一个集合,其中发生了该地区的事件.模式在下面给出

i have another collection with events happening in the area. schema is given below

{
  eventLocation:{
    latlong:[long,lat]
  }
}

现在,用户可以添加他们的位置以及他们要参加一个事件要旅行的最大距离并保存它.

now users can add their location and the maximum distance they want to travel for to attend an event and save it.

每当发布新事件时,所有满足其首选项的用户都将收到通知.现在我该如何查询.我尝试在用户架构上执行以下查询

whenever a new event is posted , all the users satisfying their preferences will get a notification. Now how do i query that. i tried following query on user schema

{
  $where: {
    'location.latlong': {
      $near: {
        $geometry: {
          type: "Point",
          coordinates: [long,lat]
        },
        $maxDistance: this.distance
      }
    }
  }
}

遇到错误

error: {
    "$err" : "Can't canonicalize query: BadValue $where got bad type",
    "code" : 17287
}

我如何查询上述情况,因为maxDistance由用户定义并且不固定.我正在使用2dsphere索引.

how do i query the above case as maxDistance is defined by user and is not fixed. i am using 2dsphere index.

推荐答案

假设您已经确定要在接收事件数据并对其进行处理时对事件数据采取行动(如果没有,那么这是另一个问题,但是请查看

Presuming you have already worked out to act on the event data as you recieve it and have it in hand ( if you have not, then that is another question, but look at tailable cursors ), then you should have an object with that data for which to query the users with.

因此,使用 $where $where ,因为它无法访问从 $near 反正操作.相反,您想要的是 $geoNear 来自聚合框架.这可以投影从查询中找到的距离",并允许以后的阶段根据用户存储的值过滤"结果,以获取他们要传播到已发布事件的最大距离:

This is therefore not a case for JavaScript evaluation with $where, as it cannot access the query data returned from a $near operation anyway. What you want instead is $geoNear from the aggregation framework. This can project the "distance" found from the query, and allow a later stage to "filter" the results against the user stored value for the maximum distance they want to travel to published events:

// Represent retrieved event data
var eventData = {
  eventLocation: {
    latlong: [long,lat]
  }
};

// Find users near that event within their stored distance
User.aggregate(
  [
    { "$geoNear": {
      "near": {
        "type": "Point",
        "coordinates": eventData.eventLocation.latlong
      },
      "distanceField": "eventDistance",
      "limit": 100000,
      "spherical": true
    }},
    { "$redact": {
      "$cond": {
        "if": { "$lt": [ "$eventDistance", "$maxDistance" ] },
        "then": "$$KEEP",
        "else": "$$PRUNE"
      }
    }}
  ]
  function(err,results) {
    // Work with results in here
  }
)

现在,您确实需要注意返回的数字,因为由于您似乎存储在旧式坐标对"中而不是GeoJSON中,因此从此操作返回的距离将以弧度而不是标准距离表示.因此,假设您要在用户对象上存储英里"或公里",则需要通过手册中使用球面几何计算距离" .

Now you do need to be careful with the returned number, as since you appear to be storing in "legacy coordinate pairs" instead of GeoJSON, then the distance returned from this operation will be in radians and not a standard distance. So presuming you are storing in "miles" or "kilometers" on the user objects then you need to calculate via the formula mentioned in the manual under "Calculate Distances Using Spherical Geometry" as mentioned in the manual.

基本原理是您需要除以地球的赤道半径,即3,963.2英里或6,378.1公里,才能将其转换为与所存储的相比.

The basics are that you need to divide by the equatorial radius of the earth, being either 3,963.2 miles or 6,378.1 kilometers to convert for a comparison to what you have stored.

另一种方法是将其存储在GeoJSON中,以米为单位进行一致的测量.

The alternate is to store in GeoJSON instead, where there is a consistent measurement in meters.

假设公里"的"if"行变为:

Assuming "kilometers" that "if" line becomes:

"if": { "$lt": [
    "$eventDistance",
    { "$divide": [ "$maxDistance", 6,378.1 ] }
 ]},

为了可靠地将您存储的公里值与重新计算的弧度结果进行比较.

To reliably compare your stored kilometer value to the radian result retured.

要注意的另一件事是,$geoNear的默认限制"为100个结果,因此您需要在此处将限制"参数抽取"到预期用户可能匹配的数字.对于大型系统,您甚至可能希望在用户ID的范围列表"中执行此操作,但是您可以在单个聚合操作中达到内存允许的最大大小,并可能添加

The other thing to be aware of is that $geoNear has a default "limit" of 100 results, so you need to "pump up" the "limit" argument there to the number for expected users to possibly match. You might even want to do this in "range lists" of user id's for a really large system, but you can go as big as memory allows within a single aggreation operation and possibly add allowDiskUse where needed.

如果您不调整该参数,则仅返回最接近的100个结果(默认),这甚至可能不适合您下一步用于过滤从开始"的事件开始的操作.不过请使用常识,因为您肯定有最大的距离甚至可以过滤掉潜在的用户,并且也可以将其添加到查询中.

If you don't tune that parameter, then only the nearest 100 results ( default ) will be returned, which may well no even suit your next operation of filtering those "near" the event to start with. Use common sense though, as you surely have a max distance to even filter out potential users, and that can be added to the query as well.

如上所述,这里的要点是返回距离以进行比较,因此下一阶段是 $redact 操作,可以将用户自己的旅行距离"值与事件返回的距离进行匹配.最终结果只会给与事件有距离约束的那些用户有资格获得通知.

As stated, the point here is returning the distance for comparison, so the next stage is the $redact operation which can fiter the user's own "travel distance" value against the returned distance from the event. The end result gives only those users that fall within their own distance contraint from the event who will qualify for notification.

这是逻辑.您可以预测从用户到事件的距离,然后将用户准备旅行的距离与用户存储的值进行比较.没有JavaScript,并且所有原生操作符都使其变得非常快.

That's the logic. You project the distance from the user to the event and then compare to the user stored value for what distance they are prepared to travel. No JavaScript, and all native operators that make it quite fast.

也如选项和一般注释中所述,我确实建议您使用"2dsphere"索引进行准确的球面距离计算,并转换为GeoJSON存储以将坐标存储在数据库对象中,因为它们都是产生一致结果的通用标准.

Also as noted in the options and the general commentary, I really do suggest you use a "2dsphere" index for accurate spherical distance calculation as well as converting to GeoJSON storage for your coordinate storage in your database Objects, as they are both general standards that produce consistent results.

这篇关于通过$ near过滤文档中存储的距离的文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆