1

What is the best way to overwrite an object inside an array of objects?

I would like to have only one object per username, in this case in the initial arr Francis has a showMessage to true but userDetails has the same username but different value for the showMessage so I would like to overwrite this last object in the array.

Expected output:

[
  { showMessage: true, username: 'Joe' },
  { showMessage: true, username: 'Douglas' },
  { showMessage: false, username: 'Francis' }
]

Current code:

let obj = {};
let arr = [
{showMessage: true, username: "Joe"}, 
{showMessage: true, username: "Douglas"}, 
{showMessage: true, username: "Francis"}  
]

const userDetails = {
  showMessage: false,
  username: 'Francis',
}
objJSON = userDetails

var newData = [...arr, userDetails] 
console.log("newData: ",newData);

1
  • Unless you have some map from username to array index, you need to find the index of the object with username: "Francis" in the array and then update it. Commented May 18, 2022 at 17:11

5 Answers 5

1

Use Object.assign after finding in array the object which matches the username — in order to overwrite/modify the object data with another Object of data

const arr = [
  {showMessage: true, username: "Joe"}, 
  {showMessage: true, username: "Douglas"}, 
  {showMessage: true, username: "Francis"}  
]

const userDetails = {
  showMessage: false,
  username: 'Francis',
};

// Update user data by username (if object is found in array):
const oldDetails = arr.find(user => user.username === userDetails.username);
oldDetails && Object.assign(oldDetails, userDetails);

console.log(arr);

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

Comments

1

I would typically find the index with that username, if it exists, splice the new object into that position, if not, splice the new object onto the end

let arr = [
    {showMessage: true, username: "Joe"}, 
    {showMessage: true, username: "Douglas"}, 
    {showMessage: true, username: "Francis"}  
]

const userDetails = {
  showMessage: false,
  username: 'Francis',
}

const set = (obj) => {
    const i = arr.findIndex(el => el.username === obj.username);
    arr.splice(i === -1 ? arr.length : i, i === -1 ? 0 : 1, obj);
    return arr;
}

var newData = set(userDetails)
console.log("newData: ",newData);

Which works both for adding a new object, and editing an existing

However, I'd generally avoid the issue entirely by using the username as a key, instead of an array:

let arr = {
    Joe: {showMessage: true, username: "Joe"}, 
    Douglas: {showMessage: true, username: "Douglas"}, 
    Francis: {showMessage: true, username: "Francis"}  
}

const userDetails = {
  showMessage: false,
  username: 'Francis',
}

const set = (obj) => {
   arr[obj.username] = obj
}

set(userDetails)
console.log("newData: ", Object.values(arr));

Comments

0

let arr = [
  { showMessage: true, username: "Joe" },
  { showMessage: true, username: "Douglas" },
  { showMessage: true, username: "Francis" },
];

const userDetails = {
  showMessage: false,
  username: "Francis",
};

const newData = [...arr];

for (let i = 0; i < newData.length; i++) {
    if (arr[i].username == userDetails.username) {
        newData[i] = userDetails;
    }
}

console.log("newData: ", newData);

Comments

0

Just map through the object and reassign the value with the desired one.

let obj = {};
let arr = [
{showMessage: true, username: "Joe"}, 
{showMessage: true, username: "Douglas"}, 
{showMessage: true, username: "Francis"}  
]

const userDetails = {
  showMessage: false,
  username: 'Francis',
}

arr.map((user) => {
  if(user.username === userDetails.username){
      user.showMessage = userDetails.showMessage
  }
})

var newData = [...arr] 
console.log("newData: ",newData);

Comments

0

We can separate out the match-testing from the object merging by writing a generic version that takes a predicate. Here's a version that does this in an immutable manner:

const mergeWhere = (pred) => (objs, obj) => 
  objs .map (o => pred (obj, o) ? Object .assign ({}, o, obj) : o)

const updateUser = mergeWhere ((a, b) => a.username == b.username)


const arr = [{showMessage: true, username: "Joe"}, {showMessage: true, username: "Douglas"}, {showMessage: true, username: "Francis"}]
const userDetails = {showMessage: false, username: 'Francis'}


console .log (updateUser (arr, userDetails))
.as-console-wrapper {max-height: 100% !important; top: 0}

This merges our output into all matching inputs. We could do it for just the first one with something like

const mergeWhere = (pred) => (objs, obj, index = objs .findIndex (o => pred (obj, o))) =>
  index == -1
    ? [...objs]
    : [...objs .slice (0, index), Object .assign ({}, objs [index], obj) , objs .slice (index + 1)]

Comments

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.