Updating nested array object with specific condition

const itemsSchema = new Schema({    
    name: String,
    checkedValue: String
});

const listSchema = new Schema({
    name: String,
    items: [itemsSchema]
});

Sample data:

[
  {
    _id: ObjectId("646ec7916f8ba817e80e3377"),
    name: "Home",
    items: [
      {
        name: "home 1",
        checkedValue: "Off",
        _id: ObjectId("646ec7966f8ba817e80e3380")
      },
      {
        name: "home 2",
        checkedValue: "Off",
        _id: ObjectId("646ec79a6f8ba817e80e338c")
      }
    ],
    __v: 2
  },
  {
    _id: ObjectId("646ed4136f8ba817e80e339b"),
    name: "School",
    items: [
      {
        name: "school 1",
        checkedValue: "Off",
        _id: ObjectId("646ed41c6f8ba817e80e33a4")
      }
    ],
    __v: 1
  }
]

If I only want to update checkedValue: “Off” of _id: ObjectId(“646ec79a6f8ba817e80e338c”) to checkedValue: “On”. How can I do it?

Hi @Md_Fahad_Rahman - Welcome to the community :wave:

Have you tried using the $[<identifier>] to see if it works for you?

Regards,
Jason

@Jason_Tran Thank you so much. I am trying to use this:

                List.collection.findOneAndUpdate({
                    name: listName
                  },
                  {
                    "$set": {
                      "items.$[i].checkedValue": "Off"
                    }
                  },
                  {
                    arrayFilters: [
                      {
                        "i._id": checkedItemId
                      }
                    ]
                  })

But the value is not changing.

Should I convert the text string to ObjectId before passing it to arrayFilters?

I’ve not yet tested this but can you try this on a test environment against more sample documents to see if it works for you?

db.collection.updateOne(  
  { 'items.checkedValue': 'Off' },
  { '$set': { 'items.$[element].checkedValue': 'On' } },
  {
    arrayFilters: [
      {
        'element._id': { '$eq': ObjectId("646ec79a6f8ba817e80e338c") }
      }
    ]
  })

You can alter it accordingly then test on a test environment to verify if it meets your requirement / use cases.

Regards,
Jason

@Jason_Tran Thank you for your kind effort. But, It is not working either. I think the problem is with the ObjectId. I am receiving the ObjectId through the following route:

            <form action="/delete" method="post">
                <div class="item">
                    <div class="item-p">
                        <input type="checkbox" name="checkbox" value="<%= item.checkedValue %>" onclick="this.form.submit(); checkedif();">
                        <input type="hidden" name="checkedItemId" value="<%= item._id %>"></input>
                        <p><%= item.name %></p>
                    </div>

                    <div><button type="submit" name="deleteIcon" value="<%= item._id %>"><i class="uil uil-trash-alt delete-icon"></i></button></div>
                </div>
                <input type="hidden" name="listName" value="<%= listTitle %>"></input>
            </form>

I am receiving the value through the hidden input which is essentially in String format. May be I need to convert it to an ObjectId before using it in the updateOne() method. I have tried something like this:

const { ObjectId } = require("mongodb");

app.post("/delete",function(req, res){//...............

const checkedItemId = req.body.checkedItemId;
//............
'element._id': { '$eq': ObjectId(checkedItemId) }
//..........
)}

But the string is not converting to an ObjectId.

@Jason_Tran Thank you so much. Your solution worked like a charm. I had to convert the _id to an ObjectId. This was done by:

    const checkedItemId = req.body.checkedItemId;
    const checkedItemObjectId = new mongoose.Types.ObjectId(checkedItemId);
1 Like

Nice one! Thanks for updating the post with those details too :slight_smile:

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.