0

Inspired by another question I was looking for a common way to add a field with the index to each item in a nested array.

Assuming my document looks like:

  {
    _id: ObjectId("5a934e000102030405000000"),
    events: [
      {
        status: 0,
        timestamp: ISODate("2022-05-29T13:26:00Z")
      },
      {
        status: 8,
        timestamp: ISODate("2022-05-29T14:41:00Z")
      },
      {
        status: 4,
        timestamp: ISODate("2022-05-31T10:13:00Z")
      },
      {
        status: 3,
        timestamp: ISODate("2022-05-31T10:18:00Z")
      }
    ]
  }

And I want each item to contain a new field which is the index of the item in the array:

{
    _id: ObjectId("5a934e000102030405000000"),
    events: [
      {
        arrayIndex: 0,
        status: 0,
        timestamp: ISODate("2022-05-29T13:26:00Z")
      },
      {
        arrayIndex: 1,
        status: 8,
        timestamp: ISODate("2022-05-29T14:41:00Z")
      },
      {
        arrayIndex: 2,
        status: 4,
        timestamp: ISODate("2022-05-31T10:13:00Z")
      },
      {
        arrayIndex: 3,
        status: 3,
        timestamp: ISODate("2022-05-31T10:18:00Z")
      }
    ]
  }
nimrod serok
  • 14,151
  • 2
  • 11
  • 33

1 Answers1

0

Since mongoDB version 3.4, this can be done using an aggregation pipeline with a $reduce phase, which uses the size of the new accumulated array:

db.collection.aggregate([
  {$project: {
      events: {
        $reduce: {
          input: "$events",
          initialValue: [],
          in: {
            $concatArrays: [
              "$$value",
              [
                {$mergeObjects: [
                    "$$this",
                    {arrayIndex: {$size: "$$value"}}
                ]}
              ]
            ]
          }
        }
      }
  }}
])

See how it works on the playground example

nimrod serok
  • 14,151
  • 2
  • 11
  • 33