9

如何根据time字段获取第一个和最后一个文档。我可以使用$group和获取$first$last记录,但我不需要在这里分组,只需获取第一个和最后一个完整文档。也许我可以使用slice?此查询不起作用:

{
  "aggregate": "353469045637980_data",
  "pipeline": [
    {
      "$match": {
        "$and": [
          {
            "time": {
              "$gte": 1461369600
            }
          },
          {
            "time": {
              "$lt": 1461456000
            }
          }
        ]
      }
    },
    {
      "$project": {
        "first": {
          "$slice": 1
        },
        "last": {
          "$slice": -1
        }
      }
    }
  ]
}
4

3 回答 3

22

好吧,您需要$group,但您可以简单地使用一个常量(例如null,参见文档),id以便它产生一个组。$$ROOT然后是指您可以使用的文档$first本身$last

$group: {
  _id: null,
  first: { $first: "$$ROOT" },
  last: { $last: "$$ROOT" }
}

当然,您可以引入进一步$project的阶段以将该数据塑造成一个数组(正如您提到的那样,您想要一个列表)等。

作为旁注,您可能需要引入一个$sort阶段以确保$first$last具有正确的含义。

于 2016-08-16T13:21:11.003 回答
0

我知道这并不能直接回答这个问题,但是当我遇到这个问题时会对我有很大帮助。

您可以(如 DAXaholic 解释的那样)使用以下查询来获取相应的文档:

[
  $sort: {...},
  $group: {
    _id: null,
    first: { $first: "$$ROOT" },
    last: { $last: "$$ROOT" }
  }
]

我面临的问题是我收到以下错误:Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting. Aborting operation. Pass allowDiskUse:true to opt in.

要解决此问题(不使用磁盘进行排序),您可以使用:

[
  $group: {
    _id: null,
    first: { $min: "$time" },
    last: { $max: "$time" }
  }
]

优点是您不需要排序,因此可能不会在 100 MB 内存限制中运行。缺点是它不返回整个文档(其中$min/$max匹配),而只返回属性的值(在本例中time)。

于 2021-06-22T11:18:44.740 回答
0

您可以使用一个$facet阶段,结合$sort/$limit阶段:

// { time: ISODate("2021-12-04"), b: "hello" }
// { time: ISODate("2021-12-07"), b: "world" }
// { time: ISODate("2021-12-05"), b: "oups"  }
db.collection.aggregate([
  { $facet: {
    first: [{ $sort: { time: 1 } }, { $limit: 1 }],
    last:  [{ $sort: { time: -1 } }, { $limit: 1 }]
  }},
  { $set: { first: { $first: "$first" }, last: { $last: "$last" } } }
])
// { first: { time: ISODate("2021-12-04"), b: "hello" }, last: { time: ISODate("2021-12-07"), b: "world" } }

$facet阶段允许我们在同一阶段的输入文档上运行多个聚合管道。每个子管道在输出文档中都有自己的字段,其结果存储为文档数组。

因此,每个字段都由其自己的聚合管道生成,其第一阶段$sort的文档按time字段(以相反的顺序),然​​后是$limit仅保留第一项(由所选排序定义的最小项目)的阶段。

管道的第二部分($set阶段)只是用于清理$facet输出格式。


请注意,Mongo 对 a$sort后面的$limit阶段进行了优化(请参见此处)。这允许排序操作在进行时只保留前 n 个结果(在我们的例子中只有 1 个元素)。

另请注意,我们的$sort阶段将受益于在time.

于 2021-12-04T21:46:08.693 回答