我的需求看起来有点复杂:
我有一个集合,其中文档有一个名为startTimeArray
的数组,存储了事件的timeStamps。如:
"startTimeArr" : [
NumberLong("1425340800000"),
NumberLong("1425513600000"),
NumberLong("1426032000000"),
NumberLong("1425427200000")
]
我希望查找结果按大于当前时间的最小时间戳排序(即时间尚未过去,最小值开启)。例如,如果当前时间戳以毫秒为单位1425513500000
,参与此文档排序操作的时间戳为1425513600000
,这是startTimeArr
数组的最小标记,大于1425513500000
。
所以startTimeArr
参与排序操作的元素应该是:
我猜我可以通过以下聚合来完成此操作:
db.event.aggregate(
{
$match:{
startTimeArr:{
$gt: 1425513500000 // presume the current time is 1425513500000
}
}
},
{
$group:{
_id:"$_id", minTimeStamp:{?????} // and I don't know what to write here.
}
},
{
$sort:{minTimeStamp:1}
}
)
但是我无法弄清楚如何编写minTimeStamp
计算。
你能告诉我怎么做吗?或者,如果还有其他方法可以做到这一点,也将不胜感激。
由于问题有点过于复杂,我只会根据需要提供一些样本和输出。
如果我们有3个这样的文件:
{
"_id" : ObjectId("537d98c20cf2264603faf0eb"),
"name": "Let's go to LA",
"fee": 500,
"duration":2,
"startTimeArr":[
NumberLong("1425310000000"),
NumberLong("1425320000000"),
NumberLong("1425330000000"),
NumberLong("1425380000000")
]
}
{
"_id" : ObjectId("537caa7e0cf2264603faf0e9"),
"name": "Let's go to NewYork",
"fee": 800,
"duration":3,
"startTimeArr":[
NumberLong("1425320000000"),
NumberLong("1425330000000"),
NumberLong("1425340000000"),
NumberLong("1425350000000")
]
}
{
"_id" : ObjectId("537c5ec50cf2264603faf0e7"),
"name": "Let's go to Washington",
"fee": 700,
"duration":2,
"startTimeArr":[
NumberLong("1425350000000"),
NumberLong("1425360000000"),
NumberLong("1425370000000"),
NumberLong("1425390000000")
]
}
如果当前时间为1425300000000
,则参与排序的时间为:
LA 1425310000000
NewYork 1425320000000
Washington 1425350000000
因此,这三个文档的查找结果将按顺序LA, NewYork, Washington
但是当时间继续前进并且当前时间为142534000000
时,参与排序程序的时间将是:
LA 1425380000000
NewYork 1425350000000
Washington 1425350000000
因此,预期查找结果将按顺序NewYork, Washington, LA
排序。
答案 0 :(得分:1)
看起来您缺少的聚合运算符是$min
,可以在聚合中的$group
步骤中使用。在分组之前,您还需要$unwind
开始时间数组:
var timeNow = 1425300000000; // set the time cut off for testing
db.event.aggregate(
// Find documents with matching events
// Note: could take advantage of an index to limit results
{ $match: {
startTimeArr:{
$gt: timeNow
}
}},
// Convert start time array to stream of docs
{ $unwind: "$startTimeArr" },
// Limit to matching array elements
{ $match: {
startTimeArr:{
$gt: timeNow
}
}},
// Find the minimum timestamp in each matching document
{ $group:{
_id:"$_id",
name: { $first: "$name" },
minTimeStamp:{ $min: "$startTimeArr" }
}},
// Sort in order of minimum timestamp (ascending)
{ $sort: { "minTimeStamp" : 1 }}
)
示例输出:
{
"result": [
{
"_id": ObjectId("537d98c20cf2264603faf0eb"),
"name": "Let's go to LA",
"minTimeStamp": NumberLong("1425310000000")
},
{
"_id": ObjectId("537caa7e0cf2264603faf0e9"),
"name": "Let's go to NewYork",
"minTimeStamp": NumberLong("1425320000000")
},
{
"_id": ObjectId("537c5ec50cf2264603faf0e7"),
"name": "Let's go to Washington",
"minTimeStamp": NumberLong("1425350000000")
}
],
"ok": 1
}
答案 1 :(得分:0)
您需要在$ group管道阶段使用$min
聚合运算符,以便从startTimeArr
数组值中获取最小时间戳。但是,您需要首先从过滤的输入文档中解构startTimeArr
数组字段(使用$match
运算符),以使用$unwind
运算符为每个元素输出文档。在$group
管道阶段,$first
运算符使您可以恢复分组中的其他字段,以便稍后在项目中进行投影。因此,您的聚合管道将如下所示:
var date = new Date(),
timestamp = +date;
db.event.aggregate([
{
"$match": {
"startTimeArr": {
"$gt": 1425300000000 // or use the timestamp variable to get the actual current timestamp
}
}
},
{
"$unwind": "$startTimeArr"
},
{
"$group": {
"_id":"$_id",
"minTimeStamp": {
"$min": "$startTimeArr"
},
"name": { "$first": "$name" },
"fee": { "$first": "$fee" },
"duration": { "$first": "$duration" },
}
},
{
"$project": {
"_id": 0,
"name": 1,
"minTimeStamp" : 1,
"fee": 1,
"duration": 1
}
},
{
"$sort": { "minTimeStamp": 1 }
}
]);
<强>输出强>:
/* 0 */
{
"result" : [
{
"minTimeStamp" : NumberLong(1425310000000),
"name" : "Let's go to LA",
"fee" : 500,
"duration" : 2
},
{
"minTimeStamp" : NumberLong(1425320000000),
"name" : "Let's go to NewYork",
"fee" : 800,
"duration" : 3
},
{
"minTimeStamp" : NumberLong(1425427200000),
"name" : "Let's go to Washington",
"fee" : 700,
"duration" : 2
}
],
"ok" : 1
}