0

I tried to do basic things. I have an array that contains multiple objects. I want to add new key-value pair in every array object.

I tried this by following code.

exports.addBuyOption = (arr) => {
    var newArr=arr;
    return new Promise((resolve, reject) => {
        for (let i = 0; i < newArr.length; i++) {
            newArr[i].name="new name" //updating the existing key value
            newArr[i].canBuy=true //new key value 
        }

        setTimeout(() => {
            resolve(newArr);
        }, 2000)
    })
}

I added set timeout as I just wanted to confirm whether the promise returned after the loop operation or not. Also when code does not run with the origin array then I make a new variable with newArr name but the code also does not work.

exports.addBuyOption = (arr) => {
    return new Promise((resolve, reject) => {
        for (let i = 0; i < arr.length; i++) {
            arr[i].name="new name" //updating the existing key value
            arr[i].canBuy=true //new key value 
        }

            resolve(arr);
    })
}

With this code, I was able to update my existing key-value but was not able to add any new key value. What am I doing wrong? I tried to change the method of adding key from dot operator to array indexing to Object.assign but none of them worked for me.

halfer
  • 19,824
  • 17
  • 99
  • 186
Pranay kumar
  • 1,983
  • 4
  • 22
  • 51
  • 1
    Why the timeout and promise? Is this not just straight forward object manipulation? Also please post a [mcve] using the `[<>]` snippet editor – mplungjan Feb 21 '22 at 11:00
  • That code will definitely add the new property to the objects if updating the existing property works, unless those are very unusual objects that have had [`preventExtensions`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions) applied to them (in which case you *can't* add new properties). Please update your question with a [mcve] demonstrating the problem, ideally a **runnable** one using Stack Snippets (the `[<>]` toolbar button); [here's how to do one](https://meta.stackoverflow.com/questions/358992/). – T.J. Crowder Feb 21 '22 at 11:00
  • Side note: `newArr` is a misleading name for that variable. It **isn't** a new array, it's just another variable pointing at the same array `arr` does. There's no reason for that variable, you could just be using `arr`. If you actually wanted to make a copy of the array, you'd have to do that intentionally, and if you wanted to make a copy of the objects *in* the array, you'd have to do that too. – T.J. Crowder Feb 21 '22 at 11:03
  • Also, your question has nothing whatsoever to do with [tag:html]. – T.J. Crowder Feb 21 '22 at 11:05
  • *"I added set timeout as I just wanted to confirm whether the promise returned after the loop operation or not."* Without the timeout, there's no purpose whatsoever to that promise. – T.J. Crowder Feb 21 '22 at 11:07
  • Where does the array come from? – T.J. Crowder Feb 21 '22 at 11:09
  • The array comes from a database query which I passed as a parameter. – Pranay kumar Feb 21 '22 at 11:10
  • @Pranaykumar - "a database query" is quite vague. What kind of database? What library are you using to access it? But from your description, it sounds like unusual though it is, the library is indeed preventing extensions to the objects and you'll need to copy them. – T.J. Crowder Feb 21 '22 at 11:15

1 Answers1

1

With this code, I was able to update my existing key-value but was not able to add any new key value.

The only explanation for that would be that the objects in the array have had Object.preventExtensions applied to them. Here's an example:

function addBuyOption(arr) {
    for (let i = 0; i < arr.length; i++) {
        arr[i].name="new name" //updating the existing key value
        arr[i].canBuy=true //new key value 
    }
    return arr;
}

const arr = [
    {name: "old name 1"},
    {name: "old name 2"},
    {name: "old name 3"},
].map(Object.preventExtensions);
console.log("Before:");
console.log(JSON.stringify(arr, null, 4));
addBuyOption(arr);
console.log("After:");
console.log(JSON.stringify(arr, null, 4));
.as-console-wrapper {
    max-height: 100% !important;
}

(Note I did away with the promise, it doesn't do anything useful in this code.)

If that's what's going on, you can't add properties to the objects. But you can create a new array with copies of the objects with the new property:

function addBuyOption(arr) {
    return arr.map(obj => ({
        ...obj,           // Copy existing properties
        name: "new name", // Set new value for existing property
        canBuy: true,     // Set new property
    }));
}

const arr = [
    {id: 1, name: "old name 1"},
    {id: 2, name: "old name 2"},
    {id: 3, name: "old name 3"},
].map(Object.preventExtensions);
console.log("Before:");
console.log(JSON.stringify(arr, null, 4));
const newArr = addBuyOption(arr);
console.log("After:");
console.log(JSON.stringify(newArr, null, 4));
.as-console-wrapper {
    max-height: 100% !important;
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks. I checked some more answers and by using JSON stringify and parse method over the array, I was able to add a new key-value in the array. no problem in the code, it is actually mongoose that restricts the array to get updated(don't know why). – Pranay kumar Feb 21 '22 at 11:31
  • @Pranaykumar - *"...and by using JSON stringify and parse method over the array, I was able to add a new key-value in the array..."* You'll see people doing that, but my strongly recommendation is: **Don't.** `JSON.parse(JSON.stringify(x))` is lossy and slow, it's an awful way to copy things. There's no reason to make a round-trip through text. Instead, do what I've shown above (shallow copy is all you need for what you've described), or [do this](https://stackoverflow.com/questions/122102/) in rare cases where you need a deep copy. Happy coding! – T.J. Crowder Feb 21 '22 at 11:41