MongoDB:如何使最低值更接近给定的数字,并在另一个字段中递减1

MongoDB:如何使最低值更接近给定的数字,并在另一个字段中递减1,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,给定包含3个嵌套文档的以下文档 { "_id": ObjectId("56116d8e4a0000c9006b57ac"), "name": "Stock 1", "items" [ { "price": 1.50, "description": "Item 1", "count": 10 } { "price": 1.70, "description": "Item 2", "count": 13 } { "price": 1.10, "description": "I

给定包含3个嵌套文档的以下文档

{ "_id": ObjectId("56116d8e4a0000c9006b57ac"), "name": "Stock 1", "items" [
    { "price": 1.50, "description": "Item 1", "count": 10 }
    { "price": 1.70, "description": "Item 2", "count": 13 }
    { "price": 1.10, "description": "Item 3", "count": 20 }
  ]
}
。。。我需要选择最低价接近给定金额的子文档(以下我假设为1.05):

这与预期一样有效,结果如下:

"result" : [
    {
        "price" : 1.10,
        "description" : "Item 3",
        "count" : 20
    }
],
"ok" : 1
除了以接近给定金额的最低价格返回物品外,我还需要将
count
减少1。例如,下面是我正在寻找的结果:

"result" : [
    {
        "price" : 1.10,
        "description" : "Item 3",
        "count" : 19
    }
],
"ok" : 1

这取决于您是真正想要“更新”结果,还是简单地用递减值“返回”结果。在前一种情况下,您当然需要返回文档并“递减”返回结果的值

还要注意的是,你“认为”这里是有效的,实际上不是。对元素进行“后排序”甚至“后退绕”的“过滤”实际上对累加器在性能方面的工作方式没有任何影响

更好的方法是在可能的情况下基本上“预过滤”数组中的值。这将减少聚合管道中的文档大小,以及
$unwind
要处理的数组元素数:

db.stocks.aggregate([
{“$match”:{
“项目.价格:{“$gte”:1.05}
}},
{“$project”:{
“项目”:{
“$setDifference”:[
{“$map”:{
“输入”:“$items”,
“作为”:“项目”,
“在”:{
“$cond”:[
{“$gte”:[“$$item.price”,1.05]}
],
“$$item”,
假的
}
}},
[错误]
]
}
}},
{“$unwind”:“$items”},
{“$sort”:{“items.price”:1},
{“$组”:{
“_id”:0,
“项”:{“$first”:“$items”}
}},
{“$project”:{
“\u id”:“$item.\u id”,
“价格”:“$item.price”,
“说明”:“$item.description”
}}
]);
当然,这确实需要MongoDB 2.6版或更高版本的服务器才能有可用的操作符,根据您的输出,您可能会有一个更早的版本。如果是这种情况,那么至少松开
$match
,因为它不会做任何有价值的事情,并且会对性能产生决定性影响

如果
$match
很有用,则在您执行任何操作之前,都要在文档选择中进行匹配,因为您总是希望避免处理甚至不可能从数组或其他任何位置满足所需条件的文档。因此,您应该始终
$match
或首先使用类似的查询阶段

无论如何,如果您想要的只是一个“预期结果”,那么只需在输出中使用:

{“$project”:{
“\u id”:“$item.\u id”,
“价格”:“$item.price”,
“说明”:“$item.description”,
“计数”:{“$subtract”:[“$item.count”,1]}
}}
但是,如果您希望“更新”结果,那么您将迭代数组(即使只有一个结果,它仍然是一个数组)以更新匹配项并通过以下方式“减少”计数:

var result=db.stocks.aggregate([
{“$match”:{
“项目.价格:{“$gte”:1.05}
}},
{“$project”:{
“项目”:{
“$setDifference”:[
{“$map”:{
“输入”:“$items”,
“作为”:“项目”,
“在”:{
“$cond”:[
{“$gte”:[“$$item.price”,1.05]}
],
“$$item”,
假的
}
}},
[错误]
]
}
}},
{“$unwind”:“$items”},
{“$sort”:{“items.price”:1},
{“$组”:{
“_id”:0,
“项”:{“$first”:“$items”}
}},
{“$project”:{
“\u id”:“$item.\u id”,
“价格”:“$item.price”,
“说明”:“$item.description”
}}
]);
结果.forEach(函数(项){
更新({“item.\u id”:item.\u id},{“$inc”:{“item.$.count”:-1})
})
在MongoDB 2.4 shell上,同样的聚合查询也适用(但请进行更改),但是
result
包含另一个名为
result
的字段和数组,因此添加级别:

result.result.forEach(函数(项){
更新({“item.\u id”:item.\u id},{“$inc”:{“item.$.count”:-1})
})
因此,要么只显示
$project
,要么根据需要使用返回的结果对数据执行
.update()

"result" : [
    {
        "price" : 1.10,
        "description" : "Item 3",
        "count" : 19
    }
],
"ok" : 1