Search code examples
mongodbmongo-java-drivermongodb-update

Exception in thread "main" com.mongodb.MongoWriteException: The array filter for identifier 'element' was not used in the update


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.


Solution

  • 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}]}
    )