2

Exception in thread "main" com.mongodb.MongoWriteException: The array filter for identifier 'element' was not used in the update { $set: { leave_history: { leave_history.$[element].pl_used: 6, leave_history.$[element].cl_used: 6, leave_history.$[element].sl_used: 6 } } } at com.mongodb.client.internal.MongoCollectionImpl.executeSingleWriteRequest(MongoCollectionImpl.java:1060) at com.mongodb.client.internal.MongoCollectionImpl.executeUpdate(MongoCollectionImpl.java:1037) at com.mongodb.client.internal.MongoCollectionImpl.updateOne(MongoCollectionImpl.java:622) at MongoDBExample.displayempDocs(MongoDBExample.java:226) at MongoDBExample.main(MongoDBExample.java:253)

Consider the document

ali@MongoDB>db.employees.find({$and : [{empno:7839},{leave_history:{$exists:true}}]}).pretty()

{
        "_id" : ObjectId("5e907ad23997181dde06e8fc"),
        "empno" : 7839,
        "ename" : "KING",
        "mgrno" : 0,
        "hiredate" : "1990-05-09",
        "sal" : 100000,
        "deptno" : {
                "_id" : ObjectId("5e9065f53997181dde06e8f8")
        },
        "username" : "none",
        "password" : "none",
        "is_admin" : "N",
        "is_approver" : "Y",
        "is_manager" : "Y",
        "user_role" : "AP",
        "admin_approval_received" : "Y",
        "active" : "Y",
        "created_date" : "2020-04-10",
        "updated_date" : "2020-04-10",
        "application_usage_log" : [
                {
                        "logged_in_as" : "AP",
                        "log_in_date" : "2020-04-10"
                },
                {
                        "logged_in_as" : "EM",
                        "log_in_date" : ISODate("2020-04-16T07:28:11.959Z")
                }
        ],
        "leave_history" : [
                {
                        "calendar_year" : 2020,
                        "pl_used" : 1,
                        "cl_used" : 2,
                        "sl_used" : 0
                },
                {
                        "calendar_year" : 2021,
                        "pl_used" : 0,
                        "cl_used" : 0,
                        "sl_used" : 0
                }
        ]
}

I am trying to update the field [leave_history] that is an array of sub-documents containing four other fields. Specifically the fields pl_used,cl_used and sl_used need to be updated. The following snippet was used

//Update the leaves used for this employee.
        query = and(eq("empno",7839),exists("leave_history",true)); // parent document query 

        Bson update = new Document("$set",new Document("leave_history",new Document("leave_history.$[element].pl_used",6)
                .append("leave_history.$[element].cl_used", 6).append("leave_history.$[element].sl_used", 6)));


        UpdateOptions update_options = new UpdateOptions(); // setting the options for sub-document arrays.
        List<Bson> array_filters = new ArrayList<Bson>();   // array list of filters.
        Bson arrayElement = Filters.eq("element.calendar_year", year); //creating the array element 
        array_filters.add(arrayElement);                         // add the filter element to the list of array list filters. 
        update_options.arrayFilters(array_filters);              // add the filters to the updateOptions. 
        update_result = generic_collection.updateOne(query, update, update_options); // calling the update.

But that raises the exception stated above. What does the exception mean ? Is there another way to update multiple fields with an array of sub-documents ?.

Hello Joe, I have the query that is needed for the Mongo Shell. Here is what I am using

db.employees.updateOne({empno:7839},{$set: {"leave_history.$[elem].pl_used":6,"leave_history.$[elem].cl_used":6,"leave_history.$[elem].sl_used":6}},{arrayFilters:[{"elem.calendar_year":2020}]})

I run into a problem when I try to replicate this within a Java program.

4
  • Please tell which sub-document of the array you are trying to update? There are two sub-documents with values; "calendar_year" : 2021 and 2022. Or, is it you want to update both (i.e., all) the sub-documents? Commented Apr 18, 2020 at 2:57
  • The update will trigger based on the year argument that will be passed and therefore at any point in time the update will be fired for just one sub-document. In this case the year was set at 2020. Commented Apr 18, 2020 at 5:43
  • See the following post. It has question and answer to update a nested array with a condition. How to add a json in a nested array of a mongodb document using Spring?. The post's issue is multile levels of nesting, but the same principle applies in your case. Commented Apr 18, 2020 at 6:31
  • Thank you Prasad. This is helpful. I appreciate it. Commented Apr 18, 2020 at 10:30

1 Answer 1

5

The update operation that you are ultimately running appears to be:

db.collection.update({"empno":7839), "leave_history",{$exists:true}},
                     {"$set":{ "leave_history":{
                                    "leave_history.$[element].pl_used":6,
                                    "leave_history.$[element].cl_used":6,
                                    "leave_history.$[element].sl_used":6
                     }}},
                     {"arrayFilters":[{"element.calendar_year":year}]}
)

The problem is that the $set is attempting to replace the leave_history array with an object containing a leave_history object, so there is never an array element comparison.

You just need to remove one layer of document so that your update is:

db.collection.update({"empno":7839), "leave_history",{$exists:true}},
                     {"$set":{
                                    "leave_history.$[element].pl_used":6,
                                    "leave_history.$[element].cl_used":6,
                                    "leave_history.$[element].sl_used":6
                     }},
                     {"arrayFilters":[{"element.calendar_year":year}]}
)
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you Joe. I could follow your hint on the answer and create the update for the Java routine. This is what worked Bson update = new Document("$set",new Document("leave_history.$[element].pl_used",9) .append("leave_history.$[element].cl_used", 9).append("leave_history.$[element].sl_used", 9));

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.