0

Here is my sample document structure e.g.

{
    "my_object": {
        "1": {
            "seq": "1",
            "time": "xyz",
        },
        "2": {
            "seq": "2",
            "time": "abc",
            "sub_aray": {
                "0": {
                    "value": 10
                },
                "1": {
                    "value": 10
                },
                "2": {
                    "value": -10
                }
            }
        }
    }
}

So what I want to achieve is, Sum of all the sub_array's value if exists, if sub_array isn't found, default it to 0

{"seq" : "1", "sub_array" : 0},
{"seq" : "2", "sub_array" : 10}

My Mongo version is 3.4.6 and I am using PyMongo as my driver.

5
  • can you please provide proper json format. Commented Aug 24, 2020 at 19:08
  • @turivishal Apologies, it should be fixed now. Commented Aug 24, 2020 at 19:19
  • Why seq2 is 20 instead 10? Commented Aug 24, 2020 at 19:25
  • Thanks for catching it, it was a typo Gibbs. Commented Aug 24, 2020 at 19:26
  • I was trying to use map and then just sum the "values" attribute, but the issue is coming when the input to the map's "input" is not present itself. Commented Aug 24, 2020 at 19:27

2 Answers 2

1

You can do as below

playground

db.collection.aggregate([
  {
    $project: {
      "array": { //To remove dynamic keys - 1,2,etc
        "$objectToArray": "$my_object"
      }
    }
  },
  {//reshaping array
    "$unwind": "$array"
  },
  {
    $project: {//reshaping sub array to access via a static name
      "k": {
        "$objectToArray": "$array.v.sub_aray"
      },
      "seq": "$array.v.seq"
    }
  },
  {
    "$project": {//actual logic, output structure
      "sub_array": {
        $sum: "$k.v.value"
      },
      "_id": 0,
      "seq": 1
    }
  }
])
Sign up to request clarification or add additional context in comments.

2 Comments

Wow! This is super clean ❤️! Thanks a lot!
Gibbs, Would appreciate if you can also share your thoughts on this question of mine stackoverflow.com/q/65857866/6524169 ; Thanks a lot for your help and time!
1

The trick part is to use the $objectToArray operator to iterate my_object items.

db.collection.aggregate([
  {
    "$project": {
      "my_object": {
        "$map": {
          input: {
            "$objectToArray": "$my_object"
          },
          as: "obj",
          in: {
            seq: "$$obj.v.seq",
            sub_array: {
              $sum: {
                $map: {
                  input: {
                    "$objectToArray": "$$obj.v.sub_aray"
                  },
                  as: "sub",
                  in: "$$sub.v.value"
                }
              }
            }
          }
        }
      }
    }
  },
  {
    "$unwind": "$my_object"
  },
  {
    "$replaceRoot": {
      "newRoot": "$my_object"
    }
  }
])

MongoPlayground

1 Comment

Thanks for sharing the map approach as well!❤️

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.