MongoDB: How to append to a string in a deep nested array

Tags: , ,



I’m a hobbyist web programmer who just started learning MongoDB/Mongoose and I can’t seem to figure out how to append to a string located in a deep nested array. I am trying to append a string to the end of hours: String. Below is the Schema I’m working with:

const TestSchema = new Schema({
    userID: Number, 
    years: [
        {
            year: Number,
            months: [{
                month: Number,
                days: [{
                    day: Number,
                    hours: String
                }]
            }]
        }
    ]
});

Here is what I have so far. I tried to extend upon this answer here: https://stackoverflow.com/a/56589089 .But this is giving me a Cannot specify arrayFilters and a pipeline update error.

TestModel.findOneAndUpdate(
  { "years.months.days.day": 12 },
  [
    {
      $set: {
        "years.$[index1].months.$[index2].days.$[index3].hours": {
          $concat: [
            "$years.$[index1].months.$[index2].days.$[index3].hours",
            " 44:44:44"
          ]
        }
      }
    }
  ],
  {
    arrayFilters: [
      { "index1.year": 2020 },
      { "index2.month": 7 },
      { "index3.day": 12 }
    ]
  }
).catch(error => {
  console.log("error>>" + error);
});

Edit: Below is code with which I created an instance of the model

var test = new TestModel({
    userID: 5,
    years: [{
        year: 2020, 
        months: [{
            month: 7,
            days: [{
                day: 12,
                hours: "4:4:4 5:5:5"
            }]
        }]
    }]
})

test.save().then(function(){
    console .log("testSaved>>" + !test.isNew);
});

Here is a screenshot of the data in the db: enter image description here Any help would be greatly appreciated.

Answer

Update is not supporting both operation together “arrayFilters” and “aggregation pipeline”, you need to use only single operation from both,

So here you need to use only update aggregation pipeline, using nested $map,

TestModel.findOneAndUpdate({
    years: {
      $elemMatch: {
        year: 2020,
        months: {
          $elemMatch: {
            month: 7,
            days: { $elemMatch: { day: 12 } }
          }
        }
      }
    }
  },
  [{
    $set: {
      years: {
        $map: {
          input: "$years",
          as: "y",
          in: {
            $mergeObjects: [
              "$$y",
              {
                months: {
                  $map: {
                    input: "$$y.months",
                    as: "m",
                    in: {
                      $mergeObjects: [
                        "$$m",
                        {
                          days: {
                            $map: {
                              input: "$$m.days",
                              as: "d",
                              in: {
                                $mergeObjects: [
                                  "$$d",
                                  {
                                    hours: {
                                      $cond: {
                                        if: { 
                                          $and: [
                                            { $eq: ["$$y.year", 2020] },
                                            { $eq: ["$$m.month", 7] },
                                            { $eq: ["$$d.day", 12] }
                                          ] 
                                        },
                                        then: { $concat: ["$$d.hours", " 44:44:44"] },
                                        else: "$$d.hours"
                                      }
                                    }
                                  }
                                ]
                              }
                            }
                          }
                        }
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }]
)


Source: stackoverflow