可能? $ add数组的值以与对象总值进行比较

时间:2017-01-07 14:54:24

标签: node.js mongodb mongodb-query aggregation-framework

  

node.js的mongodb native(驱动程序版本为2.2.4,MongoDB shell版本: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甚至可以在查询中执行此操作吗?

1 个答案:

答案 0 :(得分:1)

使用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 表达式和非 {{3}之前评估非 $where 查询操作,因此速度非常慢查询语句可以使用索引。

建议您与索引查询结合使用,以便查询可能更快。但是,强烈建议您使用JavaScript表达式和 $where 运算符作为最后的手段,当您无法以任何其他方式构建数据时,或者当您正在处理一小部分数据。

更好的方法是使用聚合框架,您可以使用 $where 运算符展平数组x,计算x.v的总和在 $unwind 管道中,然后使用 $group 管道阶段过滤文档。这允许您使用 $redact 运算符来处理逻辑条件,并使用特殊操作 $cond 来保持&#34;保持&#34;逻辑条件为真的文档或 $$KEEP 到&#34;删除&#34;条件为假的文件。

此操作类似于具有 $$PRUNE 管道,该管道选择集合中的字段并创建一个新字段,其中包含逻辑条件查询的结果,然后是后续的 $project ,但 $match 使用效率更高的单个管道阶段。

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
}

但是,尽管此解决方案优于之前使用 $redact 的解决方案,但请记住使用 $where 运算符也可以限制较大数据集的性能,因为它产生文档的笛卡尔积,即每个数组条目的每个文档的副本,它使用更多的内存(聚合管道上可能的内存上限为10%总内存)因此需要时间来生成以及在展平过程中处理文件。

此外,此解决方案需要了解文档字段,因为在 $unwind 管道中需要这样,您可以使用 {之类的累加器保留分组过程中的字段{3}} $group 。如果您的查询需要是动态的,那么这可能是一个巨大的限制。

对于最有效的解决方案,我建议将MongoDB服务器提升到3.4,并使用 $first 管道阶段和新 $last的组合数组运算符以无缝方式过滤文档。

$redact 用于通过将表达式应用于数组中的每个元素并将它们组合为单个值来计算数组中x.v字段的总和。

然后,您可以使用带有 $reduce 管道评估的表达式来获得所需的结果:

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
}