聚合字段值以分隔键名称

时间:2015-10-28 07:10:39

标签: mongodb mongodb-query aggregation-framework

我在MongoDB中有一个集合,其样本数据类似于此(简化):

{
    _id: 1,
    username: "ted",
    content: "4125151",
    status: "complete"
}
{
    _id: 2,
    username: "sam",
    content: "4151",
    status: "new"
}
{
    _id: 3,
    username: "ted",
    content: "511",
    status: "new"
}
{
    _id: 4,
    username: "ted",
    content: "411",
    status: "in_progress"
}
{
    _id: 5,
    username: "pat",
    content: "1sds51",
    status: "complete"
}
{
    _id: 6,
    username: "ted",
    content: "4151",
    status: "in_progress"
}
{
    _id: 7,
    username: "ted",
    content: "4125",
    status: "in_progress"
}

我需要聚合数据,以便为每个用户提供每个状态值的计数以及记录总数。结果应如下所示:

[
{
    username: “pat”,
    new: 0,
    in_progress: 0,
    complete: 1,
    total: 1
},

{
    username: “sam”,
    new: 1,
    in_progress: 0,
    complete: 0,
    total: 1
},

{
    username: “ted”,
    new: 1,
    in_progress: 3,
    complete: 1,
    total: 5
}
]

或任何有效用于同一目的的格式,我希望能够使用ngRepeat以这种格式在前端显示:

User    New     In Progress Complete    Total
pat     0       0           1           1
sam     1       0           0           1
ted     1       3           1           5

我可以执行此聚合:

{
    "$group": {
        "_id": {
            "username": "$username",
            "status": "$status"
        },
        "count": {
            "$sum": 1
        }
    }
}

这为我提供了至少有一条记录的每个用户/状态组合的个人计数。但是我必须将它拼凑在一起才能以我可以在前端使用的格式获得它。这根本不是理想的。

有没有办法执行聚合以获取我需要的格式的数据?

2 个答案:

答案 0 :(得分:2)

您想要的是值的“条件”聚合,以便为每个状态生成不同的字段属性。

使用$cond运算符非常简单:

[
    { "$group": {
        "_id": "$username",
        "new": { "$sum": { "$cond": [{ "$eq": [ "$status", "new" ] },1,0 ] } },
        "complete": { "$sum": { "$cond": [{ "$eq": [ "$status", "complete" ] },1,0 ] } },
        "in_progress": { "$sum": { "$cond": [{ "$eq": [ "$status", "in_progress" ] },1,0 ] } },
        "total": { "$sum": 1 }
    }}
]

当然假设这些是唯一的“状态”值,但如果它们不是,那么只需添加一个$project来对所需的字段求和:

[
    { "$match": { "status": { "$in": [ "new", "complete", "in_progress" ] } } },
    { "$group": {
        "_id": "$username",
        "new": { "$sum": { "$cond": [{ "$eq": [ "$status", "new" ] },1,0 ] } },
        "complete": { "$sum": { "$cond": [{ "$eq": [ "$status", "complete" ] },1,0 ] } },
        "in_progress": { "$sum": { "$cond": [{ "$eq": [ "$status", "in_progress" ] },1,0 ] } }
    }},
    { "$project": {
        "new": 1,
        "complete": 1,
        "in_progress": 1,
        "total": { "$add": [ "$new", "$complete", "$in_progress" ] }
]

或者只是在$add中包含$group,并对单独的字段进行相同的计算。但是$match可能只是最好的想法,如果确实存在其他你不想要的状态值。

答案 1 :(得分:1)

使用$ group两次和$ push的另一个答案,在下面这个查询中你需要计算UI端的最终总数。

    db.collection.aggregate([
  {
    "$group": {
      "_id": {
        "username": "$username",
        "status": "$status"
      },
      "statuscount": {
        "$sum": 1
      }
    }
  },
  {
    "$group": {
      "_id": "$_id.username",
      "finalstatus": {
        "$push": {
          "Status": "$_id.status",
          "statuscount": "$statuscount"
        }
      }
    }
  }
])