将geoNear查询与另一个值查询相结合

时间:2014-08-30 16:02:37

标签: node.js mongodb mongoose geospatial aggregation-framework

我有一个用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查询与特定类型位置的查询相结合,还是可以以某种方式过滤结果?

提前致谢。

2 个答案:

答案 0 :(得分:4)

只要您的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是否将其方法保留为其中一种形式的“包装”尚不清楚,但大多不太可能,因此最好坚持使用受支持的表单。

答案 1 :(得分: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);
    });