Search code examples
python-3.xmongodbaggregatepymongo

PyMongo get analytics by field for given query


I have documents in mongo db, like

doc = {
    name = MyName,
    tags = tag1,tag2,tag3,
    ...
}

When I search documents by name, I also want to get analytics of tags, for docs with that name, like

{
   tag1: 7,
   tag2: 5,
   ...
   tagn: 14
}

How can I aggregate it?


Solution

  • The data model complicates the query somewhat and the required output format complicates it even more ... but here's one way to do it.

    db.collection.aggregate([
      {
        "$set": {
          "tags": {
            "$split": ["$tags", ","]
          }
        }
      },
      {"$unwind": "$tags"},
      {
        "$set": {
          "tags": {
            "$trim": {"input": "$tags"}
          }
        }
      },
      {
        "$group": {
          "_id": "$tags",
          "count": {"$count": {}}
        }
      },
      {
        "$sort": {"_id": 1}
      },
      {
        "$group": {
          "_id": null,
          "newRoot": {
            "$mergeObjects": {
              "$arrayToObject": [
                [
                  {
                    "$reduce": {
                      "input": {"$objectToArray": "$$ROOT"},
                      "initialValue": {},
                      "in": {
                        "$mergeObjects": [
                          "$$value",
                          {
                            "$switch": {
                              "branches": [
                                {
                                  "case": {"$eq": ["$$this.k", "_id"]},
                                  "then": {"k": "$$this.v"}
                                },
                                {
                                  "case": {"$eq": ["$$this.k", "count"]},
                                  "then": {"v": "$$this.v"}
                                }
                              ],
                              "default": "$$value"
                            }
                          }
                        ]
                      }
                    }
                  }
                ]
              ]
            }
          }
        }
      },
      {"$replaceWith": "$newRoot"}
    ])
    

    Example output:

    [
      {
        "tag1": 2,
        "tag2": 2,
        "tag3": 3,
        "tag5": 1,
        "tag7": 1
      }
    ]
    

    Try it on mongoplayground.net.