JSON Problem with Keeping Data Saved

I have been using Rob Miracle’s code to save and load data with JSON.  The problem I run into is when changing scenes in composer or re running my program.  
 
What I have is some buttons that add some number values to a temporary table.  Then a submit button that loads the JSON table, then checks some conditions and either adds the temporary table to the table that holds the loaded JSON table, then the table is saved back into the JSON file.  
 
I can print the table in that scene and it recognizes the values, no problem.  Problems occur when, like I mentioned above, change scenes or reload the program.  
 
The JSON table looks like this:
When entering the data the first time - [{“1”:11,“2”:44,“3”:60,“date”:“140529”}]
When entering a second time - [{“1”:33,“2”:109,“3”:75,“date”:“140529”,“1”:11,“3”:60,“2”:44}]
 
As you can see it isn’t reading or saving the data correctly… and I’m not really sure where my problem is at.  Also, when printing the table after adding the second time it only recognizes the newly input data.  
 
If the explanation wasn’t clear enough, here is some relevant code where this is going down:
 

local function confirmHandler(event)     local buyinTable = t.loadTable("buyins.json")     tempTable.date = os.date("%y".."%m".."%d")     local function checkDate(table, date)         local match = false         local key          if table then              for i = 1, #table do                  if table[i].date == date then                      match = true                      key = i                  end              end          else             buyinTable = {}         end         if match == true then             return true, key          elseif match == false then              return false         end      end      condition, key = checkDate(buyinTable, tempTable.date)     print(condition, key)       if condition == true then          for i = 1, #tempTable do          --    table.insert( buyinTable[key], tempTable[i] )             buyinTable[key][#buyinTable[key]+1] = tempTable[i]         end          print(table.concat( tempTable, ", " ))         print("a "..table.concat( buyinTable[key], ", " ))     elseif condition == false then          table.insert(buyinTable, tempTable)         print(table.concat( tempTable, ", " ))         print("b "..table.concat( buyinTable[#buyinTable], ", " ).." date: "..buyinTable[#buyinTable].date)     end      t.saveTable(buyinTable, "buyins.json")     clearText()     composer.gotoScene("menu") end 

The confirmHandler function is called when the submit button is pressed.  

Thanks in advance, let me know if you need any further explanation.  

I don’t know if this is the issue or not, but “table” is a global variable that holds all the table functions.  In your function you are using a seemingly localized variable named table (that holds a table).   If you ever needed to access the table functions inside there, it wouldn’t work.  I would suggest giving a different name like “myTable”.

I would also consider using a table printing function like print_r()

function M.print\_r ( t )     local print\_r\_cache={}     local function sub\_print\_r(t,indent)         if (print\_r\_cache[tostring(t)]) then             print(indent.."\*"..tostring(t))         else             print\_r\_cache[tostring(t)]=true             if (type(t)=="table") then                 for pos,val in pairs(t) do                     if (type(val)=="table") then                         print(indent.."["..pos.."] =\> "..tostring(t).." {")                         sub\_print\_r(val,indent..string.rep(" ",string.len(pos)+8))                         print(indent..string.rep(" ",string.len(pos)+6).."}")                     elseif (type(val)=="string") then                         print(indent.."["..pos..'] =\> "'..val..'"')                     else                         print(indent.."["..pos.."] =\> "..tostring(val))                     end                 end             else                 print(indent..tostring(t))             end         end     end     if (type(t)=="table") then         print(tostring(t).." {")         sub\_print\_r(t,"  ")         print("}")     else         sub\_print\_r(t,"  ")     end     print() end

To print out the value of your tables as you are moving along.  It’s hard to follow your code since we can’t see where some of the other items like tempTable are being created.

Rob

Yeah, sorry, I was just trying to clutter it up as least as possible.  The table name didn’t work but I switched it anyways.  What is going on is the scene is started by creating a bunch of button widgets, each having a different number value, and also a confirm button, which calls the function posted initially.  The number value buttons have a button listener that inserts their value into the tempTable when pressed:

local function buttonHandler(event)     local id = event.target.id     table.insert( tempTable, id )   --  print(table.concat( tempTable, ", " ), tempTable.date)         if string.len(id) == 2 then              textX = textX + string.len(id)\*28             textY = 275 + row\*50     elseif string.len(id) == 3 then              textX = textX + string.len(id)\*26             textY = 275 + row\*50     elseif string.len(id) == 4 then              textX = textX + string.len(id)\*22             textY = 275 + row\*50     end      buyinText[#buyinText+1] = display.newText(" ", 0, 0, native.systemFont, 34)     buyinText[#buyinText].text = id..", "     buyinText[#buyinText].anchorX = 1     buyinText[#buyinText].x, buyinText[#buyinText].y = textX, textY     if textX \> 570 then          row = row + 1          textX = 310     end      if textY \> 926 then          for i = 1,#buttons do              buttons[i]:setEnabled(false)         end      end  end 

So their values get inserted into the tempTable when pressed, then when the confirm button is pressed, it checks if the dates match, if it does, then it inserts it into the table with the like date, or if not, inserts it into a new table.  

Here is the output of your table printing function when pressing 3 button values, then the confirm button (starting with an empty JSON table): 

2014-06-01 21:31:56.397 Corona Simulator[1182:507] tempTable: 

2014-06-01 21:31:56.398 Corona Simulator[1182:507] table: 0x7fb6c8cacef0 {

2014-06-01 21:31:56.398 Corona Simulator[1182:507]   [1] => 11

2014-06-01 21:31:56.399 Corona Simulator[1182:507]   [2] => 44

2014-06-01 21:31:56.399 Corona Simulator[1182:507]   [3] => 60

2014-06-01 21:31:56.399 Corona Simulator[1182:507]   [date] => “140601”

2014-06-01 21:31:56.400 Corona Simulator[1182:507] }

2014-06-01 21:31:56.400 Corona Simulator[1182:507] buyin/JSON table: 

2014-06-01 21:31:56.401 Corona Simulator[1182:507] table: 0x7fb6cd8560e0 {

2014-06-01 21:31:56.401 Corona Simulator[1182:507]   [1] => table: 0x7fb6cd8560e0 {

2014-06-01 21:31:56.402 Corona Simulator[1182:507]            [1] => 11

2014-06-01 21:31:56.402 Corona Simulator[1182:507]            [2] => 44

2014-06-01 21:31:56.402 Corona Simulator[1182:507]            [3] => 60

2014-06-01 21:31:56.402 Corona Simulator[1182:507]            [date] => “140601”

2014-06-01 21:31:56.403 Corona Simulator[1182:507]          }

2014-06-01 21:31:56.403 Corona Simulator[1182:507] }

 

 

Then, you are sent back to the menu but when going back to the input screen and inputting 3 more values:

2014-06-01 21:33:54.851 Corona Simulator[1182:507] tempTable: 

2014-06-01 21:33:54.852 Corona Simulator[1182:507] table: 0x7fb6cd813460 {

2014-06-01 21:33:54.852 Corona Simulator[1182:507]   [1] => 27.5

2014-06-01 21:33:54.852 Corona Simulator[1182:507]   [2] => 33

2014-06-01 21:33:54.853 Corona Simulator[1182:507]   [3] => 109

2014-06-01 21:33:54.853 Corona Simulator[1182:507]   [date] => “140601”

2014-06-01 21:33:54.854 Corona Simulator[1182:507] }

2014-06-01 21:33:54.854 Corona Simulator[1182:507] buyin/JSON table: 

2014-06-01 21:33:54.854 Corona Simulator[1182:507] table: 0x7fb6c8dd0230 {

2014-06-01 21:33:54.855 Corona Simulator[1182:507]   [1] => table: 0x7fb6c8dd0230 {

2014-06-01 21:33:54.855 Corona Simulator[1182:507]            [1] => 27.5

2014-06-01 21:33:54.855 Corona Simulator[1182:507]            [2] => 33

2014-06-01 21:33:54.856 Corona Simulator[1182:507]            [3] => 109

2014-06-01 21:33:54.856 Corona Simulator[1182:507]            [date] => “140601”

2014-06-01 21:33:54.856 Corona Simulator[1182:507]            [1] => 11

2014-06-01 21:33:54.857 Corona Simulator[1182:507]            [3] => 60

2014-06-01 21:33:54.857 Corona Simulator[1182:507]            [2] => 44

2014-06-01 21:33:54.857 Corona Simulator[1182:507]          }

2014-06-01 21:33:54.858 Corona Simulator[1182:507] }

 

And here is the output when redoing that and inputting 4 values twice:

 

2014-06-01 21:35:28.187 Corona Simulator[1182:507] tempTable: 

2014-06-01 21:35:28.188 Corona Simulator[1182:507] table: 0x7fb6c8dbc190 {

2014-06-01 21:35:28.188 Corona Simulator[1182:507]   [1] => 33

2014-06-01 21:35:28.189 Corona Simulator[1182:507]   [2] => 33

2014-06-01 21:35:28.189 Corona Simulator[1182:507]   [3] => 27.5

2014-06-01 21:35:28.189 Corona Simulator[1182:507]   [4] => 75

2014-06-01 21:35:28.189 Corona Simulator[1182:507]   [date] => “140601”

2014-06-01 21:35:28.190 Corona Simulator[1182:507] }

2014-06-01 21:35:28.190 Corona Simulator[1182:507] buyin/JSON table: 

2014-06-01 21:35:28.191 Corona Simulator[1182:507] table: 0x7fb6c8dc0dc0 {

2014-06-01 21:35:28.191 Corona Simulator[1182:507]   [1] => table: 0x7fb6c8dc0dc0 {

2014-06-01 21:35:28.191 Corona Simulator[1182:507]            [1] => 33

2014-06-01 21:35:28.192 Corona Simulator[1182:507]            [2] => 33

2014-06-01 21:35:28.192 Corona Simulator[1182:507]            [3] => 27.5

2014-06-01 21:35:28.192 Corona Simulator[1182:507]            [4] => 75

2014-06-01 21:35:28.193 Corona Simulator[1182:507]            [1] => 11

2014-06-01 21:35:28.193 Corona Simulator[1182:507]            [3] => 60

2014-06-01 21:35:28.193 Corona Simulator[1182:507]            [2] => 44

2014-06-01 21:35:28.193 Corona Simulator[1182:507]            [date] => “140601”

2014-06-01 21:35:28.194 Corona Simulator[1182:507]            [4] => 22

2014-06-01 21:35:28.194 Corona Simulator[1182:507]          }

2014-06-01 21:35:28.194 Corona Simulator[1182:507] }

 

I’m pretty confused right now but suspect it has something to do with inserting the tempTable into the buyinTable?

 

Thanks for your help.  

Can you type what your ideal table structure would look like?  Should the buyInTable have multiple records or just one record that gets updated?  If the dates are the same, should it update the existing record or add a new one?  I would think we need to understand your data needs before we can advise a course of action.

Rob

Alright so I think i’ve narrowed down where the problem is happening, but I still don’t know how to fix it.  I am pretty sure it is really not liking me mixing the array indexes with the date indexes.  

I tried to recreate a similar function from scratch so I could see when and where the problem was happening easier:

local function counterFunction() counter = counter + 1  t = loadTable("data.json") if t == nil then  t = {} end  table.insert( tempTable, counter ) if #tempTable \>= 3 then  tempTable.date = "Monday" print(type(tempTable.date)) table.insert( t, tempTable ) tempTable = {} print\_r(t) end  saveTable(t, "data.json") end 

Note that this is not part of the previous project I was working on, I created a new project to have a sort of blank canvas and the only thing in this project was the json save and load functions, a button widget, and the function shown that handles button events.  All this is doing is increasing the counter by one and adding it to the temp table each time the button is touched.  When the tempTable gets to 3 indexes, it, as well as the tempTable.date string to the main table to be saved/loaded by json.  

When the tempTable.date string was not being inserted, it was working fine, but when adding that in, the wheels started falling off as before.  

Here is what the json table in the json data file looks like after 9 button presses:

[{“date”:“Monday”,“1”:1,“3”:3,“2”:2},{“1”:4,“date”:“Monday”,“3”:6,“2”:5},{“1”:7,“2”:8,“3”:9,“date”:“Monday”}]

As you can see, the newest table added is fine, but it seems that once it gets loaded, something goes wrong.  Any idea why this would be happening?

Rob, sorry it wasn’t clear enough, but the buyin table should have multiple records, and records with the same date should get added to the same table.  

So if I have three entries, {1,2,3} and {4,5,6} have a date of 121212 and now entry {7,8,9} with a date of 060708 then the final product should look like buyinTable = {{1,2,3,4,5,6,[date]="121212,},{7,8,9,[date]=“060708”}}

Let me know if you need further explanation.  

You are right.  Mixing index “array” tables and “key-value” tables is problematic.  For instance the # operator only counts the numeric indexed items and it’s possible your key could get stuck in the middle.  What I would do is have a table that is indexed by the date:

dateTable = {}

dateTable[“Monday”] = {}

dateTable[“Monday”][1] = 5

dateTable[“Monday”][2] = 1

dateTable[“Monday”][3] = 8

dateTable[“Monday”][4] = 32

Then you can do: 

dateTable[“Monday”][#dateTable[“Monday”]+1] = some value

to append values to the end of the table.

Would that work for you?

Rob

Aha! Yeah that should work fine, thanks again for your help.  

I don’t know if this is the issue or not, but “table” is a global variable that holds all the table functions.  In your function you are using a seemingly localized variable named table (that holds a table).   If you ever needed to access the table functions inside there, it wouldn’t work.  I would suggest giving a different name like “myTable”.

I would also consider using a table printing function like print_r()

function M.print\_r ( t )     local print\_r\_cache={}     local function sub\_print\_r(t,indent)         if (print\_r\_cache[tostring(t)]) then             print(indent.."\*"..tostring(t))         else             print\_r\_cache[tostring(t)]=true             if (type(t)=="table") then                 for pos,val in pairs(t) do                     if (type(val)=="table") then                         print(indent.."["..pos.."] =\> "..tostring(t).." {")                         sub\_print\_r(val,indent..string.rep(" ",string.len(pos)+8))                         print(indent..string.rep(" ",string.len(pos)+6).."}")                     elseif (type(val)=="string") then                         print(indent.."["..pos..'] =\> "'..val..'"')                     else                         print(indent.."["..pos.."] =\> "..tostring(val))                     end                 end             else                 print(indent..tostring(t))             end         end     end     if (type(t)=="table") then         print(tostring(t).." {")         sub\_print\_r(t,"  ")         print("}")     else         sub\_print\_r(t,"  ")     end     print() end

To print out the value of your tables as you are moving along.  It’s hard to follow your code since we can’t see where some of the other items like tempTable are being created.

Rob

Yeah, sorry, I was just trying to clutter it up as least as possible.  The table name didn’t work but I switched it anyways.  What is going on is the scene is started by creating a bunch of button widgets, each having a different number value, and also a confirm button, which calls the function posted initially.  The number value buttons have a button listener that inserts their value into the tempTable when pressed:

local function buttonHandler(event)     local id = event.target.id     table.insert( tempTable, id )   --  print(table.concat( tempTable, ", " ), tempTable.date)         if string.len(id) == 2 then              textX = textX + string.len(id)\*28             textY = 275 + row\*50     elseif string.len(id) == 3 then              textX = textX + string.len(id)\*26             textY = 275 + row\*50     elseif string.len(id) == 4 then              textX = textX + string.len(id)\*22             textY = 275 + row\*50     end      buyinText[#buyinText+1] = display.newText(" ", 0, 0, native.systemFont, 34)     buyinText[#buyinText].text = id..", "     buyinText[#buyinText].anchorX = 1     buyinText[#buyinText].x, buyinText[#buyinText].y = textX, textY     if textX \> 570 then          row = row + 1          textX = 310     end      if textY \> 926 then          for i = 1,#buttons do              buttons[i]:setEnabled(false)         end      end  end 

So their values get inserted into the tempTable when pressed, then when the confirm button is pressed, it checks if the dates match, if it does, then it inserts it into the table with the like date, or if not, inserts it into a new table.  

Here is the output of your table printing function when pressing 3 button values, then the confirm button (starting with an empty JSON table): 

2014-06-01 21:31:56.397 Corona Simulator[1182:507] tempTable: 

2014-06-01 21:31:56.398 Corona Simulator[1182:507] table: 0x7fb6c8cacef0 {

2014-06-01 21:31:56.398 Corona Simulator[1182:507]   [1] => 11

2014-06-01 21:31:56.399 Corona Simulator[1182:507]   [2] => 44

2014-06-01 21:31:56.399 Corona Simulator[1182:507]   [3] => 60

2014-06-01 21:31:56.399 Corona Simulator[1182:507]   [date] => “140601”

2014-06-01 21:31:56.400 Corona Simulator[1182:507] }

2014-06-01 21:31:56.400 Corona Simulator[1182:507] buyin/JSON table: 

2014-06-01 21:31:56.401 Corona Simulator[1182:507] table: 0x7fb6cd8560e0 {

2014-06-01 21:31:56.401 Corona Simulator[1182:507]   [1] => table: 0x7fb6cd8560e0 {

2014-06-01 21:31:56.402 Corona Simulator[1182:507]            [1] => 11

2014-06-01 21:31:56.402 Corona Simulator[1182:507]            [2] => 44

2014-06-01 21:31:56.402 Corona Simulator[1182:507]            [3] => 60

2014-06-01 21:31:56.402 Corona Simulator[1182:507]            [date] => “140601”

2014-06-01 21:31:56.403 Corona Simulator[1182:507]          }

2014-06-01 21:31:56.403 Corona Simulator[1182:507] }

 

 

Then, you are sent back to the menu but when going back to the input screen and inputting 3 more values:

2014-06-01 21:33:54.851 Corona Simulator[1182:507] tempTable: 

2014-06-01 21:33:54.852 Corona Simulator[1182:507] table: 0x7fb6cd813460 {

2014-06-01 21:33:54.852 Corona Simulator[1182:507]   [1] => 27.5

2014-06-01 21:33:54.852 Corona Simulator[1182:507]   [2] => 33

2014-06-01 21:33:54.853 Corona Simulator[1182:507]   [3] => 109

2014-06-01 21:33:54.853 Corona Simulator[1182:507]   [date] => “140601”

2014-06-01 21:33:54.854 Corona Simulator[1182:507] }

2014-06-01 21:33:54.854 Corona Simulator[1182:507] buyin/JSON table: 

2014-06-01 21:33:54.854 Corona Simulator[1182:507] table: 0x7fb6c8dd0230 {

2014-06-01 21:33:54.855 Corona Simulator[1182:507]   [1] => table: 0x7fb6c8dd0230 {

2014-06-01 21:33:54.855 Corona Simulator[1182:507]            [1] => 27.5

2014-06-01 21:33:54.855 Corona Simulator[1182:507]            [2] => 33

2014-06-01 21:33:54.856 Corona Simulator[1182:507]            [3] => 109

2014-06-01 21:33:54.856 Corona Simulator[1182:507]            [date] => “140601”

2014-06-01 21:33:54.856 Corona Simulator[1182:507]            [1] => 11

2014-06-01 21:33:54.857 Corona Simulator[1182:507]            [3] => 60

2014-06-01 21:33:54.857 Corona Simulator[1182:507]            [2] => 44

2014-06-01 21:33:54.857 Corona Simulator[1182:507]          }

2014-06-01 21:33:54.858 Corona Simulator[1182:507] }

 

And here is the output when redoing that and inputting 4 values twice:

 

2014-06-01 21:35:28.187 Corona Simulator[1182:507] tempTable: 

2014-06-01 21:35:28.188 Corona Simulator[1182:507] table: 0x7fb6c8dbc190 {

2014-06-01 21:35:28.188 Corona Simulator[1182:507]   [1] => 33

2014-06-01 21:35:28.189 Corona Simulator[1182:507]   [2] => 33

2014-06-01 21:35:28.189 Corona Simulator[1182:507]   [3] => 27.5

2014-06-01 21:35:28.189 Corona Simulator[1182:507]   [4] => 75

2014-06-01 21:35:28.189 Corona Simulator[1182:507]   [date] => “140601”

2014-06-01 21:35:28.190 Corona Simulator[1182:507] }

2014-06-01 21:35:28.190 Corona Simulator[1182:507] buyin/JSON table: 

2014-06-01 21:35:28.191 Corona Simulator[1182:507] table: 0x7fb6c8dc0dc0 {

2014-06-01 21:35:28.191 Corona Simulator[1182:507]   [1] => table: 0x7fb6c8dc0dc0 {

2014-06-01 21:35:28.191 Corona Simulator[1182:507]            [1] => 33

2014-06-01 21:35:28.192 Corona Simulator[1182:507]            [2] => 33

2014-06-01 21:35:28.192 Corona Simulator[1182:507]            [3] => 27.5

2014-06-01 21:35:28.192 Corona Simulator[1182:507]            [4] => 75

2014-06-01 21:35:28.193 Corona Simulator[1182:507]            [1] => 11

2014-06-01 21:35:28.193 Corona Simulator[1182:507]            [3] => 60

2014-06-01 21:35:28.193 Corona Simulator[1182:507]            [2] => 44

2014-06-01 21:35:28.193 Corona Simulator[1182:507]            [date] => “140601”

2014-06-01 21:35:28.194 Corona Simulator[1182:507]            [4] => 22

2014-06-01 21:35:28.194 Corona Simulator[1182:507]          }

2014-06-01 21:35:28.194 Corona Simulator[1182:507] }

 

I’m pretty confused right now but suspect it has something to do with inserting the tempTable into the buyinTable?

 

Thanks for your help.  

Can you type what your ideal table structure would look like?  Should the buyInTable have multiple records or just one record that gets updated?  If the dates are the same, should it update the existing record or add a new one?  I would think we need to understand your data needs before we can advise a course of action.

Rob

Alright so I think i’ve narrowed down where the problem is happening, but I still don’t know how to fix it.  I am pretty sure it is really not liking me mixing the array indexes with the date indexes.  

I tried to recreate a similar function from scratch so I could see when and where the problem was happening easier:

local function counterFunction() counter = counter + 1  t = loadTable("data.json") if t == nil then  t = {} end  table.insert( tempTable, counter ) if #tempTable \>= 3 then  tempTable.date = "Monday" print(type(tempTable.date)) table.insert( t, tempTable ) tempTable = {} print\_r(t) end  saveTable(t, "data.json") end 

Note that this is not part of the previous project I was working on, I created a new project to have a sort of blank canvas and the only thing in this project was the json save and load functions, a button widget, and the function shown that handles button events.  All this is doing is increasing the counter by one and adding it to the temp table each time the button is touched.  When the tempTable gets to 3 indexes, it, as well as the tempTable.date string to the main table to be saved/loaded by json.  

When the tempTable.date string was not being inserted, it was working fine, but when adding that in, the wheels started falling off as before.  

Here is what the json table in the json data file looks like after 9 button presses:

[{“date”:“Monday”,“1”:1,“3”:3,“2”:2},{“1”:4,“date”:“Monday”,“3”:6,“2”:5},{“1”:7,“2”:8,“3”:9,“date”:“Monday”}]

As you can see, the newest table added is fine, but it seems that once it gets loaded, something goes wrong.  Any idea why this would be happening?

Rob, sorry it wasn’t clear enough, but the buyin table should have multiple records, and records with the same date should get added to the same table.  

So if I have three entries, {1,2,3} and {4,5,6} have a date of 121212 and now entry {7,8,9} with a date of 060708 then the final product should look like buyinTable = {{1,2,3,4,5,6,[date]="121212,},{7,8,9,[date]=“060708”}}

Let me know if you need further explanation.  

You are right.  Mixing index “array” tables and “key-value” tables is problematic.  For instance the # operator only counts the numeric indexed items and it’s possible your key could get stuck in the middle.  What I would do is have a table that is indexed by the date:

dateTable = {}

dateTable[“Monday”] = {}

dateTable[“Monday”][1] = 5

dateTable[“Monday”][2] = 1

dateTable[“Monday”][3] = 8

dateTable[“Monday”][4] = 32

Then you can do: 

dateTable[“Monday”][#dateTable[“Monday”]+1] = some value

to append values to the end of the table.

Would that work for you?

Rob

Aha! Yeah that should work fine, thanks again for your help.