Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

mongodb - Mongo Aggregation : $group and $project array to object for counts

I have documents like:

{
    "platform":"android",
    "install_date":20151029
}
  1. platform - can have one value from [android|ios|kindle|facebook ] .
  2. install_date - there are many install_dates

There are also many fields.

Aim : I am calculating installs per platform on particular date.

So I am using group by in aggregation framework and make counts by platform. Document should look like like:

{
  "install_date":20151029,
  "platform" : {
   "android":1000,
   "ios": 2000,
   "facebook":1500
  }
}

I have done like:

db.collection.aggregate([
  { 
      $group: { 
          _id: { platform: "$platform",install_date:"$install_date"},  
            count: { "$sum": 1 } 
        }
  },
  { 
      $group: { 
          _id: { install_date:"$_id.install_date"},
          platform: { $push :  {platform :"$_id.platform", count:"$count" } }  
      }
  },
  { 
     $project : { _id: 0, install_date: "$_id.install_date", platform: 1 } 
  }     
]) 

which Gives document like:

{
    "platform": [
        {
            "platform": "facebook",
            "count": 1500
        },
        {
            "platform": "ios",
            "count": 2000
        },
        {
            "platform": "android",
            "count": 1000
        }
    ],
    "install_date": 20151027
}

Problem:

Projecting array to single object as "platform"

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

With MongoDb 3.4 and newer, you can leverage the use of $arrayToObject operator to get the desired result. You would need to run the following aggregate pipeline:

db.collection.aggregate([
    { "$group": {
        "_id": {  
            "date": "$install_date",  
            "platform": { "$toLower": "$platform" }
        },
        "count": { "$sum": 1 }
    } },
    { "$group": {
        "_id": "$_id.date",
        "counts": {
            "$push": {
                "k": "$_id.platform",
                "v": "$count"
            }
        }
    } },
    {  "$addFields": {
        "install_date": "$_id", 
        "platform": { "$arrayToObject": "$counts" }
    }  },
    { "$project": { "counts": 0, "_id": 0 } } 
])

For older versions, take advantage of the $cond operator in the $group pipeline step to evaluate the counts based on the platform field value, something like the following:

db.collection.aggregate([    
    { "$group": { 
        "_id": "$install_date",             
        "android_count": {
            "$sum": {
                "$cond": [ { "$eq": [ "$platform", "android" ] }, 1, 0 ]
            }
        },
        "ios_count": {
            "$sum": {
                "$cond": [ { "$eq": [ "$platform", "ios" ] }, 1, 0 ]
            }
        },
        "facebook_count": {
            "$sum": {
                "$cond": [ { "$eq": [ "$platform", "facebook" ] }, 1, 0 ]
            }
        },
        "kindle_count": {
            "$sum": {
                "$cond": [ { "$eq": [ "$platform", "kindle" ] }, 1, 0 ]
            }
        } 
    } },
    { "$project": {
        "_id": 0, "install_date": "$_id",            
        "platform": {
            "android": "$android_count",
            "ios": "$ios_count",
            "facebook": "$facebook_count",
            "kindle": "$kindle_count"
        }
    } }
])

In the above, $cond takes a logical condition as it's first argument (if) and then returns the second argument where the evaluation is true (then) or the third argument where false (else). This makes true/false returns into 1 and 0 to feed to $sum respectively.

So for example, if { "$eq": [ "$platform", "facebook" ] }, is true then the expression will evaluate to { $sum: 1 } else it will be { $sum: 0 }


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...