首页 文章

Mongoose查询返回重复结果

提问于
浏览
3

查询接收一对坐标,最大距离半径,“跳过”整数和“限制”整数 . 该函数应根据给定的位置返回最近和最新的位置 . 我的代码中没有可见的错误,但是,当我再次调用查询时,它会返回重复的结果 . “skip”变量根据返回的结果进行更新 .

例:

1)我使用skip = 0,limit = 10进行查询 . 我收到10个非重复的位置 .

2)现在再次调用查询,skip = 10,limit = 10.我收到另外10个位置,其中第一个查询重复结果 .

QUERY

Locations.find({ coordinates :
                 { $near : [ x , y ],
                   $maxDistance: maxDistance }
            })
.sort('date_created')
.skip(skip)
.limit(limit)
.exec(function(err, locations) {
    console.log("[+]Found Locations");
    callback(locations);
});

SCHEMA

var locationSchema = new Schema({
        date_created: { type: Date },
        coordinates: [],
        text: { type: String }
});

我试着到处寻找解决方案 . 我唯一的选择是Mongo的版本?我使用mongoose 4.x.x和mongodb就像2.5.6 . 我相信 . 有任何想法吗?

1 回答

  • 2

    在你想要的那种结果中,有几件事需要考虑,首先要考虑的是你在“date_created”中有一个“二级”排序标准来处理 .

    基本的问题是,MongoDB中的$near运算符和类似运算符目前没有"project"任何字段来指示查询位置的"distance",而只是"default sort"数据 . 因此,为了做到"secondary" sort,需要存在"distance"的字段 . 因此,还有其他选择 .

    第二种情况是“跳过”和“限制”样式分页在大型数据集上表现糟糕,应该尽可能避免 . 因此,最好根据发生的“范围”选择数据,而不是“跳过”之前显示的所有结果 .

    这里要做的第一件事是使用一个命令,它可以"project"与文档的距离以及其他信息 . $geoNear的聚合命令对此有好处,特别是因为我们想要进行其他排序:

    var seenIds = [],
        lastDistance = null,
        lastDate = null;
    
    Locations.aggregate(
        [
            { "$geoNear": {
                "near": [x,y],
                "maxDistance": maxDistance
                "distanceField": "dist",
                "limit": 10
            }},
            { "$sort": { "dist": 1, "date_created": -1 }
        ],
        function(err,results) {
            results.forEach(function(result) {
    
                if ( ( result.dist != lastDistance ) || ( result.date_created != lastDate ) ) {
                    seenIds = [];
                    lastDistance = result.dist;
                    lastDate = result.date_created;
               }
               seenIds.push(result._id);
           });
           // save those variables to session or other persistence
           // do something with results
        }
    )
    

    这是您获取前10个结果的第一次迭代 . 注意循环内部的逻辑,其中结果中的每个文档都会检查“date_created”或现在出现在“date_created”或“dist”字段中的变化 . 文档和发生这种情况的地方,“seenIds”数组将擦除所有当前条目 . 一般操作是所有变量都经过测试,并且可能在每次迭代时更新,如果没有变化,则将项目添加到“seenIds”列表中 .

    正在处理的所有这三个变量都需要存储在等待下一个请求的某个地方 . 对于Web应用程序,会话存储是理想的,但不同的方法各不相同 . 您只需要在我们开始下一个请求时调用这些值,就像在下一次和后续迭代中我们稍微更改一下查询一样:

    Locations.aggregate(
        [
            { "$geoNear": {
                "near": [x,y],
                "maxDistance": maxDistance,
                "minDistance": lastDistance,
                "distanceField": "dist",
                "limit": 10,
                "query": {
                    "_id": { "$nin": seenIds },
                    "date_created": { "$lt": lastDate }
                }
            }},
            { "$sort": { "dist": 1, "date_created": -1 }
        ],
        function(err,results) {
            results.forEach(function(result) {
                if ( ( result.dist != lastDistance ) || ( result.date_created != lastDate ) ) {
                    seenIds = [];
                    lastDistance = result.dist;
                    lastDate = result.date_created;
               }
               seenIds.push(result._id);
           });
           // save those variables to session or other persistence
           // do something with results
        }
    )
    

    因此,输入“minDistance”参数是为了排除已经看到的任何“更接近”的结果,并且在查询中添加额外的检查,其中“date_created”需要“小于”“ lastDistance“也记录了,因为我们按排序的降序排列,最后的”肯定“过滤器排除了列表中记录的任何”_id“值,因为值没有改变 .

    现在使用地理空间数据,“seenIds”列表不太可能增长,因为一般情况下你不会在同一距离找到所有东西,但这是一个分页排序数据列表的一般过程,所以值得理解这个概念 .

    因此,如果您希望能够使用辅助字段对地理空间数据进行排序并考虑“近”距离,那么这是一般方法,通过将距离值投影到文档结果中以及存储最后看到的值在任何不会使它们变得独特的变化之前 .

    一般概念是“提前最小距离”以使每页结果逐渐“远离”查询中使用的源点 .

相关问题