1

I'm trying to change an specific value in a nested key value structure, but when I set a value it changes all key's value.

Initial data is:

   const data = {
      "1.157685561": {
        "1222344": {
          "batb": [
            [0, 0],
            [0, 0],
            [0, 0]
          ],
          "batl": [
            [0, 0],
            [0, 0],
            [0, 0]
          ]
        },
        "1222345": {
          "batb": [
            [0, 0],
            [0, 0],
            [0, 0]
          ],
          "batl": [
            [0, 0],
            [0, 0],
            [0, 0]
          ]
        }
      }
    }

I want to change the value of an specific path

    data['1.157685561']['1222344']['batl'][0] = [1,2]

But the result is wrong. Because it changes:

  • data['1.157685561']['1222344']
  • data['1.157685561']['1222345']

Final result:

    {
      "1.157685561": {
        "1222344": {
          "batb": [
            [0, 0],
            [0, 0],
            [0, 0]
          ],
          "batl": [
            [1, 2],
            [0, 0],
            [0, 0]
          ]
        },
        "1222345": {
          "batb": [
            [0, 0],
            [0, 0],
            [0, 0]
          ],
          "batl": [
            [1, 2],
            [0, 0],
            [0, 0]
          ]
        }
      }
    }

Source code: https://playcode.io/301552?tabs=console&script.js&output

7
  • How would that occur? You must have some other code you're not showing us - that literally would not happen. Commented Apr 27, 2019 at 3:29
  • How did you generate that structure? Commented Apr 27, 2019 at 3:29
  • I guess that you are you didn't copied the object. So they keep the reference. Can you create a runnable snippet to show the problem? Commented Apr 27, 2019 at 3:30
  • I did add the source code Commented Apr 27, 2019 at 3:34
  • 1
    Check this line: for (const runner of runners) {data[runner] = marketData;}. Since marketData is an object, you are storing multiple references to the same object. That is a problem. Commented Apr 27, 2019 at 3:56

2 Answers 2

2

Check this section of the provided code:

function createEmptyMarketData(runners) {
    const data = {};
    const marketData = {
        batb: [
          [0, 0],
          [0, 0],
          [0, 0]
        ],
        batl: [
          [0, 0],
          [0, 0],
          [0, 0]
        ]
    };

    for (const runner of runners) {
        data[runner] = marketData;
    }

    return data;
}

Using for (const runner of runners) {data[runner] = marketData;} you are storing multiple references to the same object. That is a problem.

One possible solution is to change marketData to a method that generate a new object every time is called. Example:

function createEmptyMarketData(runners)
{
    const data = {};

    const marketData = () => ({
        batb: [[0, 0], [0, 0], [0, 0]],
        batl: [[0, 0], [0, 0], [0, 0]]
    });

    for (const runner of runners)
    {
        data[runner] = marketData();
    }

    return data;
}

New version: https://playcode.io/301583?tabs=console&script.js&output

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

Comments

1

Yeah, @Shidersz is right. I also checked because when I tried from the Node terminal, I couldn't see any issue as the object you have pasted in the problem is the one created by function (So it works fine).

> const data = {
...       "1.157685561": {
.....         "1222344": {
.......           "batb": [
.......             [0, 0],
.......             [0, 0],
.......             [0, 0]
.......           ],
.......           "batl": [
.......             [0, 0],
.......             [0, 0],
.......             [0, 0]
.......           ]
.......         },
.....         "1222345": {
.......           "batb": [
.......             [0, 0],
.......             [0, 0],
.......             [0, 0]
.......           ],
.......           "batl": [
.......             [0, 0],
.......             [0, 0],
.......             [0, 0]
.......           ]
.......         }
.....       }
...     }
undefined
> 
> data['1.157685561']['1222344']['batl'][0] = [1,2]
[ 1, 2 ]
> 
> data
{ '1.157685561':
   { '1222344': { batb: [Array], batl: [Array] },
     '1222345': { batb: [Array], batl: [Array] } } }
> 
> data['1.157685561']['1222344']['batl'][0]
[ 1, 2 ]
> 
> data['1.157685561']['1222345']['batl'][0]
[ 0, 0 ]
> 

I thought, what is happening then. Finally, I checked your code which is creating data. There you're referencing the same object for different keys.

So, updating a single one is like affecting others but internally they are just references to a same memory location where the real object is stored.

This What is the most efficient way to deep clone an object in JavaScript? would be really very very helpful for you to understand the concept of Deep & Shallow copy of variables.

Finally you can check the updated code at https://playcode.io/301586?tabs=console&script.js&output. I have just copied the outer marketData and placed inside for loop.

That is it. Thank you v. much.

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.