Mongo查询从数组中查找畅销书

时间:2013-08-13 20:09:59

标签: mongodb

我对Mongo很新,我很难弄清楚如何编写这个查询。我有一个看起来像这样的订单集合。

{
"_id" : ObjectId("51fade5b8c825bb19d9ef228"),
"o_id" : 1,
...
"order_line" : [
    {
            "ol_id" : 1,
            "ol_o_id" : 1,
            "ol_i_id" : 531,
            "ol_qty" : 280
    },
    {
            "ol_id" : 2,
            "ol_o_id" : 1,
            "ol_i_id" : 90,
            "ol_qty" : 295
    },
    {
            "ol_id" : 3,
            "ol_o_id" : 1,
            "ol_i_id" : 963,
            "ol_qty" : 184
    }
]}

我需要为每件商品找到最畅销的相关商品。

查询需要查找与当前正在查询的ol_i_id一起销售的前5项/ ol_i_id。为了做到这一点,查询需要找到所讨论的“ol_i_id”的所有订单,比如说“ol_i_id”:531,然后将每个售出的商品的“ol_qty”与“ol_i_id”:531相加在整个集合中。然后报告与“ol_i_id”出售的前5名“ol_i_id”:531。

我试图尽可能地理解这一点。

/编辑 到目前为止,我有这个。

 db.orders.aggregate( { $match : { order_line: { $elemMatch : { ol_i_id : 531 } } } },
   { $project : { o_id : 1, order_line : 1} },
   { $unwind: "$order_line"},
   { $limit : 5 } )

将order_line的展开看起来像这样。

   "result" : [
           {
                   "_id" : ObjectId("51fade5b8c825bb19d9ef389
                   "o_id" : 354,
                   "order_line" : {
                           "ol_id" : 1,
                           "ol_o_id" : 354,
                           "ol_i_id" : 2,
                           "ol_qty" : 271
                   }
           },
           {
                   "_id" : ObjectId("51fade5b8c825bb19d9ef389
                   "o_id" : 354,
                   "order_line" : {
                           "ol_id" : 2,
                           "ol_o_id" : 354,
                           "ol_i_id" : 707,
                           "ol_qty" : 138
                   }
           }...

该查询刚刚给出了我们使用ol_i_id购买的所有order_lines,531。现在我需要为每个唯一的ol_i_id求和ol_qty字段并返回前5个。这类似于你可能的东西在亚马逊上看到它说“购买此产品的人还买了另一件东西”希望更有意义。很抱歉对此过于冗长。

理想情况下,我希望它能够以这样的集合返回

 {
    "result" : [
            {
                    "ol_i_id" : 46,
                    "totalSoldWithItem531" : 20012
            },
            {
                    "ol_i_id" : 669,
                    "totalSoldWithItem531" : 19000
            },
            {
                    "ol_i_id" : 5,
                    "totalSoldWithItem531" : 18291
            },
            {
                    "ol_i_id" : 881,
                    "totalSoldWithItem531" : 18101
            },
            {
                    "ol_i_id" : 538,
                    "totalSoldWithItem531" : 17001
            }
    ],
    "ok" : 1
}

/编辑我现在想出了这个,这几乎就是我所需要的。

 db.orders.aggregate( { $match : { order_line: { $elemMatch : { ol_i_id : 531 } } } },
    { $project : { o_id : 1, order_line : 1} },
    { $unwind: "$order_line"},
    { $group : { _id : "$order_line.ol_i_id", 
     totalSales : { $sum : "$order_line.ol_qty" } } },
    { $sort : { totalSales : -1 } },
    { $limit : 5 } )

结果看起来像这样。

 {
    "result" : [
            {
                    "_id" : 531,
                    "totalSales" : 10639
            },
            {
                    "_id" : 655,
                    "totalSales" : 520
            },
            {
                    "_id" : 2,
                    "totalSales" : 500
            },
             ....

我的最后一个问题是如何排除从结果集中查询的项目,因为我对这个数字不感兴趣?在这种情况下,我需要从结果中排除_id:531,因为那是被查询的id。

1 个答案:

答案 0 :(得分:2)

您自己获得了大部分答案,基本上有两种方法可以排除您基于查询的原始项目。一种是简单地将{$match:{_id:{$ne:origID}}}添加到管道的末尾。不要忘记将$limit:5更改为$limit:6,因为您想在排除项目本身后留下五个项目。

更简单的方法是在管道中更早地添加相同的{$match} - 特别是在$unwind之后。整个管道(有一些简化)应如下所示:

db.orders.aggregate( 
    { $match   : { "order_line.ol_i_id" : 531 } } } },
    { $project : { "order_line" : 1, _id:0 } },
    { $unwind  : "$order_line"},
    { $match   : { "order_line.ol_i_id":{"$ne": 531 } } },
    { $group   : { _id : "$order_line.ol_i_id", 
                   totalSales : { $sum : "$order_line.ol_qty" } } },
    { $sort    : { totalSales : -1 } },
    { $limit   : 5 } 
);