使用 pymongo 和 Flask 从 MongoDB 聚合和计算结果中的项目

Aggregate and Count Items in a Result from MongoDB using pymongo & Flask

我正在尝试 return 在 Flask 环境中使用 pymongo MongoDB 得到一个简单的 JSON 结果。这是我正在做的:

def myResults():
    myCollection = db["my_data"]
    results = list(myCollection.find({},{"ID":1,"Response":1,"_id":0}))
    return jsonify(results=results)

当我这样做时,我得到以下结果。仅供参考 "ID" 基本上是一个虚构的唯一标识符。

{
  "result": [
    {
      "ID": 1, 
      "Response": "A"
    }, 
    {
      "ID": 4, 
      "Response": "B"
    }, 
    {
      "ID": 3, 
      "Response": "A"
    },
  ]
} // and so on...

我想汇总特定 ID 的所有回复并显示计数。我猜看起来像这样的东西(或者如果有更好的方法):

{
  "result": [
    {
      "ID": 1, 
      "A": 2,
      "B": 1,
      "C": 5,
      "Total": 8
    }, 
    {
      "ID": 4, 
      "A": 0,
      "B": 5,
      "C": 18,
      "Total": 23
    }, 
    {
      "ID": 3, 
      "A": 12,
      "B": 6,
      "C": 8,
      "Total": 26
    },
  ]
}

Whosebug 上有人推荐使用 aggregate()。但这对我来说并不是很有效。

allResults = surveyCollection.aggregate([
    {"$unwind": result }, 
    {"$group": {"_id": result.ID, "A": {"$sum": 1}, "B": {"$sum": 1}}},
    {"$group": {"_id": None, "result": {"$push": {"ID": "$ID", "A": "$A", "B": "$B"}}}}
])

return jsonify(allResults)

我得到一个错误:AttributeError: 'list' object has no attribute 'ID'

有没有更简单的方法,只用find()count()

将 result.ID 替换为 "result.ID"。没有引号 python 将查找变量 result.ID(不存在)而不是向服务器发送文字字符串 "result.ID".

聚合框架引用所有带有$前缀的字段名称。这不是 "python" 代码,而是 "aggregation pipeline" 操作,因此它只是一个要转换为 BSON 的数据结构。

allResults = surveyCollection.aggregate([
    { "$group": {
        "_id": {
            "ID": "$ID",
            "type": "$Response"
        },
        "count": { "$sum": 1 },
    }},
    { "$group": {
        "_id": "$_id.ID",
        "A": { "$sum": { "$cond": [{ "$eq": [ "$_id.type", "A" ]}, "$count", 0 ] } },
        "B": { "$sum": { "$cond": [{ "$eq": [ "$_id.type", "B" ]}, "$count", 0 ] } },
        "C": { "$sum": { "$cond": [{ "$eq": [ "$_id.type", "C" ]}, "$count", 0 ] } },
        "Total": { "$sum": "$count" }
    }}
])

return jsonify(allResults)

根据您提供给我们的三个文件,这个结果:

{ "_id" : 1, "A" : 1, "B" : 0, "C" : 0, "Total" : 1 }
{ "_id" : 4, "A" : 0, "B" : 1, "C" : 0, "Total" : 1 }
{ "_id" : 3, "A" : 1, "B" : 0, "C" : 0, "Total" : 1 }

所以你最后开始做正确的事,但中间有点偏离轨道。

不能在这里做的是"dynanically"在聚合框架中创建字段,所以你需要指定所有必需的"properties"并测试条件如图。如果您不能接受它,那么您需要这种格式的 mapReduce。我个人会这样做更简单:

allResults = surveyCollection.aggregate([
    { "$group": {
        "_id": {
            "ID": "$ID",
            "type": "$Response"
        },
        "count": { "$sum": 1 }
    }},
    { "$group": {
        "_id": "$_id.ID",
        "results": { 
          "$push": {
            "type": "$_id.type", 
            "count": "$count"
          }
        },
        "Total": { "$sum": "$count" }
    }}
])

return jsonify(allResults)

不同的输出格式,但相同的基本信息和简单:

{ "_id" : 1, "results" : [ { "type" : "A", "count" : 1 } ], "Total" : 1 }
{ "_id" : 4, "results" : [ { "type" : "B", "count" : 1 } ], "Total" : 1 }
{ "_id" : 3, "results" : [ { "type" : "A", "count" : 1 } ], "Total" : 1 }

顺便说一句。这实际上看起来像是来自聚合结果,因此可能是时候重新访问创建源代码的代码了。