Home > Software design >  Aggregation $match within a $sum
Aggregation $match within a $sum

Time:07-24

I was wondering if it was possible to somehow use the $match operator within the $sum function for aggregation.

{   "$unwind": "$info.avatarInfoList" },
{   "$unwind": "$info.avatarInfoList.equipList" },
{   "$unwind": "$info.avatarInfoList.equipList.flat.reliquarySubstats" },
{
    "$project": {
        "name" : "$name",
        "character" : "$info.avatarInfoList.avatarId",
        "artifact" : "$info.avatarInfoList.equipList.itemId",
        "statValue" : {
            "$sum": [
                 {"$match" : { "$info.avatarInfoList.equipList.flat.reliquarySubstats.appendPropId" : "FIGHT_PROP_CRITICAL_HURT" } },
                 {"$multiply": [2, {"$match" : { "$info.avatarInfoList.equipList.flat.reliquarySubstats.appendPropId" : "FIGHT_PROP_CRITICAL" } }]}
            ]
        },
    }
},
{ "$sort": { "statValue": -1 }},
{ '$limit' : 30 }
]).to_list(length=None) 
print(data)

I want to be able to use the value of the $sum operator within the project fields somehow, I just don't really understand what the right approach would be for this.

Sample Input (may be too long): https://www.toptal.com/developers/hastebin/ixamekaxoq.json

Sample Output: ( 2 * FIGHT_PROP_CRITICAL ) FIGHT_PROP_CRITICAL_HURT sorted from highest to lowest for each item.

{name: hat, character: Slayer, artifact: 13, statValue : 25.6}

CodePudding user response:

It's not quite clear what you want to achieve, but as mentioned you want to be using $cond here.

like so:

{
  "$project": {
    "statValue": {
      "$sum": [
        {
          $cond: [
            { // if this condition is true (prop id = prop critical hurt )
              $eq: [
                  "$info.avatarInfoList.equipList.flat.reliquarySubstats.appendPropId",
                  "FIGHT_PROP_CRITICAL_HURT"
              ]
            },
            { // then use this value for the "$sum"
              "$multiply": [
                  2,
                  "$info.avatarInfoList.equipList.flat.reliquarySubstats.statValue"
              ]
            },
            0 // otherwise use this value for the sum.
          ]
        }
      ]
  }
}

Mongo Playground

CodePudding user response:

There are still a few ambiguities about how you want to aggregate your data, but using the full document from your link, here's one way to produce the output you want.

N.B.: Weapons in the "equipList" don't have "reliquarySubstats" so they show a "statValue" of null in the output.

db.collection.aggregate([
  {"$unwind": "$info.avatarInfoList"},
  {"$unwind": "$info.avatarInfoList.equipList"},
  {
    "$project": {
      "_id": 0,
      "name": 1,
      "character": "$info.avatarInfoList.avatarId",
      "artifact": "$info.avatarInfoList.equipList.itemId",
      "statValue": {
        "$reduce": {
          "input": "$info.avatarInfoList.equipList.flat.reliquarySubstats",
          "initialValue": 0,
          "in": {
            "$switch": {
              "branches": [
                {
                  "case": {"$eq": ["$$this.appendPropId", "FIGHT_PROP_CRITICAL"]},
                  "then": {
                    "$add": [
                      "$$value",
                      {"$multiply": [2, "$$this.statValue"]}
                    ]
                  }
                },
                {
                  "case": {"$eq": ["$$this.appendPropId", "FIGHT_PROP_CRITICAL_HURT"]},
                  "then": {"$add": ["$$value", "$$this.statValue"]}
                }
              ],
              "default": "$$value"
            }
          }
        }
      }
    }
  },
  {"$sort": {"statValue": -1}}
])

Try it on mongoplayground.net.

  • Related