Tim Sims
Tim Sims

Reputation: 165

MongoDB - Group by and count value, but treat per record as one

I want to group by and count follow_user.tags.tag_id per record, so no matter how many times the same tag_id show up on the same record, it only counts as 1.

My database structure looks like this:

{ 
    "external_userid" : "EXID1", 
    "follow_user" : [
        {
            "userid" : "USERID1", 
            "tags" : [
                {
                    "tag_id" : "TAG1"
                }
            ]
        }, 
        {
            "userid" : "USERID2", 
            "tags" : [
                {
                    "tag_id" : "TAG1"
                },
                {
                    "tag_id" : "TAG2"
                }
            ]
        }
    ]
},
{ 
    "external_userid" : "EXID2", 
    "follow_user" : [
        {
            "userid" : "USERID1", 
            "tags" : [
                {
                    "tag_id" : "TAG2"
                }
            ]
        }
    ]
}

Here's my query:

[
  { "$unwind": "$follow_user" }, { "$unwind": "$follow_user.tags" },
  { "$group" : { "_id" : { "follow_user᎐tags᎐tag_id" : "$follow_user.tags.tag_id" }, "COUNT(_id)" : { "$sum" : 1 } } },
  { "$project" : { "total" : "$COUNT(_id)", "tagId" : "$_id.follow_user᎐tags᎐tag_id", "_id" : 0 } } 
]

What I expected:

{ 
    "total" : 1, 
    "tagId" : "TAG1"
},
{ 
    "total" : 2, 
    "tagId" : "TAG2"
}

What I get:

{ 
    "total" : 2, 
    "tagId" : "TAG1"
},
{ 
    "total" : 2, 
    "tagId" : "TAG2"
}

Upvotes: 0

Views: 35

Answers (1)

Yong Shun
Yong Shun

Reputation: 51125

  1. $set - Create a new field follow_user_tags.

    1.1. $setUnion - To distinct the value from the Result 1.1.1.

    1.1.1. $reduce - Add the value of follow_user.tags.tag_id into array.

  2. $unwind - Deconstruct follow_user_tags array field to multiple documents.

  3. $group - Group by follow_user_tags and perform total count via $sum.

  4. $project - Decorate output document.

db.collection.aggregate([
  {
    $set: {
      follow_user_tags: {
        $setUnion: {
          "$reduce": {
            "input": "$follow_user.tags",
            "initialValue": [],
            "in": {
              "$concatArrays": [
                "$$value",
                "$$this.tag_id"
              ]
            }
          }
        }
      }
    }
  },
  {
    $unwind: "$follow_user_tags"
  },
  {
    $group: {
      _id: "$follow_user_tags",
      total: {
        $sum: 1
      }
    }
  },
  {
    $project: {
      _id: 0,
      tagId: "$_id",
      total: 1
    }
  }
])

Sample Mongo Playground

Upvotes: 1

Related Questions