【问题标题】:Mongo Aggregate $match after ($sort->$limit)Mongo Aggregate $match after ($sort->$limit)
【发布时间】:2017-06-21 16:22:02
【问题描述】:

考虑以下 mongo 集合“事件”:

{ "_id" : ObjectId("512bc95fe835e68f199c8686"), userId: 1, type: "music" eventNum: 1 }
{ "_id" : ObjectId("512bc962e835e68f199c8687"), userId: 1, type: "music" eventNum: 2 }
{ "_id" : ObjectId("55f5a192d4bede9ac365b257"), userId: 2, type: "music" eventNum: 3 }
{ "_id" : ObjectId("55f5a192d4bede9ac365b258"), userId: 2, type: "music" eventNum: 4 }
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b259"), userId: 1, type: "music" eventNum: 5 }
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b25a"), userId: 1, type: "athletic" eventNum: 6 }
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b25b"), userId: 2, type: "athletic" eventNum: 7 }

每个事件都使用userIdtypeeventNum 创建。我需要找到userId: 1 的前 3 个事件。所以我运行这个查询:

db.getCollection('events').aggregate([
  {
    "$match": {
      "userId": 1
    }
  },
  {
    "$sort": { "eventNum": 1 }
  },
  {
    "$limit": 3
  }
])

返回数据集(注意没有返回“运动”事件):

{ "_id" : ObjectId("512bc95fe835e68f199c8686"), userId: 1, type: "music" eventNum: 1 }
{ "_id" : ObjectId("512bc962e835e68f199c8687"), userId: 1, type: "music" eventNum: 2 }
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b259"), userId: 1, type: "music" eventNum: 5 }

但是,现在,我想要 userId: 1 的所有“运动”事件,但前提是它们在前 3 名中。由于前 3 名中没有“运动”事件,我们希望返回以下查询没有文件:

db.getCollection('events').aggregate([
  {
    "$match": {
      "userId": 1
    }
  },
  {
    "$sort": { "eventTime": 1 }
  },
  {
    "$limit": 3
  },
  {
    "$match": {
      "type": "athletic"
    }
  }
])

但是,这个查询实际上返回了这个数据集:

{ "_id" : ObjectId("55f5a1d3d4bede9ac365b25a"), userId: 1, type: "athletic" eventNum: 6 }

有人可以解释这里发生了什么吗?似乎排序/限制发生在第二场比赛之后。有没有办法在不进行多次查询的情况下解决这个问题?

【问题讨论】:

  • 这确实需要一个例子,但它通常表明你错了。如果您不这么认为,请显示在您的 $match 条件之前返回的文档。
  • 我添加了一个更好的例子来说明这个问题。
  • 除了Pipeline Sequence Optimization,我还能说什么,一直都是个蹩脚的主意。因为这个原因,我不喜欢发生在“在我背后”发生的事情。

标签: mongodb aggregation-framework


【解决方案1】:

您似乎被this bug 之类的东西击中了。

我尝试了您的确切示例,虽然我在 MongoDB 3.4.4 上的行为与您相同,但在 MongoDB 3.0.9 上,您的第二个查询没有返回任何内容。

尝试降级 MongoDB。

【讨论】:

    【解决方案2】:

    @ramnes 是正确的。这是 mongo 3.4.4 中的一个错误。但是,有一种方法可以解决此问题,方法是使用 $replaceRoot 重新分配变量并欺骗后续匹配项使其停留在排序/限制之后。以下查询可解决该问题并返回您期望的结果:

    db.getCollection('events').aggregate([
      {
        "$match": {
          "userId": 1
        }
      },
      {
        "$sort": { "eventTime": 1 }
      },
      {
        "$limit": 3
      },
      {
        "$replaceRoot": {
           "newRoot": "$$ROOT"
        }
      },
      {
        "$match": {
          "type": "athletic"
        }
      }
    ])
    

    【讨论】:

      【解决方案3】:

      这是解决方案。

      db.getCollection('events').aggregate([
      {
        "$match": {
           "$and": [
               {"userId": 1},
               {"type": "athletic"}
           ]
        }
       },
       {
          "$sort": {"eventNum": 1}
       },
       {
         "$limit": 3
       },
       {
         "$group":{
           "_id": null,
           "doc_count": {$sum: 1}, 
           "eventNums": {"$push":"$eventNum"}}
       },
       {
         "$match": {
            "doc_count": 3
       }
      },
      ])
      

      在这种方法中,当没有足够的事件时,它将返回前 3 个事件编号或为空。

      【讨论】:

        【解决方案4】:

        "$sort"更改为以下代码:

         "$sort": { "eventNum": 1 }  !=   "$sort": { "eventTime": 1 }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-01-25
          • 2012-12-20
          • 1970-01-01
          • 2021-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多