Home > OS >  Filtering items within object that is multiple level down with MongoQuery
Filtering items within object that is multiple level down with MongoQuery

Time:02-01

Please consider below model.

interface Model {
  title: string
  content: string
  comments: {
    content: string
    likes?: number
    subComments: {
      parentCommentId: string
      content: string
      likes?: number
    }[]
  }[]
}

const post: Model = {
  title: 'test',
  content: 'content',
  comments: [
    {
      content: 'level2',
      likes: 3,
      subComments: [
        {
          parentCommentId: '1',
          content: 'level3',
          likes: 3,
        },
      ],
    },
    {
      content: 'level2',
      likes: 3,
      subComments: [
        {
          parentCommentId: '1',
          content: 'level3',
          likes: 5,
        },
        {
          parentCommentId: '1',
          content: 'level3',
          likes: 5,
        },
      ],
    },
  ],
}

Let's say we have a post that has comment that has subComment.
The level of subComment is at level 3 but the depth is fixed.
Is there a way to filter subComments that has optional key "likes" and whose value is greater than 3 with MongoClient?

CodePudding user response:

Y don't know exactly what output do you want but you can try something like this example using only projection into find query:

Here there are two $filter and one map.

The $map get each object into comments array and:

  • Set the content as it is: content: "$$comment.content"
  • Set the subcomment as an array filtered only by these one objects where likes is greater than 3.
  • *I've not added likes because it seems no congruent but can be added using likes: "$$comment.likes"

So this produce an array with only obbjects where there are more than 3 likes.

That's mean it can produce an empty subComments array. So the result of the $map is used into another $filter to get only object where subComments is not empty (i.e. there is at least one comment with more than 3 likes).

db.collection.find({},
{
  title: 1,
  content: 1,
  comments: {
    $filter: {
      input: {
        $map: {
          input: "$comments",
          as: "comment",
          in: {
            content: "$$comment.content",
            subComments: {
              $filter: {
                input: "$$comment.subComments",
                as: "subComment",
                cond: {
                  $gt: [
                    "$$subComment.likes",
                    3
                  ]
                }
              }
            }
          }
        }
      },
      cond: {
        $ne: [
          "$$this.subComments",
          []
        ]
      }
    }
  }
})

Example here.

Which is also the same to use $project in an aggregate query: example

  • Related