我目前正在开发一个具有以下结构的数据库:
{"_id" : ObjectId("1abc2"),
"startdatetime" : ISODate("2016-09-11T18:00:37Z"),
"diveValues" : [
{
"temp" : 15.269,
"depth" : 0.0,
},
{
"temp" : 14.779257384,
"depth" : 1.0,
},
{
"temp" : 14.3940253165,
"depth" : 2.0,
},
{
"temp" : 13.9225795455,
"depth" : 3.0,
},
{
"temp" : 13.8214431818,
"depth" : 4.0,
},
{
"temp" : 13.6899553571,
"depth" : 5.0,
}
]}
数据库包含有关水中深度n米和给定深度温度的信息。它存储在“diveValues”数组中。我已经成功地平均了日期之间的所有深度,包括月平均值和每日平均值。我遇到的一个严重问题是,在过去的6个月中,每个月的平均深度为1到4米之间。
以下是所有深度的1月至6月每个月的平均温度示例:
db.collection.aggregate(
[
{$unwind:"$diveValues"},
{$match:
{'startdatetime':
{$gt:new ISODate("2016-01-10T06:00:29Z"),
$lt:new ISODate("2016-06-10T06:00:29Z")}
}
},
{$group:
{_id:
{ year: { $year: "$startdatetime" },
month: { $month: "$startdatetime" }},
avgTemp: { $avg: "$diveValues.temp" }}
},
{$sort:{_id:1}}
]
)
导致:
{ "_id" : { "year" : 2016, "month" : 1 }, "avgTemp" : 7.575706502958313 }
{ "_id" : { "year" : 2016, "month" : 3 }, "avgTemp" : 6.85037457740135 }
{ "_id" : { "year" : 2016, "month" : 4 }, "avgTemp" : 7.215702831902588 }
{ "_id" : { "year" : 2016, "month" : 5 }, "avgTemp" : 9.153453683614638 }
{ "_id" : { "year" : 2016, "month" : 6 }, "avgTemp" : 11.497953009390237 }
现在,我似乎无法弄清楚如何在同一时期内将平均温度控制在1到4米之间。
我一直在尝试按想要的深度对值进行分组,但是还没有对它进行管理 - 通常不会以错误的语法结束。此外,如果我没有错,只要潜水值为1米和4米,$ match管道就会返回所有深度,这样就无法使用了。
使用find()工具我使用$ slice来返回我想从数组中获取的值 - 但是与aggregate()函数一起没有成功。
有没有办法解决这个问题?非常感谢,非常感谢!
答案 0 :(得分:0)
首先,日期 $ match 运算符should be used at the beginning of the pipeline so that indexes can be used。
现在,对于这个问题,您只需像过滤日期一样过滤深度间隔:
db.col.aggregate([
{"$match": {
'startdatetime': {
"$gt": new ISODate("2016-01-10T06:00:29Z"),
"$lt": new ISODate("2016-11-10T06:00:29Z")
}
}},
{"$unwind": "$diveValues"},
{"$match": {
"diveValues.depth": {
"$gte": 1.0,
"$lt": 4.0
}
}},
{"$group": {
"_id": {
"year": {"$year": "$startdatetime" },
"month": {"$month": "$startdatetime" }
},
"avgTemp": { "$avg": "$diveValues.temp" }}
}
])
这将仅为您提供所选深度间隔的平均值。
答案 1 :(得分:0)
您需要将 $match
管道置于 $unwind
之前 optimize 聚合操作在整个集合上执行 $unwind
操作可能会导致一些性能问题,因为它会为每个数组条目生成每个文档的副本并使用更多内存(聚合时可能的内存上限)因此,产生扁平阵列的“时间”以及处理它的“时间”需要10%总内存的管道。因此,最好将进入管道的文档数量限制为扁平化。
db.collection.aggregate([
{
"$match": {
"startdatetime": {
"$gt": new ISODate("2016-01-10T06:00:29Z"),
"$lt": new ISODate("2016-06-10T06:00:29Z")
},
"diveValues.depth": { "$gte": 1, "$lte": 4 }
}
},
{ "$unwind": "$diveValues" },
{ "$match": { "diveValues.depth": { "$gte": 1, "$lte": 4 } } },
{
"$group": {
"_id": {
"year": { "$year": "$startdatetime" },
"month": { "$month": "$startdatetime" }
},
"avgTemp": { "$avg": "$diveValues.temp" }
}
}
])
如果您希望结果包含所有深度和1-4深度范围的平均温度,那么您需要运行此管道,该管道将使用 $cond
tenary运算符为 $avg
运算符提供基于深度范围的组内累积温度:
db.collection.aggregate([
{
"$match": {
"startdatetime": {
"$gt": new ISODate("2016-01-10T06:00:29Z"),
"$lt": new ISODate("2016-06-10T06:00:29Z")
}
}
},
{ "$unwind": "$diveValues" },
{
"$group": {
"_id": {
"year": { "$year": "$startdatetime" },
"month": { "$month": "$startdatetime" }
},
"avgTemp": { "$avg": "$diveValues.temp" },
"avgTempDepth1-4": {
"$avg": {
"$cond": [
{
"$and": [
{ "$gte": [ "$diveValues.depth", 1 ] },
{ "$lte": [ "$diveValues.depth", 4 ] }
]
},
"$diveValues.temp",
null
]
}
}
}
}
])