Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

236
Views
Get count of product attributes from MongoDB

I have a mongo collection of products with attributes:

{
  "_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"
    }]
}

I need to find fast way for get count of all attributes in collection. I have tried to use 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};
};

But it very slow:

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

How can I find the quantity of all attributes faster? I need it for product filter. Maybe I must use other collection structure?

I not need to find total count of attributes, I need to find count of each attribute, for example:
{ "key" : "c", "value" : 59 } has 2345 products
{ "key" : "m", "value" : 21 } has 258 products

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Running the following pipeline will give you the desired result:

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

For a more efficient query, use the aggregation framework. Consider running a pipeline with $project to get the number of attributes per document using the $size operator on the attributes array and then a final $group pipeline where you can specify an _id value of null to calculate accumulated values for all the input documents as a whole and calculate the total counts using $sum as follows:

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

The above will return the total number of attributes of ALL products in a collection.


If you want to use the count of the attributes to filter a product, then consider using the $redact pipeline as:

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

This is equivalent to a combination of a $project and $match pipeline albeit you don't have to specify all the fields in the $project pipeline, as in the following:

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

over 4 years ago · Santiago Trujillo Report

0

To get total count of attributes by key value pair can try this query.

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
       }
    }
])
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!