Meteor Collection 根据数组中的最新日期时间查找文档
Meteor Collection Find Documents Based on Latest Date Time in an Array
如何使用日期时间从集合中获取最新文档?
我在 SO 中搜索了这个特定问题,但找不到与我的数据结构相似的示例。我有这样的数据结构:
[
{
stationId: 'xxxxx',
stationName: 'xxxx',
state: 'xxxx',
lat: 'xxxxx',
long: 'xx.xxxxx',
waterLevel: [
{
wlDateTime: '11/04/2022 11:30',
wlSeverity: 'Danger',
wlLevel: 7.5
},
{
wlDateTime: '11/04/2022 09:00',
wlSeverity: 'Danger',
wlLevel: 7.3
},
{
wlDateTime: '11/04/2022 03:00',
wlSeverity: 'Normal',
wlLevel: 5.2
}
],
rainfallData: [
{
rfDateTime: '11/04/2022 11:30',
rfSeverity: 'Heavy',
rfLevel: 21
},
{
rfDateTime: '11/04/2022 10:30',
rfSeverity: 'Heavy',
rfLevel: 21
},
{
rfDateTime: '11/04/2022 9:30',
rfSeverity: 'Heavy',
rfLevel: 21
}
]
}
]
问题是,我怎样才能得到今天 wlDateTime
等于 wlSeverity
等于 Danger
的文档,但我只想要 [=17] 的最新记录=]数组。 rainfallData
数组的情况相同,即 return 今天的最新读数。
样本预期 return 将是这样的:
[
{
stationId: 'xxxxx',
stationName: 'xxxx',
state: 'xxxx',
lat: 'xxxxx',
long: 'xx.xxxxx',
waterLevelData: [
{
wlDateTime: '11/04/2022 11:30', //latest data compared to the array
wlSeverity: 'Danger',
wlLevel: 7.5
}
],
rainfallData: [
{
rfDateTime: '11/04/2022 11:30', //latest data compared to the array
rfSeverity: 'Heavy',
rfLevel: 21
}
]
}
]
我试过这样查询:
Meteor.publish('Alerts', function(){
return AlertLatest.find({
'waterLevelData.wlSeverity':'Danger',
}, {
fields : {
'stationName' : 1,
'state' : 1,
'lat' : 1,
'long' : 1,
'waterLevelData.wlDateTime' : 1,
'waterLevelData.wlSeverity' : 1,
'waterLevelData.wlLevel' : 1,
'rainfallData.rfSeverity' : 1,
}},{sort: { 'waterLevelData.wlDateTime' : -1}});
})
但是查询 returned 数据不是我想要的。任何帮助将不胜感激。
更新
我试过@YuTing提供的方案,就是用聚合来自定义发布查询。我继续阅读了一些关于 Mongodb 聚合的内容,并找到了一个简化流程的 Meteorjs 社区包 (tunguska:reactive-aggregate)。
这是目前有效聚合的样本:
Meteor.publish('PIBDataAlerts', function(){
const start = dayjs().startOf('day'); // set to 12:00 am today
const end = dayjs().endOf('day'); // set to 23:59 pm today
ReactiveAggregate(this, PIBLatest, [
{
$match: {
'stationStatus' : 'ON',
'waterLevelData': { //trying to get only today's docs
"$elemMatch" : {
"wlDateTime" : {
$gte: start.format() , $lt: end.format()
}
}
}
}
},
{
$set: {
waterLevelHFZ: {
$filter: {
input: "$waterLevelData",
as: "w",
cond: {
$and: [
{ $or : [
{ $eq: [ "$$w.wlSeverity", "Alert" ] },
{ $eq: [ "$$w.wlSeverity", "Warning" ] },
{ $eq: [ "$$w.wlSeverity", "Danger" ] },
]},
{ $eq: [ "$$w.wlDateTime", { $max: "$waterLevelData.wlDateTime" } ] }
],
}
}
},
rainfallDataHFZ: {
$filter: {
input: "$rainfallData",
as: "r",
cond: { $eq: [ "$$r.rfDateTime", { $max: "$rainfallData.rfDateTime" } ] }
}
}
}
},
{
$project : {
"stationId": 1,
"stationName" :1,
"state": 1,
"waterLevelHFZ": 1,
"rainfallDataHFZ": 1
}
}
]);
})
我正在努力获取只有 wlDateTime
等于今天的文档。我已经尝试在 $match
中查询,但它 return 为空数组。如果 $match
设置为 {}
,它将 return 所有 1548 条记录,即使 wlDateTime
不等于今天。
我认为您不能按数组字段中的嵌入文档进行排序。这不是 mongodb 的工作方式。
- 将您的日期字符串更改为日期
- 过滤数组以找到最大值
db.collection.aggregate([
{
$match: {
$expr: {
$or: [
{
$ne: [
{
$filter: {
input: "$waterLevel",
as: "w",
cond: {
$eq: [
{
$dateTrunc: {
date: {
$dateFromString: {
dateString: "$$w.wlDateTime",
format: "%d/%m/%Y %H:%M"
}
},
unit: "day"
}
},
{
$dateTrunc: {
date: "$$NOW",
unit: "day"
}
}
]
}
}
},
[]
]
},
{
$ne: [
{
$filter: {
input: "$rainfallData",
as: "r",
cond: {
$eq: [
{
$dateTrunc: {
date: {
$dateFromString: {
dateString: "$$r.rfDateTime",
format: "%d/%m/%Y %H:%M"
}
},
unit: "day"
}
},
{
$dateTrunc: {
date: "$$NOW",
unit: "day"
}
}
]
}
}
},
[]
]
}
]
}
}
},
{
$set: {
waterLevel: {
$map: {
input: "$waterLevel",
as: "w",
in: {
$mergeObjects: [
"$$w",
{
wlDateTime: {
$dateFromString: {
dateString: "$$w.wlDateTime",
format: "%d/%m/%Y %H:%M"
}
}
}
]
}
}
},
rainfallData: {
$map: {
input: "$rainfallData",
as: "r",
in: {
$mergeObjects: [
"$$r",
{
rfDateTime: {
$dateFromString: {
dateString: "$$r.rfDateTime",
format: "%d/%m/%Y %H:%M"
}
}
}
]
}
}
}
}
},
{
$set: {
waterLevel: {
$filter: {
input: "$waterLevel",
as: "w",
cond: {
$and: [
{
$in: [
"$$w.wlSeverity",
[
"Alert",
"Warning",
"Danger"
]
]
},
{
$eq: [
"$$w.wlDateTime",
{
$max: "$waterLevel.wlDateTime"
}
]
},
{
$eq: [
{
$dateTrunc: {
date: "$$w.wlDateTime",
unit: "day"
}
},
{
$dateTrunc: {
date: "$$NOW",
unit: "day"
}
}
]
}
]
}
}
},
rainfallData: {
$filter: {
input: "$rainfallData",
as: "r",
cond: {
$and: [
{
$eq: [
"$$r.rfDateTime",
{
$max: "$rainfallData.rfDateTime"
}
]
},
{
$eq: [
{
$dateTrunc: {
date: "$$r.rfDateTime",
unit: "day"
}
},
{
$dateTrunc: {
date: "$$NOW",
unit: "day"
}
}
]
}
]
}
}
}
}
}
])
but I just want the latest
如果您只对最新的文档感兴趣,您可以省略 sort
并使用自然的负光标:
Meteor.publish('Alerts', function(){
return AlertLatest.find({
'waterLevelData.wlSeverity':'Danger',
}, {
fields : {
'stationName' : 1,
'state' : 1,
'lat' : 1,
'long' : 1,
'waterLevelData.wlDateTime' : 1,
'waterLevelData.wlSeverity' : 1,
'waterLevelData.wlLevel' : 1,
'rainfallData.rfSeverity' : 1,
}},{ hint: { $natural: -1}});
})
它将从末尾开始计算文档数,而不是从头开始。
https://docs.meteor.com/api/collections.html#Mongo-Collection-find
如何使用日期时间从集合中获取最新文档?
我在 SO 中搜索了这个特定问题,但找不到与我的数据结构相似的示例。我有这样的数据结构:
[
{
stationId: 'xxxxx',
stationName: 'xxxx',
state: 'xxxx',
lat: 'xxxxx',
long: 'xx.xxxxx',
waterLevel: [
{
wlDateTime: '11/04/2022 11:30',
wlSeverity: 'Danger',
wlLevel: 7.5
},
{
wlDateTime: '11/04/2022 09:00',
wlSeverity: 'Danger',
wlLevel: 7.3
},
{
wlDateTime: '11/04/2022 03:00',
wlSeverity: 'Normal',
wlLevel: 5.2
}
],
rainfallData: [
{
rfDateTime: '11/04/2022 11:30',
rfSeverity: 'Heavy',
rfLevel: 21
},
{
rfDateTime: '11/04/2022 10:30',
rfSeverity: 'Heavy',
rfLevel: 21
},
{
rfDateTime: '11/04/2022 9:30',
rfSeverity: 'Heavy',
rfLevel: 21
}
]
}
]
问题是,我怎样才能得到今天 wlDateTime
等于 wlSeverity
等于 Danger
的文档,但我只想要 [=17] 的最新记录=]数组。 rainfallData
数组的情况相同,即 return 今天的最新读数。
样本预期 return 将是这样的:
[
{
stationId: 'xxxxx',
stationName: 'xxxx',
state: 'xxxx',
lat: 'xxxxx',
long: 'xx.xxxxx',
waterLevelData: [
{
wlDateTime: '11/04/2022 11:30', //latest data compared to the array
wlSeverity: 'Danger',
wlLevel: 7.5
}
],
rainfallData: [
{
rfDateTime: '11/04/2022 11:30', //latest data compared to the array
rfSeverity: 'Heavy',
rfLevel: 21
}
]
}
]
我试过这样查询:
Meteor.publish('Alerts', function(){
return AlertLatest.find({
'waterLevelData.wlSeverity':'Danger',
}, {
fields : {
'stationName' : 1,
'state' : 1,
'lat' : 1,
'long' : 1,
'waterLevelData.wlDateTime' : 1,
'waterLevelData.wlSeverity' : 1,
'waterLevelData.wlLevel' : 1,
'rainfallData.rfSeverity' : 1,
}},{sort: { 'waterLevelData.wlDateTime' : -1}});
})
但是查询 returned 数据不是我想要的。任何帮助将不胜感激。
更新
我试过@YuTing提供的方案,就是用聚合来自定义发布查询。我继续阅读了一些关于 Mongodb 聚合的内容,并找到了一个简化流程的 Meteorjs 社区包 (tunguska:reactive-aggregate)。
这是目前有效聚合的样本:
Meteor.publish('PIBDataAlerts', function(){
const start = dayjs().startOf('day'); // set to 12:00 am today
const end = dayjs().endOf('day'); // set to 23:59 pm today
ReactiveAggregate(this, PIBLatest, [
{
$match: {
'stationStatus' : 'ON',
'waterLevelData': { //trying to get only today's docs
"$elemMatch" : {
"wlDateTime" : {
$gte: start.format() , $lt: end.format()
}
}
}
}
},
{
$set: {
waterLevelHFZ: {
$filter: {
input: "$waterLevelData",
as: "w",
cond: {
$and: [
{ $or : [
{ $eq: [ "$$w.wlSeverity", "Alert" ] },
{ $eq: [ "$$w.wlSeverity", "Warning" ] },
{ $eq: [ "$$w.wlSeverity", "Danger" ] },
]},
{ $eq: [ "$$w.wlDateTime", { $max: "$waterLevelData.wlDateTime" } ] }
],
}
}
},
rainfallDataHFZ: {
$filter: {
input: "$rainfallData",
as: "r",
cond: { $eq: [ "$$r.rfDateTime", { $max: "$rainfallData.rfDateTime" } ] }
}
}
}
},
{
$project : {
"stationId": 1,
"stationName" :1,
"state": 1,
"waterLevelHFZ": 1,
"rainfallDataHFZ": 1
}
}
]);
})
我正在努力获取只有 wlDateTime
等于今天的文档。我已经尝试在 $match
中查询,但它 return 为空数组。如果 $match
设置为 {}
,它将 return 所有 1548 条记录,即使 wlDateTime
不等于今天。
我认为您不能按数组字段中的嵌入文档进行排序。这不是 mongodb 的工作方式。
- 将您的日期字符串更改为日期
- 过滤数组以找到最大值
db.collection.aggregate([
{
$match: {
$expr: {
$or: [
{
$ne: [
{
$filter: {
input: "$waterLevel",
as: "w",
cond: {
$eq: [
{
$dateTrunc: {
date: {
$dateFromString: {
dateString: "$$w.wlDateTime",
format: "%d/%m/%Y %H:%M"
}
},
unit: "day"
}
},
{
$dateTrunc: {
date: "$$NOW",
unit: "day"
}
}
]
}
}
},
[]
]
},
{
$ne: [
{
$filter: {
input: "$rainfallData",
as: "r",
cond: {
$eq: [
{
$dateTrunc: {
date: {
$dateFromString: {
dateString: "$$r.rfDateTime",
format: "%d/%m/%Y %H:%M"
}
},
unit: "day"
}
},
{
$dateTrunc: {
date: "$$NOW",
unit: "day"
}
}
]
}
}
},
[]
]
}
]
}
}
},
{
$set: {
waterLevel: {
$map: {
input: "$waterLevel",
as: "w",
in: {
$mergeObjects: [
"$$w",
{
wlDateTime: {
$dateFromString: {
dateString: "$$w.wlDateTime",
format: "%d/%m/%Y %H:%M"
}
}
}
]
}
}
},
rainfallData: {
$map: {
input: "$rainfallData",
as: "r",
in: {
$mergeObjects: [
"$$r",
{
rfDateTime: {
$dateFromString: {
dateString: "$$r.rfDateTime",
format: "%d/%m/%Y %H:%M"
}
}
}
]
}
}
}
}
},
{
$set: {
waterLevel: {
$filter: {
input: "$waterLevel",
as: "w",
cond: {
$and: [
{
$in: [
"$$w.wlSeverity",
[
"Alert",
"Warning",
"Danger"
]
]
},
{
$eq: [
"$$w.wlDateTime",
{
$max: "$waterLevel.wlDateTime"
}
]
},
{
$eq: [
{
$dateTrunc: {
date: "$$w.wlDateTime",
unit: "day"
}
},
{
$dateTrunc: {
date: "$$NOW",
unit: "day"
}
}
]
}
]
}
}
},
rainfallData: {
$filter: {
input: "$rainfallData",
as: "r",
cond: {
$and: [
{
$eq: [
"$$r.rfDateTime",
{
$max: "$rainfallData.rfDateTime"
}
]
},
{
$eq: [
{
$dateTrunc: {
date: "$$r.rfDateTime",
unit: "day"
}
},
{
$dateTrunc: {
date: "$$NOW",
unit: "day"
}
}
]
}
]
}
}
}
}
}
])
but I just want the latest
如果您只对最新的文档感兴趣,您可以省略 sort
并使用自然的负光标:
Meteor.publish('Alerts', function(){
return AlertLatest.find({
'waterLevelData.wlSeverity':'Danger',
}, {
fields : {
'stationName' : 1,
'state' : 1,
'lat' : 1,
'long' : 1,
'waterLevelData.wlDateTime' : 1,
'waterLevelData.wlSeverity' : 1,
'waterLevelData.wlLevel' : 1,
'rainfallData.rfSeverity' : 1,
}},{ hint: { $natural: -1}});
})
它将从末尾开始计算文档数,而不是从头开始。
https://docs.meteor.com/api/collections.html#Mongo-Collection-find