mongodb native for node.js (driver version is 2.2.4 and MongoDB shell version: 3.2.9)
我的收藏有这样的对象:
{x:[{v:0.002},{v:0.00002}],t:0.00202} //<this one has the full total in its values
{x:[{v:0.002},{v:0.002}],t:0.00202}
{x:[{v:0.002},{v:0.002}],t:0.3}
(此处显示没有对象 ID)
我不确定如何将所有 x.v
相加,以仅返回 x.v
总和大于或等于对象 t
的对象>
aggregate({"t":{"$gte":{"$add":["x.v"]}}})
返回每个对象,通过阅读文档,我对语法顺序没有任何其他想法。
mongodb 甚至可以在查询中执行此操作吗?
最佳答案
对于 MongoDB 3.2,您可以在此处采用几种方法。您可以通过$where
查询 运算符:
db.collection.find({
"$where": function() {
return (this.x.reduce(function (a, b) {
return a + b.v;
}, 0) > this.t);
}
})
示例输出
/* 1 */
{
"_id" : ObjectId("587107b3cbe62793a0f14e74"),
"x" : [
{
"v" : 0.002
},
{
"v" : 0.002
}
],
"t" : 0.00202
}
但请注意,这注定是一个不是非常有效的解决方案,因为使用 $where
进行查询操作 运算符调用 JavaScript 引擎来评估每个文档上的 JavaScript 代码并检查每个文档的条件。
这非常慢,因为 MongoDB 评估非 $where
$where
之前的查询操作 表达式和非 $where
查询语句可以使用索引。
如果可以的话,建议与索引查询结合起来,这样查询可能会更快。但是,强烈建议使用 JavaScript 表达式和 $where
当您无法以任何其他方式构造数据或处理一小部分数据时, 运算符作为最后的手段。
更好的方法是使用聚合框架,您可以在其中使用 $unwind
运算符压平数组 x
,计算 $group
内 x.v
的总和 管道,然后使用 $redact
过滤文档 管道阶段。这允许您使用 $cond
处理逻辑条件。 运算符并使用特殊操作 $$KEEP
“保留”逻辑条件为 true 的文档或 $$PRUNE
“删除”条件为假的文档。
此操作类似于 $project
管道,选择集合中的字段并创建一个新字段来保存逻辑条件查询的结果,然后是后续的 $match
,除了 $redact
使用单个管道阶段,效率更高。
db.collection.aggregate([
{ "$unwind": "$x" },
{
"$group": {
"_id": "$_id",
"x": { "$push": "$x" },
"t": { "$first": "$t" },
"y": { "$sum": "$x.v" }
}
},
{
"$redact": {
"$cond": [
{ "$gt": [ "$y", "$t" ] },
"$$KEEP",
"$$PRUNE"
]
}
}
])
示例输出
/* 1 */
{
"_id" : ObjectId("587107b3cbe62793a0f14e74"),
"x" : [
{
"v" : 0.002
},
{
"v" : 0.002
}
],
"t" : 0.00202,
"y" : 0.004
}
但是,尽管此解决方案比之前使用 $where
的解决方案要好。 ,请记住使用 $unwind
运算符还可能限制较大数据集的性能,因为它会生成文档的笛卡尔积,即每个数组条目的每个文档的副本,这会使用更多内存(聚合管道上的内存上限可能为 10% 总内存),因此在展平过程中需要时间来生成以及处理文档。
此外,此解决方案需要了解文档字段,因为 $group
中需要此知识。 管道,您可以使用 $first
等累加器在分组过程中保留字段。 或 $last
。如果您的查询需要动态,这可能是一个巨大的限制。
为了获得最有效的解决方案,我建议将 MongoDB 服务器升级到 3.4,并使用 $redact
的组合。 管道阶段和新的 $reduce
数组运算符以无缝方式过滤文档。
$reduce
用于通过将表达式应用于数组中的每个元素并将它们组合成单个值来计算数组中 x.v
字段的总和。
然后您可以将此表达式与 $redact
一起使用管道的评估以获得期望的结果:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$gt": [
{
"$reduce": {
"input": "$x",
"initialValue": 0,
"in": { "$add": ["$$value", "$$this.v"] }
}
},
"$t"
]
},
"$$KEEP",
"$$PRUNE"
]
}
}
])
示例输出
/* 1 */
{
"_id" : ObjectId("587107b3cbe62793a0f14e74"),
"x" : [
{
"v" : 0.002
},
{
"v" : 0.002
}
],
"t" : 0.00202
}
关于node.js - 可能的? $add 数组的值与对象总值进行比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41522749/