【问题标题】:Aggregate and Count Items in a Result from MongoDB using pymongo & Flask使用 pymongo 和 Flask 在 MongoDB 的结果中聚合和计数项目
【发布时间】:2015-11-07 02:15:21
【问题描述】:

我正在尝试在 Flask 环境中使用 pymongo 从 MongoDB 返回一个简单的 JSON 结果。这就是我正在做的事情:

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

当我这样做时,我得到以下结果。 FYI "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
    },
  ]
}

StackOverflow 上有人推荐使用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() 就没有更简单的方法吗?

【问题讨论】:

  • Find() 返回一个游标,其中包含查询中收集的所有数据,它的简单命令,您只需对其进行迭代并获取信息。你这样做吗?
  • @Urbester 是的,我过去曾使用find() 来迭代并获取我想要的信息,但我想知道是否可以附加count() 以解决上述问题。

标签: python mongodb mongodb-query pymongo aggregation-framework


【解决方案1】:

聚合框架引用所有带有$ 前缀的字段名称。这不是“python”代码,而是“聚合管道”操作,因此它只是一个要翻译成 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 }

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

您在此处不能做的是在聚合框架中“动态地”创建字段,因此您需要指定所有必需的“属性”并使用所示条件进行测试。如果你不能忍受,那么你需要这种格式的 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 }

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

【讨论】:

  • 感谢您的修复。说得通。但不幸的是,我没有看到结果。我得到这个作为我的结果{"ok": 1.0,"result": []}。此外,"$add" 之后的 : 由于某种原因会导致语法错误。
  • @mapr 看来您正试图从之前的聚合阶段继续,实际上每个步骤似乎都是作为一个单独的问题提出的。这会混淆您和其他所有人的上下文。我建议事先在组中添加您之前的“计数”阶段(或者您可能使用不同的字段名称),确保将所有字段添加为聚合管道阶段仅接收输出的内容。下次你问的时候,从你的源数据开始。这样做是阶段性的只会误导你,当然可以做得更好。但这是另一个问题。
  • @mapr 你说的是哪个原始问题?如果我使用上面显示的数据创建一个新集合(实际上是单个文档),那么我得到的结果正是您使用上面的查询显示的结果。正如我所说,你显然在这里做了一些不同的事情。
  • @mapr 让我们重新开始好吧,从最近的信息源完成,我认为这是您的原始数据。
  • 你可能做对了,我相信你。但我在这里没有做不同的事情。我正在仔细检查我的工作,所以我会回复你的。我觉得这条线可能会导致问题,即使我知道它是正确的:results = list(myCollection.find({},{"ID":1,"Response":1,"_id":0}))
【解决方案2】:

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

【讨论】:

  • 这导致pymongo.errors.OperationFailure。我认为$ 需要在result 字符串之前出现。
猜你喜欢
  • 2019-01-22
  • 2020-06-25
  • 1970-01-01
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多