node.js - 可能的? $add 数组的值与对象总值进行比较

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

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,计算 $groupx.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/

相关文章:

javascript - 如何使用 Node.js 最有效地解析网页

node.js - 使用 Joi 验证嵌套对象

javascript - html 表中的 Node.js Cheerio 解析 html 表

node.js - Promise with q 框架和 Node.js 中的回调模式?

javascript - 使用 React.js 将富文本编辑器中的 HTML 标记保存到 MongoDB

javascript - 用于自动完成搜索的 MongoDB + Node.js + AJAX 解决方案

node.js - Mongoose 文档保存失败, "TypeError: Cannot read property ' 选项未定义”

mongodb - 查询由 C# 驱动程序插入的带有 _t 定义的记录

javascript - MongoDB shell : How to remove specific elements in all the collections inside a DB

MongoDB按数组内部元素分组