可能? $添加数组的值与对象总值进行比较
mongodb native for node.js(驱动程序版本是2.2.4和MongoDB shell版本:3.2.9)
我的collections有这样的对象:
{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)
我不确定如何将所有xv
加起来,只返回xv
总和大于或等于对象t
的对象
aggregate({"t":{"$gte":{"$add":["xv"]}}})
返回每一个对象,我没有任何其他的想法阅读文档的语法的顺序。
mongodb甚至可以在查询中做到这一点?
有了MongoDB 3.2,你可以在这里采取几种方法。 你可以用$where
操作符来查询:
db.collection.find({ "$where": function() { return (this.x.reduce(function (a, b) { return a + bv; }, 0) > this.t); } })
示例输出
/* 1 */ { "_id" : ObjectId("587107b3cbe62793a0f14e74"), "x" : [ { "v" : 0.002 }, { "v" : 0.002 } ], "t" : 0.00202 }
但是请注意,由于使用$where
操作符调用JavaScript引擎的查询操作来评估每个文档上的JavaScript代码并检查每个文档的条件,所以这肯定不是一个非常有效的解决scheme。
这是非常缓慢的,因为MongoDB在$where
expression式和非$where
查询语句可以使用索引之前评估非$where
查询操作。
如果可以的话,build议与索引查询结合起来,以便查询速度更快。 但是,强烈build议您使用JavaScriptexpression式和$where
操作符作为最后的手段,当您不能以任何其他方式构造数据或处理一小部分数据时。
一个更好的方法是使用聚合框架,你可以使用$unwind
操作符来压扁数组x
,在$group
stream水线中计算xv
的总和,然后使用$redact
stream水线阶段过滤文档。 这允许您使用$cond
操作符处理逻辑条件,并使用特殊操作$$KEEP
将逻辑条件为true的文档“保留”,或者使用$$PRUNE
删除条件为false的文档。
这个操作类似于使用$project
pipe道来select集合中的字段,并创build一个新的字段来保存来自逻辑条件查询的结果,然后进行后续的$match
,除了$redact
使用更多的单一pipe道阶段高效。
db.collection.aggregate([ { "$unwind": "$x" }, { "$group": { "_id": "$_id", "x": { "$push": "$x" }, "t": { "$first": "$t" }, "y": { "$sum": "$xv" } } }, { "$redact": { "$cond": [ { "$gt": [ "$y", "$t" ] }, "$$KEEP", "$$PRUNE" ] } } ])
示例输出
/* 1 */ { "_id" : ObjectId("587107b3cbe62793a0f14e74"), "x" : [ { "v" : 0.002 }, { "v" : 0.002 } ], "t" : 0.00202, "y" : 0.004 }
然而,尽pipe这个解决scheme比使用$where
的以前的解决scheme更好,但要记住使用$unwind
操作符也可以限制大数据集的性能,因为它产生文档的笛卡尔乘积,即每个文档的副本每个数组入口使用更多的内存(聚集pipe线上可能的内存上限占总内存的10%),因此在展平过程中需要时间来处理文档。
而且,这个解决scheme需要知道文档字段,因为这是在$group
pipe道中需要的,通过使用诸如$first
或$last
的累加器来保留分组过程中的字段。 如果您的查询需要dynamic,这可能是一个巨大的限制。
为了最有效的解决scheme,我build议将你的MongoDB服务器$redact
3.4,并且使用$redact
pipe道阶段和新的$reduce
数组操作符以无缝的方式过滤文档。
$reduce
用于通过对数组中的每个元素应用一个expression式并将它们合并为一个单独的值来计算数组中xv
字段的总和。
然后,您可以使用$redact
pipe道评估的expression式来获得所需的结果:
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 }