1

Im trying to set a value of a nested array object Schema:

courses: [
    {
      days: [
        {
          courseDate: {
            type: String,
          },
          attendance: {
            type: Boolean,
          },
          reason: {
            type: String,
          },
        },
      ],
      courseId: {
        type: String,
      },
      name: {
        type: String,
      },
      startTime: {
        type: String,
      },
      endTime: {
        type: String,
      },
    },
  ],

Here are my attemapts:

await Student.findOneAndUpdate(
      { "courses.days._id": "6117b0c45345db20f0dc3336" },
      { $set: { "courses.$.days.$.attendance": true } },
      { new: true }
    );

    await Student.findOneAndUpdate(
      { "courses.days._id": req.params.dayId },
      { "courses.$[courseIndex].days.$[dayIndex].attendance": true },
      {
        arrayFilters: [
          {
            courseIndex: req.params.courseId,
          },
          {
            dayIndex: req.params.dayId,
          },
        ],
      }
    );

Here is the document:

 "courses" : [ 
        {
            "_id" : ObjectId("6117b0c45345db20f0dc3330"),
            "courseId" : "61155838b1fff211dd9a8765",
            "name" : "succ",
            "startTime" : "20:20",
            "endTime" : "23:20",
            "days" : [ 
                {
                    "_id" : ObjectId("6117b0c45345db20f0dc3331"),
                    "courseDate" : "Wed Aug 04 2021 00:00:00 GMT+0300 (Israel Daylight Time)",
                    "attendance" : false,
                    "reason" : ""
                }, 
                {
                    "_id" : ObjectId("6117b0c45345db20f0dc3332"),
                    "courseDate" : "Wed Aug 11 2021 00:00:00 GMT+0300 (Israel Daylight Time)",
                    "attendance" : false,
                    "reason" : ""
                }, 
                {
                    "_id" : ObjectId("6117b0c45345db20f0dc3333"),
                    "courseDate" : "Wed Aug 18 2021 00:00:00 GMT+0300 (Israel Daylight Time)",
                    "attendance" : false,
                    "reason" : ""
                }, 
                {
                    "_id" : ObjectId("6117b0c45345db20f0dc3334"),
                    "courseDate" : "Wed Aug 25 2021 00:00:00 GMT+0300 (Israel Daylight Time)",
                    "attendance" : false,
                    "reason" : ""
                }
            ]
        }, 
        {
            "_id" : ObjectId("6117b0c45345db20f0dc3335"),
            "courseId" : "61155838b1fff211dd9a8765",
            "name" : "test",
            "startTime" : "13:40",
            "endTime" : "15:40",
            "days" : [ 
                {
                    "_id" : ObjectId("6117b0c45345db20f0dc3336"),
                    "courseDate" : "Thu Aug 05 2021 00:00:00 GMT+0300 (Israel Daylight Time)",
                    "attendance" : false,
                    "reason" : ""
                }, 
                {
                    "_id" : ObjectId("6117b0c45345db20f0dc3337"),
                    "courseDate" : "Thu Aug 12 2021 00:00:00 GMT+0300 (Israel Daylight Time)",
                    "attendance" : false,
                    "reason" : ""
                }, 
                {
                    "_id" : ObjectId("6117b0c45345db20f0dc3338"),
                    "courseDate" : "Thu Aug 19 2021 00:00:00 GMT+0300 (Israel Daylight Time)",
                    "attendance" : true,
                    "reason" : ""
                }, 
                {
                    "_id" : ObjectId("6117b0c45345db20f0dc3339"),
                    "courseDate" : "Thu Aug 26 2021 00:00:00 GMT+0300 (Israel Daylight Time)",
                    "attendance" : false,
                    "reason" : ""
                }
            ]
        }
    ],

The first one is throwing an Error:

Too many positional (i.e. '$') elements found in path 'courses.$.days.$.attendance'

The second one doesn't work... I don't really understand where is the issue in the second approach.

It finds the right doc but it doesn't update anything.

It's important to note that the position of every array is dynamic so the second approach is good as well.

4
  • Make sure to typecast req.params variables. By default, they are of type string. Commented Aug 15, 2021 at 13:09
  • Still doesnt work :( Commented Aug 15, 2021 at 13:19
  • typecast "courses.days._id": ObjectId(req.params.dayId). see my answer Commented Aug 15, 2021 at 13:20
  • Does this answer your question? arrayFilters in mongodb Commented Aug 15, 2021 at 13:46

1 Answer 1

0

The filtered positional operator $[] identifies the array elements that match the arrayFilters conditions for an update operation.

{ <update operator>: { "<array>.$[<identifier>]" : value } },
{ arrayFilters: [ { <identifier>: <condition> } ] }

In case identifier is an object, we can further query over that object in arrayFilters condition.

As arrayFilters are something related to mongodb, you need to cast id in mongoose with ObjectId

    await Student.findOneAndUpdate(
      { 
        "courses": { "$elemMatch": { "_id": ObjectId(req.params.courseId)} }, 
        "courses.days": { "$elemMatch": { "_id": ObjectId(req.params.dayId)} } 
      },
      { "courses.$[courseIndex].days.$[dayIndex].attendance": true },
      {
        arrayFilters: [
          {
            courseIndex._id: ObjectId(req.params.courseId),
          },
          {
            dayIndex._id: ObjectId(req.params.dayId),
          },
        ],
        new: true,
      }
    );

Edit:
You need to use new: true to get the updated value

Sign up to request clarification or add additional context in comments.

9 Comments

Gaurav Sharma its still doesnt work.... Just making sure. req.params.dayId and req.params.courseId are the id of each element. They are not the indexs
@DavidAxelrod Ohh.. I thought they are indexes of the array
Thank you so so much!!! i really appreciate it!!!! But could you please explain me why in the filter it written ._id ? and just courseIndex?
Hi @Gaurav Sharma i would like to upvote :) but im getting this message: Thanks for the feedback! You need at least 15 reputation to cast a vote, but your feedback has been recorded. Can I help in another way ?
Thanks @DavidAxelrod, We learn from each other. Just keep on contributing to the community. That's all I want :)
|

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.