平均Mongo中的文档的子文档字段

时间:2013-11-07 23:31:44

标签: mongodb

对于给定的记录ID,如果我在MongoDB中有以下内容,如何获得子文档字段的平均值:

/* 0 */
{
    "item" : "1",
    "samples" : [ 
        {
            "key" : "test-key",
            "value" : "1"
        }, 
        {
            "key" : "test-key2",
            "value" : "2"
        }
    ]
}

/* 1 */
{
    "item" : "1",
    "samples" : [ 
        {
            "key" : "test-key",
            "value" : "3"
        }, 
        {
            "key" : "test-key2",
            "value" : "4"
        }
    ]
}

我想获得给定项目id的key =“test-key”值的平均值(在本例中为1)。所以平均值应该是$ avg(1 + 3)= 2

由于

1 个答案:

答案 0 :(得分:11)

您需要使用aggregation framework.

您的查询最终会看起来像这样:

db.stack.aggregate([
  { $unwind : "$samples" },
  { $match : { "samples.key" : "test-key" } },
  { $project : { "new_key" : "$samples.key", "new_value" : "$samples.value" } },
  { $group : { _id : "$new_key", answer : { $avg : "$new_value" } } }
])

编辑:我只是弄清楚为什么我无法让上面的查询工作。在上面发布的数据中,您将值定义为文本值而不是数字。您不能跨文本字段求和。

编辑2:以防您需要执行更新:MongoDB How to change the type of a field

编辑3:说明:

考虑聚合框架的最佳方式就像装配线。查询本身是一个JSON文档数组,其中每个子文档代表程序集中的不同步骤。

第一步$unwind用于分隔“samples”数组中的每个元素,以便我们可以跨所有元素执行操作。如果只使用该步骤运行查询,您将看到我的意思。 长话短说:

{ name : "bob", 
  children : [ {"name" : mary}, { "name" : "sue" } ] 
} 

成为两个文件:

{ name : "bob", children : [ { "name" : mary } ] }
{ name : "bob", children : [ { "name" : sue } ] }

第二步$match就像SQL中的WHERE子句。它会过滤与您定义的条件不匹配的所有文档。在这种情况下,我们只保留samples.key =“test-key”

的文档

第三步$project重新构建文档。在这种情况下,我将项目从数组中拉出来,以便我可以直接引用它们。使用上面的例子..

{ name : "bob", children : [ { "name" : mary } ] }

变为

{ new_name : "bob", new_child_name : mary }

最后,$group是神奇发生的地方。 _id值将在SQL世界中“分组”。第二个字段是对我在$project步骤中定义的值进行平均。您可以轻松替换$sum来执行求和,但计数操作通常通过以下方式完成:my_count : { $sum : 1 }

这里需要注意的最重要的事情是,要完成的大部分工作是将数据格式化到执行操作很简单的程度。 :)