0

I have following collection

[
  {
    "receiverWorkout": {
      "_id": "5b4f3920c805e1299b90716c",
      "name": "nmbnmbnmnbm",
      "exercises": [
        {
          "_id": "5b4f3920c805e1299b90716f",
          "reps": 0,
          "weights": 0
        },
        {
          "_id": "5b4c3920c805e1299b90716f",
          "reps": 4,
          "weights": 0
        }
      ]
    },
    "senderWorkout": {
      "_id": "5b4f11f16cf99524f21d2287",
      "name": "nmbnmbnmnbm",
      "exercises": [
        {
          "_id": "5b4f11f16cf99524f21d2288",
          "reps": 12,
          "weights": 0
        },
        {
          "_id": "5b4f7920c805e1299b90716f",
          "reps": 8,
          "weights": 0
        }
      ]
    }
  }
]

I need to compare both the exercises array and add new field called won to only senderWorkout ... Winning will be calculated on the reps field... And same index exercises will be matched i.e. first with first exercise and second with second exercise...

So my expected output will be

[
  {
    "receiverWorkout": {
      "_id": "5b4f3920c805e1299b90716c",
      "name": "nmbnmbnmnbm",
      "exercises": [
        {
          "_id": "5b4f3920c805e1299b90716f",
          "reps": 0,
          "weights": 0
        },
        {
          "_id": "5b4c3920c805e1299b90716f",
          "reps": 4,
          "weights": 0
        }
      ]
    },
    "senderWorkout": {
      "_id": "5b4f11f16cf99524f21d2287",
      "name": "nmbnmbnmnbm",
      "exercises": [
        {
          "_id": "5b4f11f16cf99524f21d2288",
          "reps": 12,
          "weights": 0,
          "result": "won"
        },
        {
          "_id": "5b4f7920c805e1299b90716f",
          "reps": 2,
          "weights": 0,
          "result": "lost"
        }
      ]
    }
  }
]

1 Answer 1

1

You can use below aggregation in 3.4 aggregation.

$range to iterate over senderWorkout exercises and $map to keep the exercise fields along with extra field to compare the array elements and output the boolean field.

$let expression with index ( from $range (ix) ) to output the sender and receiver element.

$addFields to update only senderWorkout exercise while keeping all the existing fields.

db.colname.aggregate({
  "$addFields":{
    "senderWorkout.exercises":{
      "$map":{
        "input":{"$range":[0,{"$size":"$senderWorkout.exercises"}]},
        "as":"ix",
        "in":{
          "$let":{
            "vars":{
              "rec":{"$arrayElemAt":["$receiverWorkout.exercises","$$ix"]},
              "sen":{"$arrayElemAt":["$senderWorkout.exercises","$$ix"]}
            },
            "in":{
              "_id":"$$sen._id",
              "reps":"$$sen.reps",
              "weights":"$$sen.weights",
              "won":{"$gt":["$$sen.reps","$$rec.reps"]}
            }
          }
        }
      }
    }
  }
})
Sign up to request clarification or add additional context in comments.

2 Comments

thanks!!! that's exactly what I want... Perfect man you are awesome... Can you please explain how $range and $let works here?
Yw. $range will iterate the sender array and $let to output the sender and receiver array element at the index followed by comparison to produce win field.

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.