Mongodb $和$ sort在不同的字段上并获得最后的匹配记录

时间:2015-05-19 06:48:34

标签: mongodb mongoose mongodb-query

我有一个大约50个湖泊记录的集合。下面是一个样本文件

{
    "_id" : NumberLong(4253223),
    "locId" : 59,
    "startIpNum" : NumberLong("3287940726"),
    "endIpNum" : NumberLong("3287940761"),
    "maxmind_location" : {
        "locId" : 59,
        "country" : "DK",
        "region" : "",
        "city" : "",
        "postalCode" : "",
        "latitude" : "56.0000",
        "longitude" : "10.0000",
        "metroCode" : "",
        "areaCode" : "\n"
    }
}

下面是我正在尝试执行的查询。我想从匹配条件中找到最后一条记录。

find({
        $and: [
                 {startIpNum: { $lte: 459950297 }},
                 {endIpNum: { $gte: 459950297 }} 
              ]
      }).sort({_id : -1}).limit(1)

我在startIpNumendIpNum上设置了升序索引。我已将_id替换为增量id值,如Mysql。

当我在没有sortlimit 1的情况下进行查询时。它给我的结果是0ms。只要我放sort(我需要排序,因为我想要最后一个匹配的记录),查询就会永远挂起。

我也尝试过以下查询,但需要大约700毫秒。用化合物
{startIpNum :1 , endIpNum : 1 , _id : -1 }上的索引,_id上的排序。

 find({
         startIpNum : { $lte: 459950297 }, 
         endIpNum : { $gte: 459950297 }
      }).sort({
                 startIpNum :1,
                 endIpNum :1 ,
                 _id : -1
              }).limit(1).explain({ verbose : true});

如何在第一种方法中实现排序。

这是解释。它仍在扫描370061索引

db.maxmind.find({startIpNum : { $lte: 459950297 }, endIpNum : { $gte: 459950297 } }).sort({startIpNum :1, endIpNum :1 , _id : -1 }).limit(1).hint("startIpNum_1_endIpNum_1__id_-1").explain( { verbose: true } );
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "yogeshTest.maxmind",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "startIpNum" : {
                        "$lte" : 459950297
                    }
                },
                {
                    "endIpNum" : {
                        "$gte" : 459950297
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "LIMIT",
            "limitAmount" : 0,
            "inputStage" : {
                "stage" : "FETCH",
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "keyPattern" : {
                        "startIpNum" : 1,
                        "endIpNum" : 1,
                        "_id" : -1
                    },
                    "indexName" : "startIpNum_1_endIpNum_1__id_-1",
                    "isMultiKey" : false,
                    "direction" : "forward",
                    "indexBounds" : {
                        "startIpNum" : [
                            "[-inf.0, 459950297.0]"
                        ],
                        "endIpNum" : [
                            "[459950297.0, inf.0]"
                        ],
                        "_id" : [
                            "[MaxKey, MinKey]"
                        ]
                    }
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 1,
        "executionTimeMillis" : 433,
        "totalKeysExamined" : 370061,
        "totalDocsExamined" : 1,
        "executionStages" : {
            "stage" : "LIMIT",
            "nReturned" : 1,
            "executionTimeMillisEstimate" : 430,
            "works" : 370062,
            "advanced" : 1,
            "needTime" : 370060,
            "needFetch" : 0,
            "saveState" : 2891,
            "restoreState" : 2891,
            "isEOF" : 1,
            "invalidates" : 0,
            "limitAmount" : 0,
            "inputStage" : {
                "stage" : "FETCH",
                "nReturned" : 1,
                "executionTimeMillisEstimate" : 420,
                "works" : 370061,
                "advanced" : 1,
                "needTime" : 370060,
                "needFetch" : 0,
                "saveState" : 2891,
                "restoreState" : 2891,
                "isEOF" : 0,
                "invalidates" : 0,
                "docsExamined" : 1,
                "alreadyHasObj" : 0,
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "nReturned" : 1,
                    "executionTimeMillisEstimate" : 410,
                    "works" : 370061,
                    "advanced" : 1,
                    "needTime" : 370060,
                    "needFetch" : 0,
                    "saveState" : 2891,
                    "restoreState" : 2891,
                    "isEOF" : 0,
                    "invalidates" : 0,
                    "keyPattern" : {
                        "startIpNum" : 1,
                        "endIpNum" : 1,
                        "_id" : -1
                    },
                    "indexName" : "startIpNum_1_endIpNum_1__id_-1",
                    "isMultiKey" : false,
                    "direction" : "forward",
                    "indexBounds" : {
                        "startIpNum" : [
                            "[-inf.0, 459950297.0]"
                        ],
                        "endIpNum" : [
                            "[459950297.0, inf.0]"
                        ],
                        "_id" : [
                            "[MaxKey, MinKey]"
                        ]
                    },
                    "keysExamined" : 370061,
                    "dupsTested" : 0,
                    "dupsDropped" : 0,
                    "seenInvalidated" : 0,
                    "matchTested" : 0
                }
            }
        },
        "allPlansExecution" : [ ]
    },
    "serverInfo" : {
        "host" : "cus360-H81M-S",
        "port" : 27017,
        "version" : "3.0.3",
        "gitVersion" : "b40106b36eecd1b4407eb1ad1af6bc60593c6105"
    },
    "ok" : 1
}

1 个答案:

答案 0 :(得分:0)

在发布查询的db.collection.getIndexes()explain的输出之前,让我们尝试以下操作。我怀疑你的{startIpNum :1 , endIpNum : 1 , _id : -1 }没有赢得查询计划。

所以你可以试试强迫MongoDB通过提示来使用该索引:

find({
         startIpNum : { $lte: 459950297 }, 
         endIpNum : { $gte: 459950297 }
      }).sort({
                 startIpNum :1,
                 endIpNum :1 ,
                 _id : -1
              }).limit(1).hint({startIpNum :1 , endIpNum : 1 , _id : -1 })

目前,您的查询似乎会获取所有匹配的文档,将它们加载到内存中,然后在那里对它们进行排序。通过提示,使用您的索引,它将最初以正确的顺序选择您的文档。