仅根据包含对象数组的字段中的值获取满足条件的文档

时间:2016-10-27 17:03:45

标签: mongodb

我有这样的文件:

{
    name: 'john',
    array: [{foo: 3, bar: 1},{foo:1, bar: 0},...]
}

我想找到foo和bar之间差异小于数组中某个条目中某个值的所有文档。我目前正在尝试使用$ where查询。我找回一个空列表。我的问题是我使用承诺的方式还是我使用$ where的方式?

代码:

    MongoClient.connect(config.database)
    .then(function(db) {
        return db.collection('MyCollection')
    })
    .then(function (collection) {
        return collection.find(
            { $where:
                function() {
                    for(var i = 0; i < this.array.length; i++) {
                        if((this.array[i].foo - this.array[i].bar) < 2) {
                            return true;
                        }
                    }
                    return false;
                }
            }
        )   
    })
    .then(function(cursor) {
        return cursor.toArray()
    })
    .then(function(arr) {
        console.log(arr)
    })
    .catch(function(err) {
        throw err;
    });

1 个答案:

答案 0 :(得分:0)

使用聚合框架和 $redact 管道运算符,您可以使用 $cond 运算符处理逻辑条件并使用特殊操作 $$KEEP 至&#34;保持&#34;逻辑条件为真的文档或 $$PRUNE 到&#34;删除&#34;条件错误的文件。

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

考虑以下展示上述概念的示例:

db.collection.aggregate([
    { 
        "$redact": {
            "$cond": [
                { 
                    "$anyElementTrue": {
                        "$map": {
                            "input": "$array",
                            "as": "el",
                            "in": { 
                                "$lt": [ 
                                    { "$subtract": ["$$el.foo", "$$el.bar"] }, 
                                    2
                                ] 
                            }
                        }
                    }
                },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

在上面的示例中, $anyElementTrue $map 组合的工作原理是,如果数组中的任何元素实际存在它的foo和bar值之间的差异小于2,那么这是一个真正的匹配,文档是&#34;保持&#34;。否则它将被修剪&#34;并丢弃。

因此,您重构的代码应该看起来像

MongoClient.connect(config.database)
    .then(function(db) {
        return db.collection('MyCollection')
    })
    .then(function (collection) {
        return collection.aggregate([
            { 
                "$redact": {
                    "$cond": [
                        { 
                            "$anyElementTrue": {
                                "$map": {
                                    "input": "$array",
                                    "as": "el",
                                    "in": { 
                                        "$lt": [ 
                                            { "$subtract": ["$$el.foo", "$$el.bar"] }, 
                                            2
                                        ] 
                                    }
                                }
                            }
                        },
                        "$$KEEP",
                        "$$PRUNE"
                    ]
                }
            }
        ]);  
    })
    .then(function(cursor) {
        return cursor.toArray()
    })
    .then(function(arr) {
        console.log(arr)
    })
    .catch(function(err) {
        throw err;
    });

这会显着改善性能,因为 $redact 运算符使用MongoDB的本机运算符,而查询操作使用 $where 运算符调用JavaScript引擎来评估每个文档的Javascript代码,并检查每个文档的条件。

由于MongoDB在 $where 表达式和非 {{3}之前评估非 $where 查询操作,因此速度非常慢查询语句可以使用索引。

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