Mongodb 匹配最接近搜索值的文档键
我有以下收藏:Mongodb 匹配最接近搜索值的文档键,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我有以下收藏: { "_id" : "Stats1", "minutes" : { "0" : [ { "0" : { "f" : 1, "t" : 0, "v" : "0" } } ], "22" :
{
"_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"}})
db.stats.aggregate()
.project({"_id":"1", "minArray": {"$arrayToObject": "$minutes"}})
我收到错误消息:
$objectToArray需要文档输入,找到:数组
当我尝试时:
db.stats.aggregate()
.project({"_id":"1", "minArray": {"$objectToArray": "$minutes"}})
db.stats.aggregate()
.project({"_id":"1", "minArray": {"$arrayToObject": "$minutes"}})
我收到错误消息:
$arrayToObject需要数组输入,找到:object
我希望获得精确或低于30分钟的最接近值:
{ "minute" : "29", "value" : [{ "32" : "2"}] }
因此,出现错误的原因是,如果没有文件,您的管道正在尝试访问其他没有预期结构的文档。不过,这确实是需要单独解决的问题 要从最终目标实际回答您的问题,您需要这样的管道:
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" } ] }
按顺序执行最初尝试的操作,但随后需要将该键或“k”
值实际转换为数值进行比较。您还需要计算与正在搜索的值之间的差值,在本例中为30
。这将以数组形式为您提供数据的“工作”副本,这对于下一个输入阶段非常重要
下一节基本上是从缩进层次向内阅读,以便更好地理解顺序
首先,您基本上希望从工作数组中提取元素,其中的差异(使用$abs
使正负值相同)是$min
的最小值。这将给出第一个匹配项的位置,并用于从工作数组返回单个选定元素
我们不需要该对象中的所有字段,因此将单个对象转换为“k”
和“v”
成对对象,第一步是确定该键是差异字段的位置,并将其从该列表中删除
接下来,您需要重命名字段并更改一些数据格式,以便迭代剩余的数组(只有两个条目),为“分钟”
分配可读名称并设置字符串格式
最后,这可以返回到一个对象作为最终输出。因为我们想多次引用该
“working”
数组,所以我们在其中声明允许我们这样做。因为所有这些都是一个表达式,它输出你想要的作为一个文档,你用它来包装“表达式”基本上是它的一个预期参数。根据消息说,$objectToArray
期望一个文档{}
作为操作符的输入,但是你提供了一个数组作为输入。你没有告诉我们任何事情。如前所述,由于这不是$objectToArray
的有效输入,因此可能会出现错误,您希望发生什么情况?如果您实际显示了预期的输出,这将非常有用。@NeilLunn为什么“分钟”不是有效的对象输入?这些错误基本上意味着集合中的其他文档不共享相同的数据类型。如果您对特定的\u id
进行$match
,则可以,但您需要查看收藏的其余部分,看看哪里是错误的。@NeilLunn thanx,您是对的