【问题标题】:Get count of product attributes from MongoDB从 MongoDB 获取产品属性计数
【发布时间】:2017-06-11 14:45:55
【问题描述】:

我有一个带有属性的产品的 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 }

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

我不需要找到属性的总数,我需要找到每个属性的计数,例如:
{ "key" : "c", "value" : 59 } 有 2345 个产品
{ "key" : "m", "value" : 21 } 有 258 个产品

【问题讨论】:

    标签: mongodb mapreduce mongodb-query aggregation-framework


    【解决方案1】:

    要通过键值对获得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
           }
        }
    ])
    

    【讨论】:

      【解决方案2】:

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

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

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

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

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


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

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

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

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

      【讨论】:

      • 我不需要查找属性的总数,我需要查找每个属性的计数,例如:{ "key" : "c", "value" : 59 } 有 2345 个产品 { " key" : "m", "value" : 21 } 有 258 个产品
      • 哦,完全偏离了轨道。感谢更新。在这种情况下,您需要一个 $unwind 和一个 $group 管道,如上述更新中所示。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      • 2019-04-30
      • 1970-01-01
      相关资源
      最近更新 更多