Search code examples
javascriptdictionarygoogle-apps-scriptnestedkey

Why is my code behaving like I have duplicate keys in a dictionary despite using unique strings? Javascript / Appscript


I am trying to loop through a dictionary of customers and save energy usage data, but for some customers when I try to change the values in their usage dictionary it will also change a completely different customer's value. I have a nested dictionary with customer utility information, the top-level key being a unique internal ID.

I stripped my code down to a single loop, looping through the top-level keys and setting the same month's usage for all customers in the dictionary to be the value of the iterator. After that, as shown in the code sample below, I log the values for three customers. After that, I increment only one of those customer's usage, and log the values again. The console shows that two over the customer's have dictionaries that are tied together somehow, but I can't figure out why or how to solve this. I can't discern any pattern in the keys of the linked customers, either.


Structure of the nested dictionary:

CustDict = 
{"N0100000XXXXXX" = 
   {"name" = "XXXX"},
   {"address" = "XXXX"},
   {"meter_read_dates" = 
      {"2021-05-13" =
         {"usage" = "XXXX"}
      }
   }
}

Stripped down code I used to demonstrate what is happening as simply as possible (real ID values):

Logger.log(custDict["N01000009700816"]["meter_read_dates"]["2021-05-13"]["usage"])
Logger.log(custDict["N01000000419887"]["meter_read_dates"]["2021-05-13"]["usage"])
Logger.log(custDict["N01000012580668"]["meter_read_dates"]["2021-05-13"]["usage"])


custDict["N01000009700816"]["meter_read_dates"]["2021-05-13"]["usage"] = 
custDict["N01000009700816"]["meter_read_dates"]["2021-05-13"]["usage"] + 1

Logger.log(custDict["N01000009700816"]["meter_read_dates"]["2021-05-13"]["usage"])
Logger.log(custDict["N01000000419887"]["meter_read_dates"]["2021-05-13"]["usage"])
Logger.log(custDict["N01000012580668"]["meter_read_dates"]["2021-05-13"]["usage"])

Console Output:

11:54:56 AM Info    346.0
11:54:56 AM Info    346.0
11:54:56 AM Info    322.0
11:54:56 AM Info    347.0
11:54:56 AM Info    347.0
11:54:56 AM Info    322.0

Code used to create the CustDict dictionary:

stmtCR = conn.prepareStatement('SELECT cust_id, utility_account, cycle_id, read_cycle FROM customers')
results = stmtCR.executeQuery()
resultsMetaData = results.getMetaData()
numCols = resultsMetaData.getColumnCount();
results.last();
numRows = results.getRow();
i = 0
results.first()  
var custDict = {}

while (i < numRows) 
{
  custDict[results.getString(1)] = {}
  custDict[results.getString(1)]["id"] = results.getString(1)
  custDict[results.getString(1)]["utility_account"] = results.getString(2)
  custDict[results.getString(1)]["cycle_id"] = results.getString(3)
  custDict[results.getString(1)]["read_cycle"] = results.getString(4)
  results.next()
  i++;
}

for (i = 0; i < Object.keys(custDict).length; i++)
{
  tempCust = custDict[Object.keys(custDict)[i]]
  tempCycleId = tempCust["cycle_id"]
  tempReadCycle = tempCust["read_cycle"]
  tempCust["meter_read_dates"] = cycleIdShdDict[tempCycleId][tempReadCycle]
  custDict[Object.keys(custDict)[i]] = tempCust 
}

cycleIdShdDict is a seperate dictionary that contains a set of dates associated with each cycle_id and read_cycle


Solution

  • I suspect the problem is that Object.keys(custDict) is returning the keys in a different order at different places in the for loop. So you're getting the object from one key, and then assigning it to a different key.

    There's no need to assign back to custDict[Object.keys(custDict)[i]] since you're modifying the object in place, not a copy.

    But instead of looping through the keys, loop through the values and modify them.

    Object.values(custDict).forEach(tempCust => {
      let tempCycleId = tempCust["cycle_id"];
      let tempReadCycle = tempCust["read_cycle"];
      tempCust["meter_read_dates"] = cycleIdShdDict[tempCycleId][tempReadCycle];
    });