MongoDB使用$ last和$ cond

时间:2017-02-09 15:37:41

标签: mongodb aggregation-framework

有没有办法在聚合中获取最后一个非零值。这可能吗?

情景:

我有一个事件集合,我在其中存储来自用户的所有事件。我想获取上次购买商品的用户列表,价格为1.99美元,并且上周至少登录过一次。

我的活动集合将包含

等记录
{_id:ObjectId("58af54d5ab7df73d71822708"),uid:1,event:"login"}
{_id:ObjectId("58db7189296fdedde1c04bc1"),uid:2,event:"login"}
{_id:ObjectId("5888419bfa4b69dc4af7c76c"),uid:2,event:"purchase",amount:3}
{_id:ObjectId("5888419bfa4b69dc4af7d45c"),uid:1,event:"purchase",amount:1.9}
{_id:ObjectId("5888819bfa4b69dc4af7c76c"),uid:1,event:"custom",type:3,value:2}

我想做什么:

  db.events.aggregate([{
      {
        $group: {
          _id: uid,
          last_login: {
            $max: {
              $cond: [{
                $eq: ['$event', 'login']
              }, '$_id', 0]
            }
          },
          last_amount: {
            $last: {
              $cond: [{
                $eq: ['$event', 'login']
              }, '$_id', 0]
            }
          }
        }
      }
    }, {
      $match: {
        last_purchase: {
          $gte: ObjectId("58af54d50000000000000000")
        },
        last_amount: 1.9
      }
    }])

显然会失败,因为最后一项将是0作为最后一项。

我期待的输出是

{_id:1,last_login:_id:ObjectId("58af54d5ab7df73d71822708"),last_amount:1.9}

查询是系统生成的。请帮忙。

2 个答案:

答案 0 :(得分:0)

要回答您的问题,您无法使用$ cond修改$ last的行为。因为标准'而不是最后一个条目。 您可以尝试几种替代方案:

  • 更改document schema访问模式,特别是如果这是您应用程序中经常使用的查询。您应该利用架构作为优化应用程序查询的杠杆。
  • 使用其中一个MongoDB supported drivers来处理预期结果。
  • 根据用例,您可以执行2个单独的聚合查询;首先查询上周至少登录过一次的所有用户uid,然后查询最后购买的商品值为1.99美元的用户。

答案 1 :(得分:0)

我找到了一个解决方法。而不是$ last,我在$ group中使用了$ push,并在$ project中添加$ slice和$ setDifference来删除空值。查询现在看起来像

    db.events.aggregate([{
          {
            $group: {
              _id: uid,
              last_login: {
                $max: {
                  $cond: [{
                    $eq: ['$event', 'login']
                  }, '$_id', 0]
                }
              },
              last_amount: {
                $push: {
                  $cond: [{
                    $eq: ['$event', 'login']
                  }, '$_id', null]
                }
              }
            }
          }
        },
    {$project:{last_login:{$slice:[{$setDifference,'$last_login',[null]},-1,1]}}}
    , {
          $match: {
            last_purchase: {
              $gte: ObjectId("58af54d50000000000000000")
            },
            last_amount: 1.9
          }
        }])