Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Replace JSON value

ANSWERED

I wanted to ask how I am able to replace values in JSON files, without overriding the whole file and losing the rest of the property values. Because if I do it in the following way: 

json_color.hours = element.data.value;

fs.writeFileSync("colors.txt", json_color, "json");

I am always replacing the previous file and I only want to change one property value and keep the other remaining property values. 

 

 

Best Answer
0 Votes
1 BEST ANSWER

Accepted Solutions

I would write the file only on app unload, and also use CBOR format for speed purposes.

 

import { me } from "appbit";

me.onunload = () => { fs.writeFileSync("colors.txt", json_color, "cbor"); }

 

 

View best answer in original post

Best Answer
5 REPLIES 5

I would write the file only on app unload, and also use CBOR format for speed purposes.

 

import { me } from "appbit";

me.onunload = () => { fs.writeFileSync("colors.txt", json_color, "cbor"); }

 

 

Best Answer

For settings, which your example appears to be, then @JonFitbit response is certainly the best solution.

 

If you were collecting data, for example sensor data for later use, then take a look at writeSync, which is for binary file use. It does add a level of complexity, but also opens up reading or updating particular 'records' at will. Each record will be a fixed byte length. I was 'playing about' with writeSync yesterday and have working code if this route is of interest/use (read/write/update) @Senorts.

Best Answer

Thank's very much for the help.

Best Answer
0 Votes

As per your message @Senorts, here you are. Please remember this is test code to confirm functionality and usage of writeSync.

 

import * as fs from "fs";
let fh = 0;
let fileName="filename.bin";
// setup variables for updating the record
var sentBuffer = new ArrayBuffer(1);
var sentFlag   = new Uint8Array  ( sentBuffer,  0, 1 ); // 1 x 1 bytes
sentFlag[0]    = 1;

//setup variables for the record format
let recSize = 58;
var buffer = new ArrayBuffer(recSize);
var dtMillies   = new Uint32Array ( buffer,   0, 2 ); // 2 x 4 bytes
var gpsLat      = new Float64Array( buffer,   8, 1 ); // 1 x 8 bytes
var gpsLon      = new Float64Array( buffer,  16, 1 ); // 1 x 8 bytes
var gpsSpeed    = new Float64Array( buffer,  24, 1 ); // 1 x 8 bytes
var gpsAccuracy = new Float64Array( buffer,  32, 1 ); // 1 x 8 bytes
var gpsHeading  = new Uint16Array ( buffer,  40, 1 ); // 1 x 2 bytes
var heartRate   = new Uint16Array ( buffer,  42, 1 ); // 1 x 2 bytes
var steps       = new Uint16Array ( buffer,  44, 1 ); // 1 x 2 bytes
var altitude    = new Uint16Array ( buffer,  46, 1 ); // 1 x 2 bytes
var ascent      = new Uint16Array ( buffer,  48, 1 ); // 1 x 2 bytes
var descent     = new Uint16Array ( buffer,  50, 1 ); // 1 x 2 bytes
var reading     = new Uint32Array ( buffer,  52, 1 ); // 1 x 4 bytes
var battery     = new Uint8Array  ( buffer,  56, 1 ); // 1 x 1 bytes
var sent        = new Uint8Array  ( buffer,  57, 1 ); // 1 x 1 bytes

let myDate=Date.now()
let recCount=0;
let firstUnsent = 0;

writeRecord();
writeRecord();

showFileDetails();

firstUnsent = findFirstUnsent();
if (firstUnsent>0) {
  updateRecordAsSent(firstUnsent);
}

showRecordsToConsole();


function writeRecord() {
  fh = fs.openSync(fileName, 'a+');
  dtMillies[0]   = parseInt(myDate/100000000);
  dtMillies[1]   = myDate%100000000;
  gpsLat[0]      = 179.987654321
  gpsLon[0]      = -179.123456789
  gpsHeading[0]  = Math.floor(Math.random() * 360);
  gpsSpeed[0]    = 2.123456791
  heartRate[0]   = 120 + Math.floor(Math.random() * 80);
  gpsAccuracy[0] = 21.2134254723
  steps[0]       = Math.floor(Math.random() * 3);
  altitude[0]    = 10 + Math.floor(Math.random() * 1991);
  ascent[0]      = 4
  descent[0]     = 0
  battery[0]     = 78
  reading[0]     = 1
  sent[0]        = 0

  fs.writeSync(fh, buffer); // write the record
  fs.closeSync(fh); // and commit changes -- important if you are about to read from the file  
}

function showFileDetails() {
  let stats = fs.statSync(fileName);
  if (stats) {
    recCount=stats.size/recSize;
    console.log("File size: " + stats.size + " bytes");
    console.log("Number of Records: " + recCount);
    console.log("Last modified: " + stats.mtime);
  }  
}

function getNumberOfRecords() {
  recCount=0;
  let stats = fs.statSync(fileName);
  if (stats) {
    recCount=stats.size/recSize;    
  }
  return recCount;
}

function findFirstUnsent() {
  let retVal=0;
  fh = fs.openSync(fileName, 'a+');
  for (let i = 0; i < recCount; i++) { 
    fs.readSync(fh, buffer, 0, recSize, i*recSize );
    if ((sent[0]==0) && (retVal===0)) {
      retVal=i+1;
      i=recCount;
    }
  }
  fs.closeSync(fh);
  return retVal;  
}

function updateRecordAsSent(recordID) {
  fh = fs.openSync(fileName, 'a+');
  fs.writeSync(fh,sentBuffer,0,1,(recSize*recordID)-1);
  fs.closeSync(fh);
}

function showRecordsToConsole() {
  recCount=getNumberOfRecords();
  fh = fs.openSync(fileName, 'r+');
  for (let i = 0; i < recCount; i++) { 
      fs.readSync(fh, buffer, 0, recSize, i*recSize );
      console.log("Record: "+(i+1)+"  Millies:"+(dtMillies[0]*100000000+dtMillies[1])+" Lat:"+gpsLat[0]+" Lon:"+gpsLon[0]+" Heading:"+gpsHeading[0]+" Speed:"+gpsSpeed[0]+" HR:"+heartRate[0]+" Accuracy:"+gpsAccuracy[0]+" Steps:"+steps[0]+" Alt:"+altitude[0]+" Asc:"+ascent[0]+" Des:"+descent[0]+" Bat:"+battery[0]+" Reading:"+reading[0]+" Sent:"+sent[0]);      
  }
  fs.closeSync(fh); 
}


function packString(mystring) {
  let i=0;
  while (mystring.length<16) { mystring+=' '; }
  for (i = 0; i < mystring.length; i++) { 
    usernameView[i]=mystring.charCodeAt(i);
  } 
}
function unPackString(usernameView) {
  let retVal='';
  let i=0;
  for (i = 0; i < usernameView.length; i++) { 
    retVal+=String.fromCharCode(usernameView[i]);
  } 
  return retVal
}

 

Best Answer

one really interesting thing i found in using @SunsetRunner's code it looks like the Uint*Arrays need to be in a certain order to pack them into the ArrayBuffer as tightly as possible.  for example, i have two Uint*Arrays i'm passing to the buffer.  if i put the Uint32Array first, i can get the record size down to 9 bytes.  but if the Uint8Array is first, the record size has to be 16 bytes (almost twice as large).  otherwise, i get an error.  anyone know the logic behind this in the Fitbit SDK? does this have something to do with Endianness?  Here's my code sample:

 

allows for a record size of 9 bytes:

 

 

var buffer = new ArrayBuffer(recSize);
var attention = new Uint8Array(buffer, 8, 1);
var dtMillies = new Uint32Array(buffer, 0, 2);

 

 
requires a record size of 16 bytes:

 

var buffer = new ArrayBuffer(recSize);
var attention = new Uint8Array(buffer, 0, 1);
var dtMillies = new Uint32Array(buffer, 8, 2);

 

 
Best Answer
0 Votes