Search code examples
arraysmongodbaggregation-frameworkslice

In MondoDB : Slice array of objects from slicing index array and push in array through aggregation


I want to slice array in document according to slicingIndex key available in the same document and push into an array.

[
  {
    slicingIndex: [0, 4, 7, 10],
    array: [
      { name: 1 },
      { name: 2 },
      { name: 3 },
      { name: 4 },
      { name: 5 },
      { name: 6 },
      { name: 7 },
      { name: 8 },
      { name: 9 },
      { name: 10 }
    ]
  }
]

Output (expected):

{
  "array": [
    [
      { "name": 1 },
      { "name": 2 },
      { "name": 3 },
      { "name": 4 }
    ],
    [
      { "name": 5 },
      { "name": 6 },
      { "name": 7 }
    ],
    [
      { "name": 8 },
      { "name": 9 },
      { "name": 10 }
    ]
  ]
}

This is what aggregation i tried below but not working as expected:

db.collection.aggregate([
  {
    "$project": {
      slicingIndex: 1,
      array: {
        "$map": {
          "input": "$slicingIndex",
          "as": "num",
          "in": {
            "$slice": [
              "$array",
              "$$num",
              {
                "$subtract": [
                  {
                    "$arrayElemAt": ["$slicingIndex", { "$indexOfArray": ["$slicingIndex", "$$num"] }]
                  },
                  "$$num"
                ]
              }
            ]
          }
        }
      }
    }
  }
])

Solution

  • MongoDb Playground Link : https://mongoplayground.net/p/oNzBVLRfIU0

    $add & $indexOfArray used to take one step ahead element from current pointer in array like (n+1).
    $let : I have used it as optional to make variable reusable if needed.
    $map : To traverse array elements.
    $arrayElemAt : To get from element from array.
    $subtract : To perform operation like [ (n+1) - n ] where n is index in array.
    $filter : To filter out elements (in our case: null).

    db.collection.aggregate([
      {
        "$project": {
          array: {
            "$map": {
              "input": "$slicingIndex",
              "as": "elem",
              "in": {
                "$let": {
                  "vars": {
                    //create variable that holds element one index+1 to the current index
                    "elemOneStepHeadToElem": {
                      "$arrayElemAt": [
                        "$slicingIndex",
                        {
                          $add: [
                            1,
                            {
                              "$indexOfArray": [
                                "$slicingIndex",
                                "$$elem"
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  },
                  "in": {
                    "$slice": [
                      "$array",
                      "$$elem",
                      {
                        "$subtract": [
                          "$$elemOneStepHeadToElem",
                          "$$elem"
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }//remove null from array from last index
      ,
      {
        "$project": {
          array: {
            "$filter": {
              "input": "$array",
              "cond": {
                $ne: [
                  "$$this",
                  null
                ]
              }
            }
          }
        }
      }
    ])