将文档在数组中分组,对它们进行评分、计数和求和,并添加新字段。

huangapple go评论57阅读模式
英文:

mongo db. Group documents in array, score them count and sum and add new field

问题

我可以为您翻译代码的这部分内容。以下是代码的翻译部分:

我有两个集合:

> 包含一些操作的集合:

[
  {
    "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
  }
]

将不胜感激您的帮助!
英文:

I have two collections:

> Collections with some actions:

[
{
"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"
}
]

> And collection with score of this actions:

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

> I need achieve next results:

[
{
"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
}
]

> I write next aggregation:

[
{
$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
}
}
]

> And i get next result:

[
{
"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
}
]

> Question:

How i can get this part? How i can grop documents by field actions and get expected results?

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

Will be grateful for the help!

答案1

得分: 1

以下是翻译好的部分代码:

One option is to use `$group` twice and then `$reduce` to flatten the array:

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示例上查看它的运行方式。

英文:

One option is to use $group twice and then $reduce to flatten the array:

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"]}
}}
}}
])

See how it works on the playground example

huangapple
  • 本文由 发表于 2023年4月10日 21:59:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75977772.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定