Mongo 使用日期时间戳的 $lookup 聚合
Mongo $lookup aggregation using date timestamps
我有两个 collections:汽车驾驶历史 和 汽车地理位置。为了分析驾驶模式,我必须汇总驾驶历史并将它们 link 到汽车地理位置。
我使用 $match
和 $project
聚合阶段来获取具有以下结构的驱动历史文档:
travelPurpose:<String>
carID:<ObjectId>
checkOutTime:<Date>
checkInTime:<Date>
下一步是使用$lookup
阶段获取两个时间戳之间的汽车位置(checkOutTime和checkInTime) .每个汽车地理定位文档都有 carID 和 geoLocationTimestamp 字段。如果我使用静态日期,例如:
{
from: 'carGeoLocations',
localField: 'carID',
foreignField: 'carID',
pipeline: [
{$match: {
geoLocationTimestamp: {
$gte: ISODate('2022-01-01T00:00:00.000+0000'),
$lte: ISODate('2023-01-01T00:00:00.000+0000')
}
}}
],
as: 'coordinates'
}
我确实得到了 1. 1. 2022 和 1. 1. 2023 之间的地理位置。Mongo 可以访问带有此行为示例的游乐场 here。
但是,如果我尝试使用基于 checkOutTime 和 checkInTime 值的动态日期,则不会检索到任何文档。 Mongo 带有此示例的游乐场可用 here。我尝试了以下方法:
{
from: 'carGeoLocations',
localField: 'carID',
foreignField: 'carID',
pipeline: [
{$match: {
geoLocationTimestamp: {
$gte: "$checkOutTime",
$lte: "$checkInTime"
}
}}
],
as: 'coordinates'
}
和
{
from: 'carGeoLocations',
localField: 'carID',
foreignField: 'carID',
let: {t1: '$checkOutTime', t2: '$checkInTime'}
pipeline: [
{$match: {
geoLocationTimestamp: {
$gte: '$$t1',
$lte: '$$t2'
}
}}
],
as: 'coordinates'
}
结果相同。有人能发现我的方法有什么问题吗?
首先查找然后使用 geoLocationTimestamp 匹配
试试下面的代码
{
$lookup:{
from: 'carGeoLocations',
localField: 'carID',
foreignField: 'carID',
as: 'coordinates'
}
},
{
$match:{
geoLocationTimestamp: {
$gte:'$coordinates.checkOutTime',
$lte:'$coordinates.checkInTime'
}
}
}
更新
经过进一步的实验,当你想在 $lookup
聚合阶段使用用 let
声明的变量时,你需要使用 $expr
。
我的查找阶段现在看起来像这样:
{
"$lookup": {
"from": "carGeoLocations",
"localField": "carID",
"foreignField": "carID",
"let": {
t1: "$checkOutTime",
t2: "$checkInTime"
},
"pipeline": [
{
$match: {
$and: [
{
$expr: {
$gte: [
"$geoLocationTimestamp",
"$$t1"
],
}
},
{
$expr: {
$lte: [
"$geoLocationTimestamp",
"$$t2"
],
}
},
]
}
}
],
"as": "coordinates"
}
}
我有两个 collections:汽车驾驶历史 和 汽车地理位置。为了分析驾驶模式,我必须汇总驾驶历史并将它们 link 到汽车地理位置。
我使用 $match
和 $project
聚合阶段来获取具有以下结构的驱动历史文档:
travelPurpose:<String>
carID:<ObjectId>
checkOutTime:<Date>
checkInTime:<Date>
下一步是使用$lookup
阶段获取两个时间戳之间的汽车位置(checkOutTime和checkInTime) .每个汽车地理定位文档都有 carID 和 geoLocationTimestamp 字段。如果我使用静态日期,例如:
{
from: 'carGeoLocations',
localField: 'carID',
foreignField: 'carID',
pipeline: [
{$match: {
geoLocationTimestamp: {
$gte: ISODate('2022-01-01T00:00:00.000+0000'),
$lte: ISODate('2023-01-01T00:00:00.000+0000')
}
}}
],
as: 'coordinates'
}
我确实得到了 1. 1. 2022 和 1. 1. 2023 之间的地理位置。Mongo 可以访问带有此行为示例的游乐场 here。 但是,如果我尝试使用基于 checkOutTime 和 checkInTime 值的动态日期,则不会检索到任何文档。 Mongo 带有此示例的游乐场可用 here。我尝试了以下方法:
{
from: 'carGeoLocations',
localField: 'carID',
foreignField: 'carID',
pipeline: [
{$match: {
geoLocationTimestamp: {
$gte: "$checkOutTime",
$lte: "$checkInTime"
}
}}
],
as: 'coordinates'
}
和
{
from: 'carGeoLocations',
localField: 'carID',
foreignField: 'carID',
let: {t1: '$checkOutTime', t2: '$checkInTime'}
pipeline: [
{$match: {
geoLocationTimestamp: {
$gte: '$$t1',
$lte: '$$t2'
}
}}
],
as: 'coordinates'
}
结果相同。有人能发现我的方法有什么问题吗?
首先查找然后使用 geoLocationTimestamp 匹配
试试下面的代码
{
$lookup:{
from: 'carGeoLocations',
localField: 'carID',
foreignField: 'carID',
as: 'coordinates'
}
},
{
$match:{
geoLocationTimestamp: {
$gte:'$coordinates.checkOutTime',
$lte:'$coordinates.checkInTime'
}
}
}
更新
经过进一步的实验,当你想在 $lookup
聚合阶段使用用 let
声明的变量时,你需要使用 $expr
。
我的查找阶段现在看起来像这样:
{
"$lookup": {
"from": "carGeoLocations",
"localField": "carID",
"foreignField": "carID",
"let": {
t1: "$checkOutTime",
t2: "$checkInTime"
},
"pipeline": [
{
$match: {
$and: [
{
$expr: {
$gte: [
"$geoLocationTimestamp",
"$$t1"
],
}
},
{
$expr: {
$lte: [
"$geoLocationTimestamp",
"$$t2"
],
}
},
]
}
}
],
"as": "coordinates"
}
}