MongoDB:" find()"与外国钥匙不同的集合

时间:2015-02-23 12:47:25

标签: php mongodb mongo-collection

很抱歉,如果这可能是一个典型的“RTM”问题,我是MongoDB的新手并做了一些手工阅读,但遗憾的是我没有找到解决这个问题的尝试。

我有两个集合,一个集合是“文章”,其中包含一个“类别”数组,其中包含一个或多个具有我的类别集合ID的MongoID对象。

我想显示所有类别,其中包含引用该类别的文章数量。在我的解决方案下面,我发现了一些研究时间:

我的类别集合:

Array
(
    [_id] => MongoId Object
        (
            [$id] => 54eb1510974f5590179702aa
        )

    [name] => Test
    [multiplier] => 2    
)

我的文章集:

Array
(
    [_id] => MongoId Object
        (
            [$id] => 54e5e39f974f5535248b4bdf
        )

    [productnumber] => 63483

    [categories] => Array
        (
            //... other categories...
            [1] => MongoId Object
                (
                    [$id] => 54eb1510974f5590179702aa
                )

        )
    [image] => /var/www/mongodbtest/Files/FTP/images/63483.jpg
)

我目前的PHP代码:

foreach($oAllCategories as $oCategory)
{            
    $iArticleCount = $oArticles->find(array('categories' => $oCategory['_id']))->count();   
    // Debug
    echo $oCategory['name'].' = '.$iArticleCount.' <br />';
}  

现在问题是,有70,000篇文章和2,200个类别,这很慢并且需要花费很多时间。此外,我不能按照文章的数量对我的类别进行排序,而不会遍历所有文章。

有更好的方法吗?

1 个答案:

答案 0 :(得分:2)

我不熟悉PHP,所以我将使用mongo shell语法。您可以使用聚合管道一次性计算此服务器端:

db.articles.aggregate([
    { "$unwind" : "$categories" },
    { "$group" : { "_id" : "$categories", "count" : { "$sum" : 1 } } }
])

$unwind阶段“展开”每个文章文档沿着categories数组,例如

{ "x" : 1, "categories" : ["a", "b", "c"] }
===>
{ "x" : 1, "categories" : "a" },
{ "x" : 1, "categories" : "b" },
{ "x" : 1, "categories" : "c" }

然后$group阶段合并categories值的所有文档,并计算组中元素的数量。结果看起来像

{ "_id" : "c", "count" : 1 }
{ "_id" : "b", "count" : 1 }
{ "_id" : "a", "count" : 1 }

您的_id将是_id类别,您可以将其与categories集合一起转换为名称。我认为您应该只在文章中存储类别名称和_id。类别名称实际更改的频率是多少?

通常,您应该避免执行此类操作,因为聚合扫描每篇文章,将其扩展为多个文档,将每个文档处理到相应的组中。最好在另一个集合中逐步维护此信息。例如,每次插入该类别的文章时,您都可以增加每个类别文档中的计数。