Split payload from JSON String

Viewed 618

I receive these huge Strings via WebSocket:

[
  "BTC-31DEC21-100000-P",
  "{\"data\":{\"bids\":{\"0.01\":{\"price\":0.01,\"volume\":66.2,\"exchange\":\"DER\"},\"5.0E-4\":{\"price\":5.0E-4,\"volume\":1.1,\"exchange\":\"DER\"},\"0.637\":{\"price\":0.637,\"volume\":8.4,\"exchange\":\"DER\"}},\"asks\":{\"0.664\":{\"price\":0.664,\"volume\":8.4,\"exchange\":\"DER\"}}},\"isMasterFrame\":true}"
]

or

[
  "BTC-31DEC21-36000-C",
  "{\"data\":[{\"price\":0.422,\"volume\":8.4,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.423,\"volume\":0.0,\"exchange\":\"DER\",\"side\":\"ASKS\"}],\"isMasterFrame\":false}"
]

or

[
  "BTC-31DEC21-60000-P",
  "{\"data\":[{\"price\":0.105,\"volume\":0.0,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.1055,\"volume\":28.7,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.106,\"volume\":7.6,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.1065,\"volume\":43.0,\"exchange\":\"DER\",\"side\":\"ASKS\"}],\"isMasterFrame\":false}"
]

I want to check for isMasterFrame

let payload = JSON.parse(messageString[1]);

if (payload.hasOwnProperty("isMasterFrame")) {
 for (let i = 0; i < payload.pairs.length; i++) {
   let currentPair = payload.data[i]
      currentPair = currentPair.replace(/\0/g, ''); //Remove null chars
       if (currentPair.toUpperCase() != 'KILL') {
           props.onAddAvailablePair(currentPair);
        }
       }
      } else {
             // print some output with payload which holds "isMasterFrame":false
     }

When I run the code I get error:

TypeError: Cannot read properties of undefined (reading 'length')

Data from one inner pair: {\"price\":0.423,\"volume\":0.0,\"exchange\":\"DER\",\"side\":\"ASKS\"} should be split and inserted into the loop one by one

Do you know how I can fix this issue?

6 Answers

Problem

You don't have property pairs inside payload object, so you can not access its length.

Solution

You should iterate over data property. Since data property is also object, you can use Object.keys() function and iterate over its sub-properties.

let payload = JSON.parse(messageString[1]);

if (payload.hasOwnProperty("isMasterFrame")) {
  for (let i = 0; i < Object.keys(payload.data).length; i++) {
    let current_property= payload.data[Object.keys(payload.data)[i]];
    console.log(current_property);
    ...

Your data has different structure when isMasterFrame is different. You have Object of bids and asks in data when isMasterFrame is true while it is an array when isMasterFrame is false.

const data1 = [
    "BTC-31DEC21-100000-P",
    "{\"data\":{\"bids\":{\"0.01\":{\"price\":0.01,\"volume\":66.2,\"exchange\":\"DER\"},\"5.0E-4\":{\"price\":5.0E-4,\"volume\":1.1,\"exchange\":\"DER\"},\"0.637\":{\"price\":0.637,\"volume\":8.4,\"exchange\":\"DER\"}},\"asks\":{\"0.664\":{\"price\":0.664,\"volume\":8.4,\"exchange\":\"DER\"}}},\"isMasterFrame\":true}"
  ],
  data2 = [
    "BTC-31DEC21-36000-C",
    "{\"data\":[{\"price\":0.422,\"volume\":8.4,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.423,\"volume\":0.0,\"exchange\":\"DER\",\"side\":\"ASKS\"}],\"isMasterFrame\":false}"
  ]
data3 = [
  "BTC-31DEC21-60000-P",
  "{\"data\":[{\"price\":0.105,\"volume\":0.0,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.1055,\"volume\":28.7,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.106,\"volume\":7.6,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.1065,\"volume\":43.0,\"exchange\":\"DER\",\"side\":\"ASKS\"}],\"isMasterFrame\":false}"
];

const formatData = (data) => {
  return data.reduce((r, o) => {
      Object.entries(o).forEach(([k,v]) => {
        r[k] ??= [];
        r[k].push(v);
      });
      return r;
    }, {})
}

[data1, data2, data3].forEach(data => {
  const o = JSON.parse(data[1]);
  if(o.isMasterFrame) {
    const result = formatData(Object.values(o.data.bids));
    console.log(result);
  } else {
    const result = formatData(o.data);
    console.log(result);
  }
});

You can run the code snippet below to see it in operation. I have also attached a screenshot of a console showing the output of values.

// THIS IS AN ARRAY CONTAINING A JSON
var messageString = [
  "BTC-31DEC21-100000-P",
  "{\"data\":{\"bids\":{\"0.01\":{\"price\":0.01,\"volume\":66.2,\"exchange\":\"DER\"},\"5.0E-4\":{\"price\":5.0E-4,\"volume\":1.1,\"exchange\":\"DER\"},\"0.637\":{\"price\":0.637,\"volume\":8.4,\"exchange\":\"DER\"}},\"asks\":{\"0.664\":{\"price\":0.664,\"volume\":8.4,\"exchange\":\"DER\"}}},\"isMasterFrame\":true}"
];

// THE JSON IS AT INDEX '1' OF THE ARRAY SO WE PARSE IT
let payload = JSON.parse(messageString[1]);

// YOU CAN SEE THE PARSED JSON IN CONSOLE
console.log(payload.data);

// SINCE isMasterFrame IS EITHER TRUE OR FALSE, WE CAN TEST FOR IT WITHOUT USING hasOwnProperty 
// IF isMasterFrame IS UNDEFINED OR NOT IN THE JSON, THE ELSE BLOCK WILL EXECUTE AND NOT BREAK THE CODE
if (payload.isMasterFrame) {
    console.log("1 payload.isMasterFrame: " + payload.isMasterFrame);
   // SINCE IT IS A JSON, WE HAVE TO LOOP THROUGH THE FIRST PART THIS WAY
    for (var key in payload.data) {
        if (payload.data.hasOwnProperty(key)) {
            console.log("key base: " + key + " -> " + payload.data[key]);
            // SINCE THE VALUE IS ALSO A JSON OF VALUES, WE LOOP THROUGH AGAIN
            for (var key_inner1 in payload.data[key]) {
                if (payload.data[key].hasOwnProperty(key_inner1)) {
                    console.log("key inner1: " + key_inner1 + " -> " + payload.data[key][key_inner1]);
                    // GETTING THE CURRENT PAIR
                    let currentPair = payload.data[key][key_inner1];
                    console.log("CURRENT PAIR");
                    console.log(currentPair);
                    /*
                    currentPair = currentPair.replace(/\0/g, ''); //Remove null chars
                    if (currentPair.toUpperCase() != 'KILL') {
                        props.onAddAvailablePair(currentPair);
                    }
                    */

                    // SINCE THE VALUE IS ALSO A JSON OF VALUES, WE LOOP THROUGH AGAIN TO GET THE REAL VALUES
                    for (var key_inner2 in payload.data[key][key_inner1]) {
                        if (payload.data[key][key_inner1].hasOwnProperty(key_inner2)) {
                            // NOW WE CAN DO WHAT WE NEED TO WITH THE ACTUAL VALUES
                            console.log("key inner2: " + key_inner2 + " -> " + payload.data[key][key_inner1][key_inner2]);

                        }
                    }
                }
            }
        }
    }
    
} else {
    console.log("2 payload.isMasterFrame: " + payload.isMasterFrame);
}

enter image description here

  1. pairs property is not found inside object.
  2. String replace() method to replace a substring in a string with a new one. Here currentPair is a Object.If you try to replace any value of object just put if after currentPair ex: currentPair.exchange.replace(/\0/g, '');
  3. if (currentPair.toUpperCase() != 'KILL') this condition is not clear to me, you may try to match kill with any object value. you may use like this (currentPair.side.toUpperCase() != 'KILL')

     var messageString = [
             "BTC-31DEC21-60000-P",
             "{\"data\":[{\"price\":0.105,\"volume\":0.0,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.1055,\"volume\":28.7,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.106,\"volume\":7.6,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.1065,\"volume\":43.0,\"exchange\":\"DER\",\"side\":\"ASKS\"}],\"isMasterFrame\":false}"
         ]
    let payload = JSON.parse(messageString[1]);

    if (payload.hasOwnProperty("isMasterFrame")) {

        for (let i = 0; i < payload.data.length; i++) { //change here[1]
            let currentPair = payload.data[i]
            console.log(`current ${i} pair is- `,currentPair);
            // currentPair = currentPair.replace(/\0/g, ''); //change here[2]
            //  if (currentPair.toUpperCase() != 'KILL') { //change here[3] 
            //    props.onAddAvailablePair(currentPair);
            // }
        }
    } else {
        //print some output with payload which holds "isMasterFrame":false
    }


Output:
current 0 pair is-  {price: 0.105, volume: 0, exchange: 'DER', side: 'ASKS'}
current 1 pair is-  {price: 0.1055, volume: 28.7, exchange: 'DER', side: 'ASKS'}
current 2 pair is-  {price: 0.106, volume: 7.6, exchange: 'DER', side: 'ASKS'}
current 3 pair is-  {price: 0.1065, volume: 43, exchange: 'DER', side: 'ASKS'}

I kinda cannot make heads and tails of what you are trying to achieve but here you have it.
your payload.data (and mine decodedPayloadData.data) is and object and not an array so lenght will throw error. That is why you can use Object.entries to get array of elements from this object and then iterate it.

I have added iterateObject() function just to be fancy with displaying data.

const data = [
    [
        "BTC-31DEC21-100000-P",
        "{\"data\":{\"bids\":{\"0.01\":{\"price\":0.01,\"volume\":66.2,\"exchange\":\"DER\"},\"5.0E-4\":{\"price\":5.0E-4,\"volume\":1.1,\"exchange\":\"DER\"},\"0.637\":{\"price\":0.637,\"volume\":8.4,\"exchange\":\"DER\"}},\"asks\":{\"0.664\":{\"price\":0.664,\"volume\":8.4,\"exchange\":\"DER\"}}},\"isMasterFrame\":true}"
    ],
    [
        "BTC-31DEC21-36000-C",
        "{\"data\":[{\"price\":0.422,\"volume\":8.4,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.423,\"volume\":0.0,\"exchange\":\"DER\",\"side\":\"ASKS\"}]}"
    ],
    [
        "BTC-31DEC21-60000-P",
        "{\"data\":[{\"price\":0.105,\"volume\":0.0,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.1055,\"volume\":28.7,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.106,\"volume\":7.6,\"exchange\":\"DER\",\"side\":\"ASKS\"},{\"price\":0.1065,\"volume\":43.0,\"exchange\":\"DER\",\"side\":\"ASKS\"}],\"isMasterFrame\":false}"
    ]
];

const iterateObject = (params) => {
    Object.entries(params).map(([name, value]) => {
        if (typeof value === 'object') {
            console.log('name:', name, '{');
            iterateObject(value);
            console.log('}');
        } else {
            console.log('name:', name, '; value:', value);
        }
    });
};

data.map(payload => {
    const decodedPayloadData = JSON.parse(payload[1]);

    if (decodedPayloadData.hasOwnProperty('isMasterFrame') && decodedPayloadData.isMasterFrame === true) {
        Object.entries(decodedPayloadData?.data ?? {}).map(([_, params]) => {
            if (typeof params === 'object') {
                iterateObject(params);
            } else {
                console.log('name:', name, '; value:', value);
            }
        });
    } else {
        console.log('isMasterFrame is not defined or is not `true`');
    }
    console.log('----------------');
});
.as-console-wrapper {
  max-height: unset !important;
  top: 0;
}

Using an object

const message = [
  "BTC-31DEC21-100000-P",
  "{\"data\":{\"bids\":{\"0.01\":{\"price\":0.01,\"volume\":66.2,\"exchange\":\"DER\"},\"5.0E-4\":{\"price\":5.0E-4,\"volume\":1.1,\"exchange\":\"DER\"},\"0.637\":{\"price\":0.637,\"volume\":8.4,\"exchange\":\"DER\"}},\"asks\":{\"0.664\":{\"price\":0.664,\"volume\":8.4,\"exchange\":\"DER\"}}},\"isMasterFrame\":true}"
]
const obj = JSON.parse(message[1])
console.log(obj["isMasterFrame"])

output:

True
Related