Search code examples
javamongodbmongodb-java

Update field of a document inside an array of arrays in mongodb


I have a Document that has an array field called listsOfItems. Its contents are Documents and they all contain another array field called setOfItems, which is composed of Document.
So the structure is like listsOfItems(Array of Documents) > setOfItems(Array of Documents) > Items(Documents)

Each Document in listsOfItems has a listId field which is used to uniquely identify it's contents.
Each Document in setOfItems has a itemId field which is used to uniquely identify it's contents.

I want to change the value of a field inside a Document of setOfItems given the listId and itemId.
Currently, I'm trying to do it like this:

final var filter = Filters.and(Filters.eq("accessDetail.email", email),
                Filters.eq("listsOfItems.listId", listId),
                Filters.eq("listsOfItems.$.setOfItems.itemId", itemId));
final var updateQuery = Updates.set("listsOfItems.$.setOfItems.obtained", BsonBoolean.TRUE);

usersCollection.findOneAndUpdate(filter, updateQuery)  

The query doesn't match any Document
I cannot access the elements in the setOfItems by directly accessing them by index because they are ordered by other indexes and not according to their itemId field.

What is the right query for performing the update given the condition?

EDIT1
I have replaced my filter to:

 final var filter = Filters.and(Filters.eq("accessDetail.email", email),
                Filters.elemMatch("listsOfItems",
                        Filters.eq("listId", listId)),
                Filters.elemMatch("listsOfItems.setOfItems",
                        Filters.eq("itemId", itemId)));

Now I get the error message: 'Cannot create field 'obtained' with the correct sub-document that it should make changes in.
The issue boils down to the updateQuery.


Solution

  • To do this, you need to make use of arrayFilters.

    Document filter = new Document("base-doc-field","<value>");//query for base doc 
       //fields if any
    
    Document updateDoc = new Document("$inc",
         new Document("listOfItems.$[elem].setOfItems.$[elem1].fieldName","value to  
            update"));
    
    
     //prepare array filters.
      List<Bson> arrayFilters = new ArrayList<>();
      arrayFilters.add(new Document("elem.listId","<list_id>"));
      arrayFilters.add(new Document("elem1.itemId","<item_id>"));
    
     //prepare update options, and set these array filters to update options.
     UpdateOptions options = new UpdateOptions().
                      arrayFilters(filterArr).bypassDocumentValidation(true);
    
     //execute update method.
     collection.updateOne(filter,updateDoc,options);
    

    Visit https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#update-nested-arrays-in-conjunction-with