Mongodb算法表达数组内的元素

时间:2018-01-10 09:48:43

标签: mongodb aggregation-framework pymongo

{
    "_id" : ObjectId("5a4d0712368ff072a56a66e8"),
    "a" : {
        "nodes" : [
            {
                "b" : 1
            },
            {
                "c" : {
                    "nodes" : [
                        {
                            "d" : 2
                        },
                        {
                            "e" : 2
                        }
                    ]
                }
            }
        ]
    },
    "r" : 1
}
{
        "_id" : ObjectId("5a4d0712368ff072a56a66e9"),
        "a" : {
            "nodes" : [
                {
                    "b" : 4
                },
                {
                    "c" : {
                        "nodes" : [
                            {
                                "e" : 9
                            }
                        ]
                    }
                }
            ]
        },
        "r" : 2
    }

以上是示例文档,我想找到a.nodes.b * a.nodes.c.nodes.d * a.nodes.c.nodes.e 的总和 我尝试了很多管道,但无法概括聚合。任何帮助,将不胜感激。 节点数组可以在任何级别再次出现。如果我得到了解决方案,我将尝试概括聚合管道。

MongoDB 版本3.2

预期的计算和输出 (1 * 2 * 2)+(4 * 0 * 9)= 4

1 个答案:

答案 0 :(得分:0)

我怀疑是否可以处理“节点阵列可以在任何级别再次出现”。聚合。

使用map-reduce可能是这样的:

db.collection.mapReduce(
    function(){ 
        let reducer = (result, node) => {            
            Object.keys(node).map(key => {
                if (typeof node[key] === "object") {
                    if (node[key].nodes && Array.isArray(node[key].nodes)) {
                        result = node[key].nodes.reduce(reducer, result);
                    }
                } else {
                    result.product = result.product * node[key];
                    result.keys.add(key);
                }
            });
            return result;
        };        
        let {product, keys} = this.a.nodes.reduce(reducer, {product: 1, keys: new Set()});        
        emit(null, {product, keys: Array.from(keys)}) 
    },
    function(key, values){ 
        return values.reduce((total, item) => {
            let totalSum = total.sum, itemSum = item.product;
            for (let key of item.keys) if (!total.keys.includes(key)) totalSum = 0;
            for (let key of total.keys) if (!item.keys.includes(key)) itemSum = 0;

            return {sum: totalSum + itemSum, keys: Array.from(new Set([...total.keys, ...item.keys]))};
        }, {sum: 0, keys: []}).sum;
    },
    { query: { "a.nodes": { $exists: true } } , out: { inline: 1 }}
);

Map函数递归地乘以所有键,reducer检查键并计算总数。