Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB aggregation: flatten array property into root array

I'm working on a feature that recursively looks up a thread of comments using $graphLookUp, and I almost have it. (albeit in a somewhat convoluted way but it is working!)

The last step I need is the following: instead of having the nested posteriorThread as a property of the root array ($$ROOT), just merge it onto the root itself.

  • AGGREGATION CODE:
const posteriorThread = await Comment.aggregate([
  {
    $match: {
      _id: post.threadDescendant
    }
  },

  {
    $graphLookup: {
      from: 'baseposts',
      startWith: '$threadDescendant',
      connectFromField: 'threadDescendant',
      connectToField: '_id',
      as: 'posteriorThread'
    }
  },

  {
    $unwind: '$posteriorThread'
  },

  {
    $sort: { 'posteriorThread.depth': 1 }
  },

  {
    $group: {
      _id: '$_id',
      posteriorThread: { $push: '$posteriorThread' },
      root: { $first: '$$ROOT' }
    }
  },

  {
    $project: {
      'root.posteriorThread': 0
    }
  },

  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          {
            posteriorThread: '$posteriorThread'
          },
          '$root'
        ]
      }
    }
  }
]);
  • CURRENT OUTPUT
 OUTPUT: posteriorThread
[
  {
    _id: '5f7eab40575e6fc56ee07604',
    onModel: 'BasePost',
    depth: 1,
    user: '5f5da45245c07cc06e51b09f',
    text: 'thread 0',
    isThread: true,
    threadDescendant: '5f7eabad575e6fc56ee07607',
    posteriorThread: [
      {
        _id: '5f7eabad575e6fc56ee07607',
        onModel: 'Comment',
        depth: 2,
        user: '5f5da45245c07cc06e51b09f',
        text: 'thread 1',
        isThread: true,
        threadDescendant: '5f7eac82575e6fc56ee07609'
      },
      {
        _id: '5f7eac82575e6fc56ee07609',
        onModel: 'Comment',
        depth: 3,
        user: '5f5da45245c07cc06e51b09f',
        text: 'thread 2',
        isThread: true
      }
    ]
  }
];

  • DESIRED OUTPUT
OUTPUT: posteriorThread 
[
  {
    _id: '5f7eab40575e6fc56ee07604',
    onModel: 'BasePost',
    depth: 1,
    user: '5f5da45245c07cc06e51b09f',
    text: 'thread 0',
    isThread: true,
    threadDescendant: '5f7eabad575e6fc56ee07607'
  },
  {
    _id: '5f7eabad575e6fc56ee07607',
    onModel: 'Comment',
    depth: 2,
    user: '5f5da45245c07cc06e51b09f',
    text: 'thread 1',
    isThread: true,
    threadDescendant: '5f7eac82575e6fc56ee07609'
  },
  {
    _id: '5f7eac82575e6fc56ee07609',
    onModel: 'Comment',
    depth: 3,
    user: '5f5da45245c07cc06e51b09f',
    text: 'thread 2',
    isThread: true
  }
];

I could accomplish this after the aggregation in regular js, but I would prefer to do it all in the aggregation. The part that needs to be replaced is the mergeObjects bit and replaced with something else or the group aggregation and taking a different strategy, but I'm not sure what to put in it's place. Also, if you have any other suggestions to make this cleaner, I'm all ears.

Thanks in advance.

like image 605
ram Avatar asked Mar 26 '26 04:03

ram


1 Answers

Its really challenging. Atleast for me. And really very interesting case. Lets try my solution. Hope it works..

db.test.aggregate([

    // PREVIOSU STEPS YOU ALREADY DID

    {
        $group: {
            _id: "$_id",
            items: {$push: "$$ROOT"},
            subItems: {$first: "$posteriorThread"}
        }
    },
    {
        $project: {
            "items.posteriorThread": 0
        }
    },
    {
        $addFields: {
            allItems: {
                $concatArrays: ["$items", "$subItems"]
            }
        }
    },
    {
        $group: {
            _id: null,
            mergedItems: {$push: "$allItems"}
        }
    },
    {
        $unwind: "$mergedItems"
    },
    {
        $unwind: "$mergedItems"
    },
    {
        $replaceRoot: {
          newRoot: "$mergedItems"
        }
    }

])
like image 119
Sunil K Samanta Avatar answered Mar 27 '26 18:03

Sunil K Samanta



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!