如何在$ nearSphere查询中使用$ maxDistance的文档属性?

时间:2016-02-11 02:44:08

标签: mongodb meteor geolocation mongodb-query aggregation-framework

我有一个包含这样的文档的集合:

{
    "_id" : "cysMrqjootq6YS6WP",
    “profile” : {
        ……
        "deliveryDistance” : 20,
        "address" : {
            "loc" : {
                "type" : "Point",
                "coordinates" : [
                    —2.120361,
                    52.536273
                ]
            }       }
    }
}

我有一个GeoJSON点,如:

var referencePoint= {
                "type" : "Point",
                "coordinates" : [
                    —2.120361,
                    52.536273
                ]
            }

我正在使用Meteor.js,Node.js和MongoDB。我想创建一个查询,其中此点的maxDistance是每个文档到我的集合中的deliveryDistance属性

如果maxDistance是固定值,则查询为:

myCollection.find({
    “profile.address.loc":{
      "$nearSphere": {
        "$geometry": referencePoint,
        "$maxDistance": 20000 //for 20Kms
      }
    }
  })

但事实并非如此。对于每个文档,maxDistance必须是'profile.deliveryDistance'的值。如何在此查询中将文档中的此值用作maxDistance?可能吗?如果没有,还有其他想法吗?

1 个答案:

答案 0 :(得分:3)

您无法在.find()查询中引用文档的现有属性,并且至少不在$near$nearSphere操作中。

相反,这里的方法是使用聚合框架和$geoNear。这允许您计算与查询点的距离,然后比较是否属于" deliveryDistance"在文件中。

所以对于meteor,你可能最好安装meteorhacks aggregate包,然后做这样的事情:

Meteor.publish("aggResults",function(referencePoint) {
   var self = this;

   var results = myCollection.aggregate([
       { "$geoNear": {
           "near": referencePoint,
           "distanceField": "distance",
           "spherical": true
       }},
       { "$redact": {
           "$cond": {
               "if": { "$lt": [ "$distance", "$profile.deliveryDistance" ] },
               "then": "$$KEEP",
               "else": "$$PRUNE"
           }
       }}
   ]);

   _.each(results,function(result) {
       self.added("client_collection_name",result._id, {
           "profile": result.profile,
           "distance": result.distance           
       });
   });
   self.ready();
})

如果您的MongoDB服务器小于2.6版(并且地理空间查询必须至少为2.4),那么您将使用$project$match来代替$redact来过滤输出不属于" deliveryDistance":

的文件
   var results = myCollection.aggregate([
       { "$geoNear": {
           "near": referencePoint,
           "distanceField": "distance",
           "spherical": true
       }},
       { "$project": {
           "profile": 1,
           "distance": 1,
           "within": { "$lt": [ "$distance", "$profile.distance" ] }
       }},
       { "$match": { "within": true } }
   ]);

但这是基本情况,你给服务器提供工具来计算距离比较,然后返回任何这些文件。

汇总输出的包装实际上取决于您在应用程序中使用数据的重要性。这只是将输出放入客户端可寻址集合的一个示例。

当然,您也可以深入了解驱动程序内部,将.aggregate()称为shown here,但它可能不如使用上述流星程序包灵活。