Skip to content
Advertisement

Get access to the “current element” when traversing a mongoDB (mongoose) array

I have a mongoose model for a “social media like post” (called PostModel) that has this schema:

{
  caption: String,
  comments: [
    {
      comment: String,
      // basically an array to store all those who liked the comment
      likedBy: [...] // array of references to a different model
    },
    ... // more comment objects like this
  ]
}

I simply want to know the number of likes each comment got when querying for a post. This should not be as annoying and difficult as it is. I have spent more than 4 hours on this.

What I have tried so far:

Attempt 1:

PostModel.findById(postId, {
  "comments.likes": { $size: "$comment.likedBy" } // gives the number of comments instead of the number of likes on the comment
})

Attempt 2:

PostModel.findById(postId, {
  "comments.likes": { $size: "$likedBy" } // gives "likedBy not defined" error
})

Attempt 3:

PostModel.findById(postId, {
  "comments.likes": { $size: "$comments.$likedBy" } // gives "FieldPath field names may not start with '$'. Consider using $getField or $setField" error
})

Attempt 4:

PostModel.findById(postId, {
  "comments.likes": { $size: "$comments.$.likedBy" } // gives "FieldPath field names may not start with '$'. Consider using $getField or $setField" error
})

I basically want to access the “current element” in this “forEach” like array traversal. For example:

const a = [{likes: ["x", "y"]}, {likes: ["a", "b"]}, {likes: []}];
a.forEach((element, index) => {
  console.log(element.likes.length) // this is what I want but for mongoDB
})
// output: 2 2 0

I have looked everywhere but could not find a solution even after searching for 4 hours. Anything that would point me even remotely near the current direction would be helpful.

I do not want to load the entire comments array into memory just to get the lengths of the nested likedBy arrays. Otherwise this would not even be a problem.

Advertisement

Answer

In case you want to get total number of likes from all comments you can use $reduce operator:

{
    $project: {
        likes: {
            $reduce: {
                input: "$comments",
                initialValue: 0,
                in: { $add: [ "$$value", { $size: "$$this.likedBy" } ] }
            }
        }
    }
}

Mongo Playground

Alternatively you may need $map to enrich each comment with a number of likes:

{
    $project: {
        comments: {
            $map: {
                input: "$comments",
                in: {
                    $mergeObjects: [
                        "$$this",
                        { $numberOfLikes: { $size: "$$this.likedBy" } }
                    ]
                }
            }
        }
    }
}

Mongo Playground

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement