将 geoNear 查询与另一个查询组合以获取值

Posted

技术标签:

【中文标题】将 geoNear 查询与另一个查询组合以获取值【英文标题】:combine geoNear query with another query for a value 【发布时间】:2014-10-24 09:50:31 【问题描述】:

我有一个使用 node.js mongodb 和 mongoose 实现的地理数据 api。 我想用两个条件查询我的数据。

首先,我使用 geoNear 来获取给定半径内的所有位置,效果很好。 其次,我想按类型进一步过滤位置。

这是我的架构:

var GeoLocationSchema   = new Schema(
    name: String,
    type: String,
    loc: 
        type: 
            type: String,
            required: true,
            enum: ["Point", "LineString", "Polygon"],
            default: "Point"
        ,
        coordinates: [Number]
    
);
// ensure the geo location uses 2dsphere
GeoLocationSchema.index( loc : "2dsphere" );

这是我的 geoNear 查询:

router.route("/locations/near/:lng/:lat/:type/:max")

    // get locations near the get params
    .get(function(req, res) 
        // setup geoJson for query
        var geoJson             = ;
        geoJson.type            = "Point";
        geoJson.coordinates     = [parseFloat(req.params.lng), parseFloat(req.params.lat)];

        // setup options for query
        var options             = ;
        options.spherical       = true;
        options.maxDistance     = parseInt(req.params.max)/6370000;

        // query db with mongoose geoNear wrapper
        GeoLocation.geoNear(geoJson, options, function (err, results, stats) 
            if (err)
                res.send(err);
            res.json(results);
        );
    );

是否有可能将 geoNear 查询与特定类型位置的查询结合起来,或者我可以以某种方式过滤结果?

提前致谢。

【问题讨论】:

使用 $geoNear 聚合阶段作为管道中的第一阶段。您可以使用$match 阶段等进行进一步的条件/操作。 【参考方案1】:

只要您的 MongoDB 服务器足够新,即 2.6 或更高版本,那么此功能实际上已移至通用查询引擎。这里的 mongoose 方法包装了 .runCommand() 表单,该表单被认为在所有未来版本中都已弃用,因此只需放置一个带有其他运算符的标准查询即可。

GeoLocation.find(
    "$nearSphere": 
        "$geometry": 
            "type": "Point",
            "coordinates": [parseFloat(req.params.lng), parseFloat(req.params.lat)] 
        ,
        "$maxDistance": distanceInMeters
    ,
    "loc.type": "Point"
,function(err,docs) 

   // The documents are also mongoose document objects as well
);

请参阅$nearSphere 或其他运算符的更多选项以获取选项。这里的主要区别是$maxDistance 在使用 GeoJSON 表单时以米为单位,而不是在其他情况下以弧度为单位。

当然还有用于聚合管道的$geoNear 运算符。这在 MongoDB 2.4 中可用,并且可以采用其他选项(例如“查询”)来进一步缩小结果范围。这里的另一个可能的优势是它会将一个字段“投影”到您的结果中,表示距查询点的“距离”。这可用于其他计算或自定义排序:

GeoLocation.aggregate(
    [
         "$geoNear": 
            "near": 
                "type": "Point",
                "coordinates": [parseFloat(req.params.lng), parseFloat(req.params.lat)]
            ,
            "distanceField": "distance",
            "maxDistance": distanceInMeters,
            "spherical": true,
            "query":  "loc.type": "Point" 
        ,
         "$sort":  "distance": -1   // Sort nearest first
    ],
    function(err,docs) 

       // These are not mongoose documents, but you can always cast them
    
);

需要注意的其他区别是,在标准查询表单中,结果不再像在“命令”表单中那样限制为 100 个文档。默认情况下,聚合$geoNear 限制为 100 个文档作为结果,但返回的文档数量可以通过管道命令的附加“限制”选项进行调整。聚合语句不会“排序”结果,除了从搜索返回的最大文档是给定条件的***结果,但它们没有按顺序返回,因此您需要按所示对它们进行排序。

在任何一种情况下,您都应该将代码移动到使用这些形式中的任何一种,因为命令形式被认为已被弃用,并且将来会被删除。 mongoose API 是否将其方法保留为这些表单之一的“包装器”尚不清楚,但几乎不可能,因此最好坚持使用受支持的表单。

【讨论】:

感谢您提供如此详细的回答!【参考方案2】:

您可以像这样将附加查询作为选项传递给 mongoose geoNear 函数:

   // setup geoJson for query
    var geoJson             = ;
    geoJson.type            = "Point";
    geoJson.coordinates     = [parseFloat(req.params.lng), parseFloat(req.params.lat)];

    // setup options for query
    var options             = ;
    options.spherical       = true;
    options.maxDistance     = parseInt(req.params.max)/6370000;
    // you can put any query here to further refine the result.
    options.query =  "loc.type": "Point" ;

    // query db with mongoose geoNear wrapper
    GeoLocation.geoNear(geoJson, options, function (err, results, stats) 
        if (err)
            res.send(err);
        res.json(results);
    );

【讨论】:

以上是关于将 geoNear 查询与另一个查询组合以获取值的主要内容,如果未能解决你的问题,请参考以下文章

$near 错误 - 规划器返回错误:无法找到 $geoNear 查询的索引

标准 sql 查询以获取与另一个表匹配的记录字段(Google BigQuery)

SQL查询以获取与另一列的MAX值对应的列值?

geoNear查询 near查询的升级版

过滤与另一个表匹配的查询

Oracle SQL 查询问题