比原来的答案更现代一点:
db.collection.aggregate([
{ "$sort": { "date": 1 } },
{ "$group": {
"_id": {
"$subtract": ["$date",{"$mod": ["$date",86400000]}]
},
"doc": { "$last": "$$ROOT" }
}},
{ "$replaceRoot": { "newDocument": "$doc" } }
])
同样的原则适用于您基本上 $sort 集合,然后在所需的分组键上 $group 从分组边界拾取 $last 数据。
让事情变得更清楚一点,因为原始写作是您可以使用$$ROOT 而不是指定每个文档属性,当然$replaceRoot 阶段允许您将该数据完全恢复为原始文档形式。
但一般解决方案仍然是首先$sort,然后在所需的公共键上使用$group,并根据所需属性的分组边界出现的排序顺序保留$last 或$first .
对于 BSON 日期,而不是问题中的时间戳值,请参阅Group result by 15 minutes time interval in MongoDb,了解有关如何在实际使用和返回 BSON 日期值的不同时间间隔内累积的不同方法。
不太清楚你在这里做什么,但如果我的理解是正确的,你可以这样做。所以要获取每天的最后一条记录:
db.collection.aggregate([
// Sort in date order as ascending
{"$sort": { "date": 1 } },
// Date math converts to whole day
{"$project": {
"adco": 1,
"hchc": 1,
"hchp": 1,
"hhphc": 1,
"ptec": 1,
"iinst": 1,
"papp": 1,
"imax": 1,
"optarif": 1,
"isousc": 1,
"motdetat": 1,
"date": 1,
"wholeDay": {"$subtract": ["$date",{"$mod": ["$date",86400000]}]}
}},
// Group on wholeDay ( _id insertion is monotonic )
{"$group":
"_id": "$wholeDay",
"docId": {"$last": "$_id" },
"adco": {"$last": "$adco" },
"hchc": {"$last": "$hchc" },
"hchp": {"$last": "$hchp" },
"hhphc": {"$last": "$hhphc" },
"ptec": {"$last": "$ptec" },
"iinst": {"$last": "$iinst" },
"papp": {"$last": "$papp" },
"imax": {"$last": "$imax" },
"optarif": {"$last": "$optarif",
"isousc": {"$last": "$isouc" },
"motdetat": {"$last": "$motdetat" },
"date": {"$last": "$date" },
}}
])
所以这里的原则是,给定时间戳值,进行日期数学运算以将其投影为每天开始的午夜时间。然后由于文档上的_id 键已经是单调的(一直在增加),那么只需对wholeDay 值进行分组,同时将$last 文档从分组边界中拉出。
如果您不需要所有字段,则只需对您想要的字段进行投影和分组。
是的,您可以在 spring 数据框架中执行此操作。我确定那里有一个包装的命令。但除此之外,获取本机命令的咒语是这样的:
mongoOps.getCollection("yourCollection").aggregate( ... )
作为记录,如果您实际上有 BSON 日期类型而不是时间戳作为数字,那么您可以跳过日期数学:
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$date" },
"month": { "$month": "$date" },
"day": { "$dayOfMonth": "$date" }
},
"hchp": { "$last": "$hchp" }
}}
])