Issue with update 2nd level nested array element using spring boot mongotemplate

Viewed 1145

Question document

{
  "_id": ObjetId("5b91ce1d001902722e79539b")
  ...
  "questionDetail": {
   ...
    "answers": [
      {
        "srno": 10,
        ...
        "userMatchPairAnswerCounts": [
          {
            "anssrno": 8,
            "anscnt": 0
          },
          {
            "anssrno": 9,
            "anscnt": 0
          }
        ]
      },
      {
        "srno": 20,
        ...
        "userMatchPairAnswerCounts": [
          {
            "anssrno": 14,
            "anscnt": 0
          },
          {
            "anssrno": 15,
            "anscnt": 0
          },
          {
            "anssrno": 16,
            "anscnt": 0
          }
        ]
      }
      ...
}

Java classes

public class Question {
   private QuestionDetail  questionDetail;
   ...
}

public class QuestionDetail {
  private List<Answer> answers = new ArrayList<>();
  ...
}


public class Answer {
  private int srno;
  private List<UserMatchPairAnswerCount>  userMatchPairAnswerCounts; 
  ...  
}

public class UserMatchPairAnswerCount {
  private int anssrno;
  private long anscnt;
  ...
}

My code:

Query query = new Query( new Criteria().andOperator(Criteria.where("id").is(question.getId()), 
Criteria.where("questionDetail.answers").elemMatch(Criteria.where("srno").is(10))));

Update update = new Update().inc("questionDetail.answers.$[answer].userMatchPairAnswerCounts.$.anscnt", 1)
                .filterArray(new Criteria().andOperator(
                Criteria.where("answer.srno").is(10),                 
Criteria.where("answer.userMatchPairAnswerCounts").elemMatch(Criteria.where("anssrno").is(9))));
                
Question questionFound = mongoTemplate.findAndModify(query, update, Question.class);                        
                    

Above modifies the "anssrno": 8 (index 1 - which is same as selected 'answer' index )

Query query = new Query( new Criteria().andOperator(Criteria.where("id").is(question.getId()), 
Criteria.where("questionDetail.answers").elemMatch(Criteria.where("srno").is(20))));

Update update = new Update().inc("questionDetail.answers.$[answer].userMatchPairAnswerCounts.$.anscnt", 1)
                .filterArray(new Criteria().andOperator(
                Criteria.where("answer.srno").is(20),                     
    Criteria.where("answer.userMatchPairAnswerCounts").elemMatch(Criteria.where("anssrno").is(16))));
                
Question questionFound = mongoTemplate.findAndModify(query, update, Question.class);

Above modifies the "anssrno": 15 (index 2 - which is same as selected 'answer' index )

Looks like filterArray criteria

"answer.userMatchPairAnswerCounts").elemMatch(Criteria.where("anssrno").is(16))));

is not having any impact, instead it always updates/inserts(if no document at the required index) as per the index of the selected answer.

What am I doing wrong? Pls guide

Updates:

Direct command line works fine:

db.questions.update({
  "_id": ObjectId("5b91ce1d001902722e79539b"),
  "questionDetail.answers.srno": 10
},
{
  "$inc": {
    "questionDetail.answers.$[answer].userMatchPairAnswerCounts.$[userMtc].anscnt": 1
  }
},
{
  arrayFilters: [
    {
      "answer.srno": 10
    },
    {
      "userMtc.anssrno": 9
    }
  ]
})

My Spring Boot Version:2.4.0 MongoDB version: 4.2.3 Added the changes in my java code as suggested below. Getting below error

Caused by: com.mongodb.MongoCommandException: Command failed with error 9 (FailedToParse): 'Error parsing array filter :: caused by :: Expected a single top-level field name, found 'answer' and 'userMtc'' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "Error parsing array filter :: caused by :: Expected a single top-level field name, found 'answer' and 'userMtc'", "code": 9, "codeName": "FailedToParse"}

Adding a screenshot (Debug) - incase it helps My Debug Screen

1 Answers

Your usage for updating nested array is incorrect. Refactored code too.

Query query = new Query(Criteria.where("id").is(question.getId()).and("questionDetail.answers.srno").is(10));
Update update = new Update().inc("questionDetail.answers.$[answer].userMatchPairAnswerCounts.$[userMtc].anscnt", 1)
        .filterArray(Criteria.where("answer.srno").is(10))
        .filterArray(Criteria.where("userMtc.anssrno").is(9));
Question questionFound = mongoTemplate.findAndModify(query, update, Question.class);

Working example added - https://mongoplayground.net/p/n1skENr-yZQ

Related