When using JSON to send an array of objects from the same class the objects fields are repeated many times, often unnecessarily, and the message becomes very long for arrays with big length. To my knowledge, there is no way to remove the field's repetition using only JSON. So I'm looking for a solution that solves the encoding and decoding of arrays without repeating the fields names.
As an example, the array below:
A:
[
{id:1;name:Name 1;description:Description 1},
{id:2;name:Name 2;description:Description 2},
...,
{id:N;name:Name N;description:Description N}
]
can be represented by:
B:
{
fields:[id, name, description],
values:[
[1,Name 1,Description 1],
[2,Name 2,Description 2],
...,
[N,Name N,Description N]
]
}
spending lot less space in the case of arrays with big length.
But I need a solution that does this transformation (from A to B and B to A) automatically. It can use the B represantation, or a better, to reduce the message size by eliminating fields names.
Any solution?
You can do this by writing two simple javascript functions to encode and decode as you want. Some rules have to apply in order for this paterns to work:
There must be a valid JSON input data string, though you can use a
plain array with objects
All array elements must have the same object structure format
It does not wotk with child objects
Minify/Unminify object function:
function minifyObject(obj) {
var fields = Object.keys(obj[0]);
var values = [];
for(var record in obj) {
var value = [];
for(var field in fields) {
value.push(obj[record][fields[field]]);
}
values.push(value);
}
return {
fields: fields,
values: values
}
}
function unminifyObject(obj) {
var output = [];
for(var i = 0; i < obj.values.length; i++) {
var record = {};
for(var j = 0; j < obj.fields.length; j++) {
record[obj.fields[j]] = obj.values[i][j];
}
output.push(record);
}
return output;
}
var data = [
{"id":1, "name": "Name 1", "description": "Description 1"},
{"id":2, "name": "Name 2", "description": "Description 2"},
{"id":3, "name": "Name 3", "description": "Description 3"}
];
var minified = minifyObject(data);
console.log("Minified object\n", minified);
var unminified = unminifyObject(minified);
console.log("Unminified array\n", unminified);
This code can also be simplified using ES6.
You can also find my test JSON converter here: https://zikro.gr/dbg/so/20129724/
Related
I am trying to write a script to batch update products in a Woocommerce store via Rest API. API requires to send request as a JSON object, but I can't build the Object in the necessarily format.
Object should look like this:
'{
"update": [
{
"id": 799,
"name": "product name"
},
{
"id": 800,
"name": "product name 1"
}
]
}'
I am trying to build the Object the following way, but it doesn't work:
var APIPayloadObject = {update:[]};
//starting loop
for ( i = 0; i < lastrow; i++){
var product = [];
product.push({
id: loopRange[i][0],
name: loopRange[i][1]
})
//???????
}
Logger.log(JSON.stringify(APIPayloadObject));
At question marks I don't know how to push product array into the object
Sample 1
As mentioned in my comment, the first solution is to access the update property and invoke push() on it since you already defined update to contain an Array instance:
//starting loop
for ( i = 0; i < lastrow; i++){
APIPayloadObject.update.push({
id: loopRange[i][0],
name: loopRange[i][1]
})
}
Sample 2
You can take it one step further and directly write your objects to update Array at the i index, since you start from 0:
//starting loop
for ( i = 0; i < lastrow; i++){
APIPayloadObject.update[i] = {
id: loopRange[i][0],
name: loopRange[i][1]
};
}
This is a great use case for Array.prototype.map.
// #param {sheetValues[][]} loopRange
function getPayload(loopRange) {
return JSON.stringify({
update: loopRange.map(function (row) {
return {id: row[0], name: row[1]};
})
});
}
I want to create a dojo datagrid with a header looking like this :
As you can see I want some section headers (Section A, Section B...), containing many "subheaders" (A1, A2, A3... B1, B2...). I get all the data in a json response when I call the page. Then I was able to do two things :
First, get the data in the json to display all the subheaders, like this :
var gridStructure = [
{width:'150px', name:'Table'}
];
for(var i = 0 ; i < response.columns.length ; i++) {
for(var j = 0 ; j < response.columns[i].sections.length ; j++) {
var subColumnToAdd =
{width:'200px', name:response.columns[i].sections[j].sectionName};
gridStructure.push(subColumnToAdd);
}
}
grid.setStructure(gridStructure);
And I also was able to display a table like how I want, but not dynamically :
var gridStructure = [{
cells:[
[{width: 'auto'}],
[{
name: 'Section A',
colSpan: 2
}],
[{
name: 'A1',
field: 'col1'
}, {
name: 'A2',
field: 'col2'
}]
],
onBeforeRow : function(inDataIndex, inSubRows) {
inSubRows[0].invisible = true;
}
}];
grid.setStructure(gridStructure);
Now what I don't know to do is how to mix it, to fill the headers/subheaders with dynamic data. Thanks for your help and advices.
Try something like this:
var gridStructure = [
[
{width:'150px', name:'Table', rowSpan: 2}
]
];
for(var i = 0 ; i < response.columns.length ; i++) {
for(var j = 0 ; j < response.columns[i].sections.length ; j++) {
var subColumnToAdd =
{width:'200px', name:response.columns[i].sections[j].sectionName};
gridStructure.push(subColumnToAdd);
}
}
But that is adding the table statically... to make it completely dynamic, you'll still need something (perhaps in the data itself) that specifies the value for colSpan/rowSpan to get it to display properly.
To add the data, you just need to build a json array of your data. Each item of that array will be an object containing a single item. Should be straightforward if your data is already in this format, otherwise just create a loop and build the item dynamically.
var items = [
{ name: "First", someProperty: true},
{ name: "Second", someProperty: false}
];
Once you have it, there are many options on how to build stores:
store = new Memory({ data: items });
dataStore = new ObjectStore({ objectStore: store });
myGrid.set("store", dataStore);
or
grid = new DataGrid({
store: dataStore,
...
You can use this as a reference/example https://dojotoolkit.org/documentation/tutorials/1.9/datagrid/demo/datagrid-subrows.php
My sample json is
"multiList": [
{
"my_key" : "this is my key"
},
{
"my_text_box": "This is my text box"
},
]
How do I convert this to
{"my_key" : "this is my key"},
{my_text_box": "This is my text box"},
dynamically?
using jquery
Your question doesn't make sense. Are you asking to convert to two separate objects? A string representation of those two objects? Something else? I can do the first two:
var objOne = json.multiList[0];
var objTwo = json.multiList[1];
var objStr = JSON.stringify(json.multiList[0]) + ', '
+ JSON.stringify(json.multiList[1]);
If you want to add all of the separate properties into one object, you can just extend another object in a loop.
var obj = {};
json.multiList.forEach(function (elem) {
for (k in elem) {
if (elem.hasOwnProperty(k)) {
obj[k] = elem[k];
}
}
});
http://jsfiddle.net/ExplosionPIlls/t2xyd/
This makes no consideration for the overriding of properties in obj.
I have an array of objects that I need to convert to a 2d array so I can write to a Google spreadsheet where each property is written to a cell. I have the function below:
function objectsToArray(objects) {
var outPutArray = createArray(objects.length, objects[0].length);
for (var i in objects) {
for (var j in objects[i]) {
if (objects.hasOwnProperty(i)) {
outPutArray[i][j] = objects[i][j];
}
}
}
return outPutArray;
}
example object:
object {
name: John
phone: 555-5555
email: john#john.com
}
The problem is that instead of putting the properties value in the array element (outputArray should look like [[John, 555-5555, john#john.com],[..., ..., ...]] it adds the properties to each array element.
In the first part of your function,
function objectsToArray(objects) {
var outPutArray = createArray(objects.length, objects[0].length);
it looks like you are assuming objects is already a 2D array. I'm going to assume that objects is a 1D array of objects like this. [{prop:value...},{...},{...}].
Now what you want to do is generate 2 numerical indices from this data. You will want to ensure that "column 1" of the 2D array is the same property for all objects.
So your first for loop should be over the properties. Also, keep an index so you know what number property you are on.
var j = 0;
for (var prop in objects[0]) {
Then you should do a loop over all the objects. So the idea is that first you will select "name", then go through all the objects, adding the "name" field to the 2D array for each object.
for (var i in objects) {
outPutArray[i][j] = objects[i][prop];
}
j++;
}
I think the main issue that you were seeing is because you weren't using numeric indices. (var j in objects[i]: this defines j as a property, such as "name", not a numeric index, like you were expecting).
Here's one way...
function myFunction() {
var objects = {};
objects[0] = {"name": "John", "phone": "555-5555", "email": "john#john.com"};
objects[1] = {"name": "Mary", "phone": "444-4444", "email": "mary#mary.com"};
var outputArrary = objectsToArray(objects);
Logger.log(outputArrary);
}
function objectsToArray(objects) {
var outputArray = [];
for (var i in objects)
outputArray.push([objects[i].name, objects[i].phone, objects[i].email]);
return outputArray;
}
I need to get rather complicate JSON data from (large) JSON file into a table at a specific part of a page. Somehow when I ran my code, nothing happens.
Snap shoot of purchase.json file -
{
"table": {
"purchases": [
{
"First Name": "Joe",
"Last Name": "Jenson",
"Product": "Netbook Computer",
"Price": "356",
"Purchase Date": "04/04/2011",
"Unit Count": "1",
"Type": "Computer",
"Return Date": "05/03/2011",
"Seq. No.": "0"
},
{
"First Name": "Christy",
"Last Name": "Davis",
"Product": "iPad",
"Price": "656",
"Purchase Date": "04/07/2011",
"Unit Count": "1",
"Type": "Computer",
"Return Date": "05/06/2011",
"Seq. No.": "10"
},
{
"First Name": "Justin",
"Last Name": "Gill",
"Product": "Laptop Computer sleeve",
"Price": "699",
"Purchase Date": "04/02/2011",
"Unit Count": "1",
"Type": "Computer Assesory",
"Return Date": "05/01/2011",
"Seq. No.": "20"
}
]
}
}
The html file -
JSON to table
get json file "purchase.json"
Parse the array into a table and load it in AJAXDiv
Table header has to be pulled from the key in the key:value pair found in the JSON.
The JavaScript code I have is -
$(document).ready(function() {
//Retrieve the JSON data from the server using AJAX
$('#AJAXButton').click(function() {
$.getJSON('data/purchase.json', function(data) {
processJSON(data);
});
});
//Process and display the JSON data
function processJSON(jsondata) {
var output = '<table cellpadding="0" cellspacing="0" border="0" class="display" id="example"><thead><tr>';
// retrieve the keys and place into an array
var keys = objKeys(jsonData.table.loans[0]).join("|");
var keyData = splitString(keys);
// print header
for (var i = 0; i < keyData.length; i++)
{
output += "<th>" + keyData[i] + "</th>";
}
output += "</thead></tr><tfoot>";
// print footer
for (var i = 0; i < keyData.length; i++)
{
output += "<th>" + keyData[i] + "</th>";
}
output += "</tfoot></tr><tbody>";
// print content of the json array in tbody
for(var j=0, jj = jsonData.table.loans.length; j < jj; j++)
{
for (var k = 0, kk = keyData.length; k < kk; k++)
{
var current = keyData[k];
output +="<td>" + jsonData.table.loans[j][current] + "</td>";
}
output += "</tr>";
}
output += "</tbody></tr></table>";
//Loop through the Languages
$('#AJAXDiv').html(output);
}
// get json keys
function objKeys(obj)
{
var keys = [];
var i = 0;
for (var z in obj)
{
if (obj.hasOwnProperty(z)) {
keys[i++] = z;
}
}
return keys;
}
// split string into array
function splitString(myString)
{
var mySplitResult = myString.split("|");
return mySplitResult;
}
});
It may be that you have a variable missing, there's
function processJSON(jsondata)
But you later use
jsonData.table.loans[0] //etc....
I suggest using a debugger like Firebug or DevTools, it makes problems like this much easier to catch.
You can also use this library: Json-To-Html-Table
I use this script that i coded my self, it really builds any json table from a mysql result
o whatever the MySQL is outputting, you can rename the column names with your own labels, by the output order. Also if you give none, the default names will be generated.
It used the $post Jquery plugin-in which you can add easly with 1 line of code.
all you need is the div with table_result:
function dyna_query(label){
$.post("your_mysql_query.php",{post_limit:15},function(e){
if(e=="fail"|| e=="" ||e=="[]"){return;}
var obj=JSON.parse(e);
//get default column names based on the associative object JSON
var column_n=Object.keys(obj[0]).length/2;
var c_names=Object.keys(obj[0]).splice(column_n,column_n);
//if there are labels, then these will replace others.
if( label){c_names=label.split(",");}
var table_row="";
//initialize table
var table_format="<table border=0><tr>";
for(var r=0; r<c_names.length;r++){
table_row+="<td class=table_h>"+c_names[r]+"</td>";}
table_row+="</tr>";
for(var i=0; i<obj.length;i++){table_row+="<tr>";
for(var c=0; c<c_names.length;c++){table_row+="<td class='table_bb'>"+obj[i][c]+" </td>";}table_row+="</tr>";}
//get all the other fields and rows
table_format+=table_row+"</table>";
//buld the html for the div with the id table_result
$("#table_result").html(table_format);
});
}
now simply call dyna_query("c1, c2, c3"); //renames default column names
or
dyna_query(); for full output with default labels