"data" : {
"visits" : {
"daily" : {
"2018-09-05" : 3586,
"2018-09-06" : 2969,
"2018-09-07" : 2624,
"2018-09-08" : 2803,
"2018-09-09" : 3439,
"2018-09-10" : 3655
}
}
},
我在MongoDB中具有这样的属性结构,我想做的是,例如,如果我有开始日期和结束日期,例如(2018-09-06-2018-09-07), 我想以这种格式获取结果
"data" : {
"visits" : {
"daily" : {
"2018-09-06" : 2969,
"2018-09-07" : 2624
}
}
},
有没有有效的方法可以动态地做到这一点?我可以通过将类似{{data.visits.daily.2018-09-06“:1,” data.visits.daily.2018-09-07“:1}的投影内容做到这一点,但它可以正常工作在我看来,这不是一个好的解决方案。
答案 0 :(得分:1)
使用 MongoDB 3.4.4 和更高版本:
db.collection.aggregate([
{ "$addFields": {
"data.visits.daily": {
"$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$data.visits.daily" },
"as": "el",
"cond": {
"$and": [
{ "$gte": ["$$el.k", "2018-09-06"] },
{ "$lte": ["$$el.k", "2018-09-07"] },
]
}
}
}
}
} }
])
上述管道将产生最终输出
{
"data" : {
"visits" : {
"daily" : {
"2018-09-06" : 2969,
"2018-09-07" : 2624
}
}
}
}
可以分解管道以显示每个操作员的结果。
$objectToArray
使您可以使用动态键来转换文档
放入一个数组,该数组包含原始文档中每个字段/值对的元素。返回数组中的每个元素都是一个包含两个字段k和v的文档。
在 $project
阶段仅由操作员运行管道
db.collection.aggregate([
{ "$project": {
"keys": { "$objectToArray": "$data.visits.daily" }
} }
])
收益
{
"_id" : ObjectId("5bab6d09b1951fef20a5dce4"),
"keys" : [
{
"k" : "2018-09-05",
"v" : 3586
},
{
"k" : "2018-09-06",
"v" : 2969
},
{
"k" : "2018-09-07",
"v" : 2624
},
{
"k" : "2018-09-08",
"v" : 2803
},
{
"k" : "2018-09-09",
"v" : 3439
},
{
"k" : "2018-09-10",
"v" : 3655
}
]
}
$filter
运算符充当 $objectToArray
运算符生成的数组的过滤机制,它通过选择数组的子集来工作根据指定条件返回
成为您的查询。
考虑以下管道,该管道返回与条件"2018-09-06" <= key <= "2018-09-07"
相匹配的键/值对的数组
db.collection.aggregate([
{ "$project": {
"keys": {
"$filter": {
"input": { "$objectToArray": "$data.visits.daily" },
"as": "el",
"cond": {
"$and": [
{ "$gte": ["$$el.k", "2018-09-06"] },
{ "$lte": ["$$el.k", "2018-09-07"] },
]
}
}
}
} }
])
产生
{
"_id" : ObjectId("5bab6d09b1951fef20a5dce4"),
"keys" : [
{
"k" : "2018-09-06",
"v" : 2969
},
{
"k" : "2018-09-07",
"v" : 2624
}
]
}
这将从
转换上面的过滤数组[
{
"k" : "2018-09-06",
"v" : 2969
},
{
"k" : "2018-09-07",
"v" : 2624
}
]
使用动态键到原始文档
{
"2018-09-06" : 2969,
"2018-09-07" : 2624
}
所以要运行管道
db.collection.aggregate([
{ "$project": {
"keys": {
"$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$data.visits.daily" },
"as": "el",
"cond": {
"$and": [
{ "$gte": ["$$el.k", "2018-09-06"] },
{ "$lte": ["$$el.k", "2018-09-07"] },
]
}
}
}
}
} }
])
会产生
{
"_id" : ObjectId("5bab6d09b1951fef20a5dce4"),
"keys" : {
"2018-09-06" : 2969,
"2018-09-07" : 2624
}
}
但是,您当然要保留原始架构,即当前字段,因此您需要使用 $addFields
而不是 $project
>用于说明的管道。
这等效于 $project
阶段,该阶段明确指定输入文档中的所有现有字段并添加新字段。在 $addFields
操作中指定现有字段名称将导致替换原始字段,并且您将需要使用点符号来使用动态键更新嵌入的data.visits.daily字段。
答案 1 :(得分:0)
您可以使用以下聚合来实现:
var startdate = "2018-09-06";
var enddate = "2018-09-09";
db['01'].aggregate(
[
{
$project: {
daily:{$objectToArray:"$data.visits.daily"}
}
},
{
$unwind: {
path : "$daily",
}
},
{
$addFields: {
"date": {$dateFromString:{dateString:"$daily.k",format:"%Y-%m-%d"}}
}
},
{
$match: {
$and:[{date:{$gte:new Date(startdate)}},{date:{$lte:new Date(enddate)}}]
}
},
{
$group: {
_id:"_id",
daily:{$push:"$daily"}
}
},
{
$project: {
"data.visits.daily":{$arrayToObject:"$daily"}
}
},
]
);