spring-bootmongotemplatecriteriaquery

I want to update values ​in an array in an array while using MongoTemplate


First, I will show the state stored in mongodb.

enter image description here

As you can see, it is a structure with a list called replies in a list called comments. And inside replies there is an array called likes.

comments : [
    Object1 : {
        replies : [ 
            likes : [
                0 : {},
                1 : {}
            ]
        ]
    },
    Object2 : {
        replies : [
            likes : [
                0 : {},
                1 : {}
            ]
        ]
    }
]

What I want to do here is to insert/subtract a value only from the likes array inside a specific replies structure. I'm currently using Spring boot and have tried the following:

        Query query = new Query();
        Criteria criteria = Criteria.where("_id").is(new ObjectId(postId))
                .andOperator(Criteria.where("comments")
                                .elemMatch(Criteria.where("_id").is(new ObjectId(commentId))
                                        .andOperator(Criteria.where("replies")
                                                .elemMatch(Criteria.where("_id").is(new ObjectId(replyId)))
                                        )
                                )
                );

        query.addCriteria(criteria);

        Update update = new Update();
        if (state) {
            // remove user id 
            update.pull("comments.$[].replies.$.likes", new ObjectId(userId));
        } else {
            // add user id 
            update.push("comments.$[].replies.$.likes").value(new ObjectId(userId));
        }
        mongoTemplate.updateFirst(query, update, MyEntity.class);

It is an operation to add or remove userId according to boolean state. As a result of the attempt, up to a specific comment is found, but userId is unconditionally entered in the first likes list of the replies list inside the comment. What I want is to get into the likes list inside a specific reply. Am I using the wrong parameter in update.push()? I would appreciate it if you could tell me how to solve it.


Solution

  • Not a direct answer to your question as I'm not experienced with spring's criteria builder, but here's how you would do it in mongo directly, which might help you to figure it out:

    You could define arrayfilters allowing you to keep track of the corresponding indices of each comments and replies. You can then use those indices to push a new object at the exact matching indices:

    db.collection.update({
      _id: "<postId>"
    },
    {
      $push: {
        "comments.$[comments].replies.$[replies].likes": {
          _id: "newlyInsertedLikeId"
        }
      }
    },
    {
      arrayFilters: [
        {
          "comments._id": "<commentId>"
        },
        {
          "replies._id": "<replyId>"
        }
      ]
    })
    

    Here's an example on mongoplayground: https://mongoplayground.net/p/eNdDXXlyi2X