MongoDB - Distinct,Limit和Sort可获得更好的结果

时间:2015-03-17 17:53:32

标签: python mongodb pymongo

我正在尝试开发一个查询来帮助在MongoDB中混合搜索请求中的结果。我的集合的示例(和非常简化的版本)看起来像这样。每个文档都有一个查询位置,列表质量排名以及插入列表的提供商名称。

[
  {
    "location": "paris",
    "ranking": "998",
    "provider": "Alpha"
  },
  {
    "location": "paris",
    "ranking": "965",
    "provider": "Alpha"
  },
  {
    "location": "paris",
    "ranking": "945",
    "provider": "Alpha"
  },
  {
    "location": "paris",
    "ranking": "933",
    "provider": "Alpha"
  },
  {
    "location": "paris",
    "ranking": "953",
    "provider": "Alpha"
  },
  {
    "location": "paris",
    "ranking": "983",
    "provider": "Alpha"
  },
  {
    "location": "paris",
    "ranking": "700",
    "provider": "Beta"
  },
  {
    "location": "paris",
    "ranking": "745",
    "provider": "Beta"
  },
  {
    "location": "paris",
    "ranking": "670",
    "provider": "Omega"
  },
  {
    "location": "paris",
    "ranking": "885",
    "provider": "Omega"
  },
  {
    "location": "paris",
    "ranking": "500",
    "provider": "Omega"
  },
  {
    "location": "london",
    "ranking": "600",
    "provider": "Omega"
  },
  {
    "location": "london",
    "ranking": "650",
    "provider": "Beta"
  }
]

正如您所看到的,提供商Alpha拥有最多的列表和最佳排名。因此,当我搜索巴黎并按排名排序时,Alpha提供商的所有列表都会被置于顶部,而Beta和Omega的列表则被推到了最底层。

我想做的是将每个提供商限制为3.因此即使Alphas仍然位居榜首,他们也会被限制为3,从而允许Betas和Omegas更高。然后剩下的Alpha可以在"第2页"当使用.skip时。

如果我在Python中这样做,同步示例将如下所示。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

results = []

providersAvailable = colc.find({'location': 'paris'}).distinct('provider')
for provider in providersAvailable:
    search = colc.find({'provider':provider, 'location': 'paris'}).limit(3)
    results = results + list(search)

return sorted(results, key=lambda k: k['ranking']) 

这非常耗时,而且整体上很糟糕,特别是收集了250万份文档。我怎么能在Mongos方面做到这一切?谢谢!

1 个答案:

答案 0 :(得分:0)

您可以尝试一些服务器端JS例如。

var providers = db.runCommand({distinct:"colc", key:"provider"}).values
for(p in providers){
   var c = db.colc.find({"provider":providers[p]}).sort({"ranking":-1}).limit(3);
   c.forEach(printjson);
}

但由于所有JS都被解释为它不会是最快的选择。

您可以使用聚合框架,这将主要是服务器端点击,例如。

db.colc.aggregate([ 
    {$match: {"location":"paris"}}, 
    {$group:{_id: { "provider": "$provider", "location":"$location"}, 
             "rankings" : { $addToSet: "$ranking"} } } 
]);

但是你需要一些客户端代码来从返回数组中挑选出每个提供商的排名。

{
    "result" : [
        {
            "_id" : {
                "provider" : "Omega",
                "location" : "paris"
            },
            "rankings" : [
                "500",
                "885",
                "670"
            ]
        },
        {
            "_id" : {
                "provider" : "Beta",
                "location" : "paris"
            },
            "rankings" : [
                "745",
                "700"
            ]
        },
        {
            "_id" : {
                "provider" : "Alpha",
                "location" : "paris"
            },
            "rankings" : [
                "983",
                "953",
                "933",
                "945",
                "965",
                "998"
            ]
        }
    ],
    "ok" : 1
}