mongodb与$ match,$ skip,$ limit和$ geoNear

时间:2016-07-29 22:42:47

标签: mongodb geospatial

我想这样做:

model.User.aggregate([
    //step 1 match criteria
    {
        $match: criteria
    },
    //step 2 skip
    { 
        $skip: offset 
    },
    //step 3 limit
    {
        $limit: limit
    },
    //step 4 sort by computed distance
    {
        $geoNear : {
            near: {type: 'Point', coordinates: coords },
            distanceField: 'currentCity.computed_distance',
            includeLocs: 'currentCity.loc',
            spherical: true,
            uniqueDocs: true,
            distanceMultiplier: 3963.2, //convert to miles (this number is the radius of the earth in miles)
        }
    }
],function(err,users){
    if (err) return res.error(err);
    if (!users.length) return res.error('no matched criteria');
    res.apiResponse(users);
});

$ geoNear 的文档声明:

  

您只能使用$ geoNear作为管道的第一阶段。

阅读文档,我看到我只需通过$match选项将$geoNear移到query内。同样,$limit可以通过$geoNear选项放在limit内。一个问题是,$skip选项没有等价物,所以看起来好像不便于分页?我真的很困惑,为什么$geoNear不能成为管道中的第四步。查询的目标只是找到最佳的n匹配项,其中n = limit,然后按近似值排序。这有可能吗?我无法找到这个特定用例的答案。

我认为一个解决方案可能是执行查询以仅选择匹配文档的ID,转换为ID列表,然后使用$in查询进行聚合,如下所示:

model.User.find(criteria).skip(offset).limit(limit).select('_id').exec(function (err, userIds) {
    var ids = [];
    userIds.forEach(function(u){
        ids.push(u._id);
    });

    model.User.aggregate([
        {
            $geoNear : {
                query: { _id: {$in: $ids } },
                near: {type: 'Point', coordinates: coords },
                distanceField: 'currentCity.computed_distance',
                includeLocs: 'currentCity.loc',
                spherical: true,
                uniqueDocs: true,
                distanceMultiplier: 3963.2, //convert to miles (this number is the radius of the earth in miles)
            }
        }
    ],function(err,users){
        if (err) return res.error(err);
        if (!users.length) return res.error('no matched criteria');
        res.apiResponse(users);
    });
}); 

这可行,但理想情况下,如果可能,我可以在1个查询中执行此操作。任何想法都非常感激。

1 个答案:

答案 0 :(得分:1)

这是一个解决方案:

result = db.cafes.aggregate([{
'$geoNear': {
    'near': {
        'type': 'Point',
        'coordinates': [
            -73.991084,
            40.735863]},
    'spherical': True,
    'distanceField': 'dist',
    'num': 20}
}, {
   '$skip': 10
}])

这种方法还有更好的解决方案:

ids = [42]

result = db.command(
'geoNear', 'cafes',
near={
    'type': 'Point',
    'coordinates': [
        -73.991084,
        40.735863]},
spherical=True,
minDistance=268,
query={
    '_id': {
        '$nin': ids}},
num=10)

关于速度和问题的一个非常好的解释:

https://emptysqua.re/blog/paging-geo-mongodb/