从MongoDB获取产品属性的数量

时间:2017-01-26 06:57:02

标签: mongodb mapreduce mongodb-query aggregation-framework

我有一组具有属性的mongo产品:

{
  "_id" : ObjectId("5888a2860c001d31a1089958"),
  "product_id" : "107",
  "store_id" : 0,
  "attributes" : [{
      "key" : "m",
      "value" : 21,
      "label" : "Mothercare"
    }, {
      "key" : "sp",
      "value" : 10.0,
      "label" : 10.0
    }, {
      "key" : "pr",
      "value" : 2,
      "label" : "150-300"
    }, {
      "key" : "c",
      "value" : 59,
      "label" : "Category 1"
    }, {
      "key" : "c",
      "value" : 86,
      "label" : "Category 2"
    }, {
      "key" : "c",
      "value" : 134,
      "label" : "Category 3"
    }, {
      "key" : "c",
      "value" : 1013,
      "label" : "Category 4"
    }, {
      "key" : "c",
      "value" : 1063,
      "label" : "Category 5"
    }, {
      "key" : "c",
      "value" : 1073,
      "label" : "Category 6"
    }, {
      "key" : "13",
      "value" : 270,
      "label" : "Brown"
    }, {
      "key" : "18",
      "value" : 125,
      "label" : "Girl"
    }, {
      "key" : "19",
      "value" : 298,
      "label" : "0-3 month"
    }, {
      "key" : "19",
      "value" : 299,
      "label" : "3-6 month"
    }, {
      "key" : "19",
      "value" : 300,
      "label" : "6-9 month"
    }, {
      "key" : "19",
      "value" : 301,
      "label" : "9-12 month"
    }]
}

我需要找到快速获取集合中所有属性的计数方法。我曾尝试使用MapReduce:

function map() {
    var max = this.attributes.length;
    var key = {};

    for (var i = 0; i < max; i++) {
        key = {
            key: this.attributes[i]['key'],
            value: this.attributes[i]['value'],
        }

        emit(key, {count: 1}); 
    }
}
function reduce(key, values) {
    var sum = 0;
    values.forEach(function(value) {
        sum += value['count'];
    });
    return {count: sum};
};

但它很慢:

timeMillis=2420  
counts={ "input" : 18963, "emit" : 221232, "reduce" : 7341, "output" : 1289 }

如何更快地找到所有属性的数量?我需要它用于产品过滤器。也许我必须使用其他收藏结构?

我不需要查找属性总数,我需要找到每个属性的计数,例如:
{&#34; key&#34; :&#34; c&#34;,&#34;价值&#34; :59}共有2345件产品
{&#34; key&#34; :&#34; m&#34;,&#34;价值&#34; :21}有258个产品

2 个答案:

答案 0 :(得分:1)

运行以下管道将为您提供所需的结果:

db.collection.aggregate([
    { "$unwind": "$attributes" },
    {
        "$group": {
            "_id": {
                "key": "$attributes.key",
                "value": "$attributes.value"
            },
            "counts": { "$sum": 1 }
        }
    }
])

要获得更有效的查询,请使用聚合框架。考虑使用 $project 运行管道,使用attributes数组上的 $size 运算符获取每个文档的属性数,然后决赛 $group 管道,您可以在其中指定_id值null,以计算所有输入文档的累计值,并使用 {{3计算总计数如下:

db.collection.aggregate([
    {
        "$project": {
            "counts": {
                "$size": "$attributes"
            }
        }       
    },
    {
        "$group": {
            "_id": null,
            "counts": { "$sum": "$counts" }
        }
    }
])

以上内容将返回集合中所有产品的属性总数。

如果您想使用属性的数量来过滤产品,请考虑使用 $sum 管道:

var attributeCount = 12; // for example
db.collection.aggregate([
    {
        "$redact": {
            "$cond": [
                { "$eq": [ { "$size": "$attributes" }, attributeCount ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }       
    }
])

这相当于 $redact $project 管道的组合,尽管您不必指定其中的所有字段 $match 管道,如下所示:

db.collection.aggregate([
    {
        "$project": {
            "product_id": 1,
            "store_id": 1,
            "$attributes": 1,
            "counts": {
                "$size": "$attributes"
            }
        }       
    },
    { "$match": { "counts": { "$gte": attributeCount } } }
])

答案 1 :(得分:0)

要通过键值对获得attributes的总计数,可以尝试此查询。

db.collectionName.aggregate([
    {$unwind:{"$attributes"}}
    {$group: {
            _id: {"key": "$attributes.key","value": "$attributes.value"},
            count: { $sum: 1 }
        }
    },
    {$project:{
        key:"$_id.key",
        value:"$_id.value",
        count:1
       }
    }
])