mongodb mongo db.将文档分组到数组中,对它们进行计数和求和,并添加新字段

rta7y2nd  于 2023-04-11  发布在  Go
关注(0)|答案(1)|浏览(138)

我有两个收藏:
带有一些操作的集合:

[
  {
    "id": 0,
    "action": "qwe",
    "timestamp": "2022-11-20T23:59:59",
    "user": "test"
  },
  {
    "id": 1,
    "action": "zwe",
    "timestamp": "2022-11-20T11:22:33",
    "user": "test"
  },
  {
    "id": 1,
    "action": "qwe",
    "timestamp": "2022-11-20T11:22:33",
    "user": "test"
  }
]

并收集此操作的分数:

[
  {
    "action": "qwe",
    "score": 5
  },
  {
    "action": "zwe",
    "score": 3
  },
  {
    "action": "qwe",
    "score": 5
  }
]

我需要实现下一个结果:

[
  {
    "user": "test",
    "actions": [
      {
        "action":"qwe",
        "score":5,
        "timestamp":"2022-11-17T12:55:34.804+00:00"
      },
      {
        "action":"zwe",
        "score":3,
        "timestamp":"2022-11-17T12:55:34.804+00:00"
      },
      {
        "action":"qwe",
        "score":5,
        "timestamp":"2022-11-18T12:51:11.804+00:00"
      }
    ],
    "actions_total": [
      {
          "action": "qwe",
          "count": 2,
          "total_score": 10
      },
      {
          "action": "zwe",
          "count": 1,
          "total_score": 3
      }
    ],
    "total_score": 13
  }
]

我写下一个聚合:

[
  {
    $match: {
      timestamp: {
        $gte: ISODate(
        '2022-11-17T00:00:00'
        ),
        $lte: ISODate(
        '2022-11-20T23:59:59'
        )
      }
    }
  },
  {
    $lookup: {
      from: 'actions_score',
      localField: 'action',
      foreignField: 'action',
      as: 'score'
    }
  },
  {
    $unwind: {
      path: "$score"
    }
  },
  {
    $project: {
      'username': true,
      'action': true,
      'score': '$score.score',
      'timestamp': true,
      'role_id': true,
      '_id': false
    }
  },
  {
    $group: {
      _id: '$username',
      'username': {
        $first: '$username'
      },
      'role_id': {
        $first: '$role_id'
      },
      'actions': {
        $addToSet: '$$ROOT'
      }
    }
  },
  {
    $addFields: {
      'total_score': {
        "$sum": "$actions.score"
      }
    }
  },
  {
    $project: {
      _id: false,
      'actions.username': false,
      'actions.role_id': false
    }
  }
]

我得到下一个结果:

[
  {
    "user": "test",
    "actions": [
      {
        "action":"qwe",
        "score":5,
        "timestamp":"2022-11-17T12:55:34.804+00:00"
      },
      {
        "action":"zwe",
        "score":3,
        "timestamp":"2022-11-17T12:55:34.804+00:00"
      },
      {
        "action":"qwe",
        "score":5,
        "timestamp":"2022-11-18T12:51:11.804+00:00"
      }
    ],
    "total_score": 13
  }
]

问题:
我怎样才能得到这个部分?我怎样才能通过现场操作来摸索文档并得到预期的结果?

"actions_total": [
      {
          "action": "qwe",
          "count": 2,
          "total_score": 10
      },
      {
          "action": "zwe",
          "count": 1,
          "total_score": 3
      }
    ]

将感激的帮助!

jchrr9hc

jchrr9hc1#

一个选项是使用$group两次,然后使用$reduce来展平数组:

db.actions.aggregate([
  {$match: {timestamp: {
        $gte: ISODate("2022-11-17T00:00:00Z"),
        $lte: ISODate("2022-11-20T23:59:59Z")
  }}},
  {$lookup: {
      from: "actions_score",
      localField: "action",
      foreignField: "action",
      as: "score"
  }},
  {$project: {
      user: 1, _id: 0, action: 1, score: {$first: "$score.score"}, timestamp: 1}},
  {$group: {
      _id: {user: "$user", action: "$action"},
      count: {$sum: 1},
      total_score: {$sum: "$score"},
      actions: {$addToSet: "$$ROOT"}
  }},
  {$group: {
      _id: "$_id.user",
      user: {$first: "$_id.user"},
      actions: {$push: "$actions"},
      actions_total: {$push: {
          action: "$_id.action",
          count: "$count",
          total_score: "$total_score"
      }},
      total_score: {$sum: "$total_score"}
  }},
  {$set: {
      actions: {$reduce: {
          input: "$actions",
          initialValue: [],
          in: {$concatArrays: ["$$value", "$$this"]}
      }}
  }}
])

了解它在playground example上的工作原理

相关问题