【问题标题】:mongo query select only first of monthmongo查询只选择第一个月
【发布时间】:2025-12-30 08:45:11
【问题描述】:

是否可以只查询 mongo 日期字段的月份的第一天(或最后一个或任何一个?)。

我经常在 $group 子句中使用$date aggregation operators

基本上,我有一个已经为每个月的每一天聚合(平均)的字段。我只想选择其中的一天(以代表整个月的值。)

以下是 2014 年 1 月 1 日至 2015 年 2 月 1 日创下的记录示例,price 为每日价格,28day_avg 为 28 天的每月平均价格。

{ "date" : ISODate("2014-01-01T00:00:00Z"), "_id" : ObjectId("533b3697574e2fd08f431cff"), "price": 59.23,  "28day_avg": 54.21}
{ "date" : ISODate("2014-01-02T00:00:00Z"), "_id" : ObjectId("533b3697574e2fd08f431cff"), "price": 58.75,  "28day_avg": 54.15}
...

{ "date" : ISODate("2015-02-01T00:00:00Z"), "_id" : ObjectId("533b3697574e2fd08f431cff"), "price": 123.50,  "28day_avg": 122.25} 

方法1。 我目前正在使用 $month 数据运行聚合(并对 price 求和),但一个问题是我试图检索基础日期值 ISODate("2015-02-01T00:00:00Z") 与 0,1,2几个日期聚合附带的值(在一周、一个月、一年的第一天循环)。 mod(28) 约会?

方法 2 我想简单地提取28day_avg 的一条记录作为该时期的代表。一个月的第一天就足够了

想要的输出是……

_id: ISODate("2015-02-01T00:00:00Z"), value: 122.25,
_id: ISODate("2015-01-01T00:00:00Z"), value: 120.78,
_id: ISODate("2014-12-01T00:00:00Z"), value: 118.71,
 ...
_id: ISODate("2014-01-01T00:00:00Z"), value: 53.21,

当然,方法 1 到方法 2 的值会有所不同,但这很好。一个是 28 天,而另一个将占 28、30、31 天的月份……不要太在意。

非 agg 是可以的,但也不起作用。又名{"date": { "$mod": [ 28, 0 ]} }

【问题讨论】:

  • 您能否提供一个有问题的示例文档以及您希望如何在输出中汇总日期。这将使您的问题更加清晰。
  • 我不明白方法 1 的具体要求是什么。你能告诉我们有问题的聚合吗?

标签: mongodb


【解决方案1】:

要选择每个月的第一天(方法 2),请使用以下聚合:

db.test.aggregate([
    { "$project" : { "_id" : "$date", "day" : { "$dayOfMonth" : "$date" }, "28day_avg" : 1 } },
    { "$match" : { "day" : 1 } }
])

您不能使用索引进行匹配,因此效率不高。我建议在每个包含 $dayOfMonth 值的文档中添加另一个字段,这样您就可以对其进行索引并进行简单的查找:

{
    "date" : ISODate("2014-01-01T00:00:00Z"),
    "price" : 59.23,
    "28day_avg" : 54.21,
    "dayOfMonth" : 1
}

db.test.ensureIndex({ "dayOfMonth" : 1 })
db.test.find({ "dayOfMonth" : 1 }, { "_id" : 0, "date" : 1, "28day_avg" : 1 })

【讨论】:

  • 啊哈。使用来自 dayofmonth 的 0,1,2 并应用匹配。甜的。而且速度很慢。我会为此研究 crontabbing mongo shell 脚本。谢谢你在纽约的好 mongo 朋友。
  • 最后一个月呢?