我有以下收藏:
{
"_id" : "Stats1",
"minutes" : {
"0" : [
{
"0" : {
"f" : 1,
"t" : 0,
"v" : "0"
}
}
],
"22" : [
{
"2" : "1"
}
],
"29" : [
{
"32" : "2"
}
],
"38" : [
{
"40" : "3"
}
]
}
}
当我尝试时:
db.stats.aggregate()
.project({"_id":"1", "minArray": {"$objectToArray": "$minutes"}})
我收到错误消息:
“ $ objectToArray需要输入文档,找到:数组”
当我尝试时:
db.stats.aggregate()
.project({"_id":"1", "minArray": {"$arrayToObject": "$minutes"}})
我收到错误消息:
“ $ arrayToObject需要一个数组输入,找到了:object”
我想获取精确到或小于30分钟的最接近值:
{ "minute" : "29", "value" : [{ "32" : "2"}] }
答案 0 :(得分:1)
所以出现错误是因为没有$match
,您的管道正在尝试访问其他没有预期结构的文档。但这确实是需要分开的东西。
要从最终目的中真正回答您的问题,您需要一个这样的管道:
var _id = "Stats1";
var target = 30;
db.stats.aggregate([
{ "$match": { "_id" : _id } },
{ "$replaceRoot": {
"newRoot": {
"$let": {
"vars": {
"working": {
"$map": {
"input": { "$objectToArray": "$minutes" },
"in": {
"k": { "$toInt": "$$this.k" },
"v": "$$this.v",
"diff": { "$abs": { "$subtract": [ target, { "$toInt": "$$this.k" }] } }
}
}
}
},
"in": {
"$arrayToObject": {
"$map": {
"input": {
"$filter": {
"input": {
"$objectToArray": {
"$arrayElemAt": [
"$$working",
{ "$indexOfArray": [ "$$working.diff", { "$min": "$$working.diff" } ] }
]
}
},
"cond": { "$ne": [ "$$this.k", "diff" ] }
}
},
"in": {
"k": { "$cond": [{ "$eq": [ "$$this.k", "k"] }, "minute", "value" ] },
"v": { "$cond": [{ "$eq": [ "$$this.k", "k"] }, { "$toString": "$$this.v" }, "$$this.v" ] }
}
}
}
}
}
}
}}
])
当然会返回所需的输出:
{ "minute" : "29", "value" : [ { "32" : "2" } ] }
依次执行您最初尝试的$objectToArray
,但是随后您需要将该 key 或"k"
值实际转换为数字以进行比较。您还需要根据要搜索的值(在这种情况下为30
)计算出它们的差异。这将为您提供数组形式的数据的“工作”副本,这对于接下来的输入阶段很重要。
下一节基本上是从缩进级别向内阅读的,以最好地理解顺序。
首先,您基本上想从该工作数组中提取元素,其中差异(使用$abs
,使正负相同)是$min
的最小值。这样就给出了$indexOfArray
中第一个匹配项的位置,并将其与$arrayElemAt
一起使用来从工作数组中返回单个选定的元素。
我们不需要该对象中的所有字段,因此$objectToArray
会将单个对象转换为"k"
和"v"
配对的对象,第一步是转到{{3} },其中 key 是 difference 字段,并将其从该列表中删除。
接下来,您要重命名字段并更改某些数据格式,因此$filter
迭代其余数组(仅两个条目),分配可读名称并设置"minute"
的字符串格式。
最后,它可以作为最终输出返回到$map
对象。由于我们想多次引用该"working"
数组,因此我们在$arrayToObject
中进行了声明,这使我们能够做到这一点。并且由于所有这些都是一个表达式,可以将您想要的内容输出为文档,因此您可以使用$let
将其包装为“表达式”,因为它基本上是单个预期参数。