简体   繁体   中英

How to group documents of a collection to a map with unique field values as key and count of documents as mapped value in mongodb?

I need a mongodb query to get the list or map of values with unique value of the field(f) as the key in the collection and count of documents having the same value in the field(f) as the mapped value . How can I achieve this ?

Example:

Document1: {"id":"1","name":"n1","city":"c1"}
Document2: {"id":"2","name":"n2","city":"c2"}
Document3: {"id":"3","name":"n1","city":"c3"}
Document4: {"id":"4","name":"n1","city":"c5"}
Document5: {"id":"5","name":"n2","city":"c2"}
Document6: {"id":"6,""name":"n1","city":"c8"}
Document7: {"id":"7","name":"n3","city":"c9"}
Document8: {"id":"8","name":"n2","city":"c6"}

Query result should be something like this if group by field is "name":

{"n1":"4",
 "n2":"3",
 "n3":"1"}

It would be nice if the list is also sorted in the descending order.

It's worth noting, using data points as field names (keys) is somewhat considered an anti-pattern and makes tooling difficult. Nonetheless if you insist on having data points as field names you can use this complicated aggregation to perform the query output you desire...

Aggregation

db.collection.aggregate([
    {
        $group: { _id: "$name", "count": { "$sum": 1} }
    },
    {
        $sort: { "count": -1 }
    },
    {
        $group: { _id: null, "values": { "$push": { "name": "$_id", "count": "$count" } } }
    },
    {
        $project:
        {
            _id: 0,
            results:
            {
                $arrayToObject:
                {
                    $map:
                    {
                        input: "$values",
                        as: "pair",
                        in: ["$$pair.name", "$$pair.count"]
                    }
                }
            }
        }
    },
    {
        $replaceRoot: { newRoot: "$results" }
    }
])

Aggregation Explanation

This is a 5 stage aggregation consisting of the following...

  1. $group - get the count of the data as required by name.
  2. $sort - sort the results with count descending.
  3. $group - place results into an array for the next stage.
  4. $project - use the $arrayToObject and $map to pivot the data such that a data point can be a field name.
  5. $replaceRoot - make results the top level fields.

Sample Results

{ "n1" : 4, "n2" : 3, "n3" : 1 }

For whatever reason, you show desired results having count as a string, but my results show the count as an integer. I assume that is not an issue, and may actually be preferred.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM