mongodbnosqltypegoose

Merge nested array data in single array and get them into root of document


I am struggling with retrieving nested document in root.

below i have a schema inside it there is a array of tasks in which objects are present, in those objects there is again an array of assigned objects and in those objects i have solution array.

now i want to merge all solutions in one array and get that solution array in root od document.

Schema -

{
  _id: 1,
  tasks: [
    {
      _id: 1,
      assigned: [
        {
          _id: 1,
          solutions: [
            {
              _id: 1,
              name: 'solution 1',
            },
            {
              _id: 2,
              name: 'solution 2',
            },
          ],
        },
        {
          _id: 2,
          solutions: [
            {
              _id: 1,
              name: 'solution 1',
            },
            {
              _id: 2,
              name: 'solution 2',
            },
          ],
        },
      ],
    },
  ],
};

I want to merge all solutions to a single array based on some condition and set that array into new field in root of collection.

const order = this.orderModel
      .aggregate([
        { $match: { _id: orderId, student: studentId } },
        {
          $addFields: {
            solutions: {
              $map: {
                input: '$tasks.assigned.solutions',
                as: 's',
                in: '$$s',
              },
            },
          },
        },
      ])
      .exec();

output i am getting -

"solutions": [
        [
            [
                {
                    "id": 1,
                    "name": "solution 1",
                }
            ],
            [
                {
                    "_id": 2,
                    "name": "solution 2"
                }
            ]
        ]
    ],

Solution

  • Maybe something like this:

    db.collection.aggregate([
    {
    "$project": {
      "solutions": {
        "$reduce": {
          "input": "$tasks",
          "initialValue": [],
          "in": {
            "$concatArrays": [
              "$$value",
              {
                $reduce: {
                  input: "$$this.assigned",
                  initialValue: [],
                  in: {
                    $concatArrays: [
                      "$$value",
                      "$$this.solutions"
                    ]
                  }
                }
              }
            ]
           }
         }
       }
     }
    }
    ])
    

    Explained:

    Use $project and two nested $reduce/$concatArrays to join the "solutions" array objects under the new array field "solutions" in the document root.

    Playground

    if you want to filter based on some condition you can replace "$$this.solutions" with:

              {
                $filter: {
                  input: "$$this.solutions",
                  cond: { $eq: ["$$this._id", 1] }
                }
              }
    

    will filter only documents with _id:1

    see example here