1

I am using mongodb in springboot. And here is a part of my data:

{
  "topic": [
    {
      "_topicId": "5e5e4d4bb431502946c15342",
      "name": "testName0",
      "username": "test0",
      "date": 1583238474961,
      "reply": [
        {
          "_replyId": "38d29dcb-1a79-4788-b721-5fbe700cc99d",
          "username": "test0",
          "content": "reply0",
          "date": 1583240780072
        },
        {
          "_replyId": "07a0293a-22a1-45fb-9aa2-775fa24e9915",
          "username": "test1",
          "content": "reply1",
          "date": 1583240955561
        }
      ]
    },
    {
      "_topicId": "5e5e4d4bb431502946c15343",
      "name": "testName1",
      "username": "test1",
      "date": 1583238475241,
      "reply": []
    }
  ]
}

I have two problems:

(1) I try to pull a reply(a object of in java) from a topic, I try these queries:

Query query = Query.query(Criteria.where("_topicId").is(topicId));
Update update = new Update().pull("reply.$._replyId", topicReplyId);
mongoTemplate.updateFirst(query, update, "colletionName");

And I got a error The positional operator did not find the match needed from the query

Query query = Query.query(Criteria.where("_topicId").is(topicId));
Update update = new Update().pull("reply._replyId", topicReplyId);
mongoTemplate.updateFirst(query, update, "colletionName");

And I got a error Cannot use the part (_replyId) of (reply._replyId) to traverse the element

Then I decide to use the third way:

Query query = Query.query(Criteria.where("_topicId").is(topicId));
Update update = new Update().pull("reply", replyEntity);
mongoTemplate.updateFirst(query, update, "colletionName");

I try to new a ReplyEntity replyEntity, and I got my second problem:

(2) How can I get the subdocument from a document?

Query query = Query.query(Criteria.where("_topicId").is(topicId).and("reply._replyId").is(replyId));
TopicEntity t = mongoTemplate.findOne(query, TopicEntity.class, "colletionName");

I used the query but I get the outer-document(topic), include two reply on the example above of topic1. I just want the reply,how can make it? Thanks a lot.

5
  • The $pull update operator removes (or pulls from an array) the specified element. For example, you can pull the reply with the replyId = "07a0293a-22a1-45fb-9aa2-775fa24e9915". The resulting document will not have that particular sub-document element in the reply array. Is that what you want to achieve? Commented Mar 4, 2020 at 5:45
  • @prasad_ Thanks for you comment. Your comment is one part of what I want to achieve. I understand the pull operation ,but I can't use it correctly, which means I can't pull the reply with the replyId = "07a0293a-22a1-45fb-9aa2-775fa24e9915",my query and update are always wrong. Commented Mar 4, 2020 at 6:27
  • Okay, I will post some code, based on my comment. Commented Mar 4, 2020 at 6:28
  • 1
    For the question (2), on querying the specific element from a nested array (array within array) you have to use Aggregation query. The find method's positional projection operator $ doesn't work with more than one-level nesting. The aggregation $project (or addFields) stage and $filter operator can be used for the query. Commented Mar 4, 2020 at 7:01
  • I added the aggregation query for the question (2). Note that I didn't use the $filter approach, as the output needed to be just the reply sub-document. The query uses the $unwind and $match stages to get the specific sub-document in the nested array. Commented Mar 4, 2020 at 7:42

1 Answer 1

2

(1) Update (pull) reply array element:

This code will update the document; that is removes the specific element (sub-document) from the reply array:

// Query criteria for topic and reply
String topicId = "5e5e4d4bb431502946c15342";
String topicReplyId = "07a0293a-22a1-45fb-9aa2-775fa24e9915";

MongoOperations mongoTemplate = new MongoTemplate(MongoClients.create(), "test");
Query query = Query.query(Criteria
                               .where("topic._topicId").is(topicId)
                               .and("topic.reply._replyId").is(topicReplyId));
Update update = new Update().pull("topic.$.reply", new Document("_replyId", topicReplyId));
mongoTemplate.updateFirst(query, update, "topics"); // "topics" is the collection name



[ EDIT ADD ]

(2) Aggregation query to get the reply document:

db.topics.aggregate( [
  { $unwind: "$topic" },
  { $match: { "topic._topicId": topicId } },
  { $unwind: "$topic.reply" },
  { $match: { "topic.reply._replyId": topicReplyId } },
  { $project: { _id: 0, reply: "$topic.reply" } }
] ).pretty()

This returns:

{
        "reply" : {
                "_replyId" : "07a0293a-22a1-45fb-9aa2-775fa24e9915",
                "username" : "test1",
                "content" : "reply1",
                "date" : 1583240955561
        }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.