Search code examples
javascriptmongodbmongoosefindoneandupdate

Mongoose update nested object in array of record


I am currently having a problem where I am trying to update an of a nested array in a Mongoose record.My schema is as follows:

const customerSchema = new mongoose.Schema({
    kimCustomerId: {
      type: Number,
      required: true
    },      
    addresses: [
      {        
        created: Date,
        updated: Date,                     
        addressInfo: {
          type: { type: String },
          typeOfAddress: String,
          careOf: String,
          address: String,
          addressRow1: String,
          addressRow2: String,
          zipcode: String,
          city: String,
          countryCode: String,
          physicalAddressType: String,
          validFrom: Date,
          validTo: Date
        }
      }
    ],
.....

As you can see, the adrress array for each record holds many addresses. I want to be able to pass through an update object and update the properties inside the addressInfo nested object inside a particular array object. Here is my query as it stands:

const updated = await db.models.customers.findOneAndUpdate(
    {
      _id: customer._id,
      'addresses.addressId': addressData.addressId
    },
    { $set: { 'addresses.$': addressData } },
    { new: true }
  );

and an example of an object I pass through to update a record:

{
    addressId: officialAddressExists.addressId,
    addressInfo: {
      validTo: new Date().toISOString()
    }
 }

What I want to happen is, when I pass this object to the schema method, I want to select the correct address by the values 'kimCustomerId' and 'addressId' (which I have working fine) then only update the values of the 'addressInfo' nested object that I have passed and keep the ones not passed as they are, in this case the 'validTo' field but it can be any number of them updated. It is overwriting the whole 'addressInfo' nestedObject at the moment so I presume I have to do some kind of set operation on that nested object as well but I am unsure how. Is anyone able to point me in the right direction here? Thanks!


Solution

  • There is no straight way to do this in query, you can do it in your client side, something like,

    // Sample body request
    let addressData = {
        addressId: 1,
        addressInfo: {
          validTo: new Date().toISOString(),
          typeOfAddress: "Home",
          address: "ABC"
        }
    };
    
    let set = {};
    for (let key in addressData.addressInfo) {
        set["addresses.$.addressInfo." + key] = addressData.addressInfo[key];
    }
    console.log(set);

    Pass set variable in to your query,

    const updated = await db.models.customers.findOneAndUpdate(
        {
          _id: customer._id,
          'addresses.addressId': addressData.addressId
        },
        { $set: set },
        { new: true }
    );