bassman21
bassman21

Reputation: 390

Is there a smart way to modify an array within an object by using JavaScript's destructuring approach?

The following example demonstrates what I would like to achieve:

const data_template = {
  key: 1,
  data_object: {
    data1: 1,
    data2: 2,
    data3: 3
  },
  data_array: [
    { key: 1, data1: 1 },
    { key: 2, data1: 2 },
    { key: 3, data1: 3 }
  ]
}

let data = [];

data.push({ ...data_template, key: 1 });
data.push({ ...data_template, key: 2 });

console.log(data);

By using destructuring I can easily modify my "template object" (data_template) while adding instances of it to my "data array". The result of the code above is:

[
  {
    key: 1,
    data_object: { data1: 1, data2: 2, data3: 3 },
    data_array: [ [Object], [Object], [Object] ]
  },
  {
    key: 2,
    data_object: { data1: 1, data2: 2, data3: 3 },
    data_array: [ [Object], [Object], [Object] ]
  }
]

As you can see, there are 2 objects in my array (data), each with a unique key (1 and 2, respectively).

Now my question: How can I modify the keys within data_array, which is an array within my "data template"? Is there a smart way to do this by destructuring as well?

Upvotes: 3

Views: 716

Answers (2)

Webber
Webber

Reputation: 5514

The short answer

No, you cant.

JavaScript destructuring only allows you to override root level keys of an object, which replaces their value.

(You also usually wouldn't do this, to keep cognitive complexity low.)

The long answer

There are actually better ways to do this.

Usually when creating a new object by spreading becomes more complex, you'd simply create a function for each level of nesting, and give it a better name than I did, that correlates to your domain.

This is exactly what functions are made for; to split pieces of code to reduce complexity.

Simple example

function createDataEntry(key, data) {
  return { key, data }
}

function createRecord(key, data) {
  return {
    key,
    dataObject: {
      data,
    },
    dataArray: [
      createDataEntry(key, data),
      // or simply:
      // { key, data },
    ]
  }
}

let data = [];

data.push(createRecord(1, 'foo'));
data.push(createRecord(2, 'bar'));

console.log(JSON.stringify(data, null, 2));

produces

[
  {
    "key": 1,
    "dataObject": {
      "data": "foo"
    },
    "dataArray": [
      {
        "key": 1,
        "data": "foo"
      }
    ]
  },
  {
    "key": 2,
    "dataObject": {
      "data": "bar"
    },
    "dataArray": [
      {
        "key": 2,
        "data": "bar"
      }
    ]
  }
]

Add + Edit example

If you want to add or edit an entry from that data array, you'll have to do a check to see if an entry already exists.

If it already exists, update it using map.

If it does not exist, use array.push().

function addOrUpdateEntry(myObject, key, data) {
  let updated = false;

  const updatedObject = {
    ...myObject,
    items: myObject.items.map(member => {
      if (member.key === key) {
        updated = true;
        return { ...member, data };
      }

      return member;
    })
  };

  if (!updated) {
    updatedObject.items.push({ key, data });
  }

  return updatedObject;
}

let data = {
  items: []
};

data = addOrUpdateEntry(data, 1, "foo");
data = addOrUpdateEntry(data, 2, "bar");
data = addOrUpdateEntry(data, 2, "baz");

console.log(JSON.stringify(data, null, 2));

Which will output

{
  "items": [
    {
      "key": 1,
      "data": "foo"
    },
    {
      "key": 2,
      "data": "baz"
    }
  ]
}

Note that mutating an existing object can easily make for undesired behaviour in JavaScript, hence the creation of a new object and returning that from the function.

This concept is called immutability.

Upvotes: 0

Kelvin Schoofs
Kelvin Schoofs

Reputation: 8718

Depends on what you're trying to do.

If you simply want to clone the array with extra elements:

data.push({
    ...data_template,
    key: 1,
    data_array: [
        ...data_template.data_array,
        { key: 4, data1: 4},
    ],
});

If you want to e.g. add a new field to all the objects inside data_array:

const data_template = {
    key: 1,
    data_object: { data1: 1, data2: 2, data3: 3 },
    data_array: [ { key: 1, data1: 1 }, { key: 2, data1: 2 }, { key: 3, data1: 3 }]
}

console.log({
    ...data_template,
    key: 1,
    data_array: data_template.data_array.map(d => ({ ...d, newField: 123 })),
});
which you could also use to overwrite the key field

Otherwise I can't immediately think of any other destructuring "tricks" you could use.

Upvotes: 1

Related Questions