I have a JSON file with a large amount of the following values:
"values": [
"Foo": 1,
"Bar": 2,
"Baz": 3,
...
],
How do I efficiently convert this into:
"values": [
{
"name": "Foo",
"value": 1
},
{
"name": "Bar",
"value": 2
},
{
"name": "Baz",
"value": 3
},
...
],
Any help would be appreciated!
Okay, so there are two problems with your input. The first is the fact that the given JSON is invalid, so can't directly be parsed. The square brackets after "values" should be curly brackets, to allow for a hash instead of an array:
let raw_old_data =
// Read the old file
fs.readFileSync('./input_data.json').toString()
// Remove all newlines which could interfere with the regex
.replace(/[\r\n]/g, '')
// Replace the square brackets after `"values"` with curly braces
.replace(/"values": \[(.+?)\]/g, '"values": { $1 }');
To convert this (now valid) string to a JSON object, you use JSON.parse:
let old_data = JSON.parse(raw_old_data);
The second problem is that the format in which the values are stored doesn't match your needs. You want to convert from { key: "value" } to [ name: "key", value: "value" ]. The following function can do that, assuming your version of Node supports ES6 (If not, look at Murillo's answer):
function fix_format(obj) {
// This is where we keep the new items in the correct format
let res = [];
// Loop over all values
Object.keys(obj.values).forEach(name => {
let value = obj.values[name];
// Change the format and add to resulting array
res.push({
// If the variable is the same as the key of the hash, it doesn't have to be specified
name,
value,
});
});
return res;
}
All that's then left to do is loop all data from the old object through that function with the Array.map function:
let new_data = old_data.map(fix_format);
And optionally write it back to a file to use with a different program:
fs.writeFileSync('./formatted_data.json', JSON.stringify(data, null, 2));
Note: The 2 in the JSON.stringify function indicates that the resulting JSON should be padded with 2 spaces, to keep it readable.
With ES6:
Object.keys(values).map(name => ({
name,
value: values[name]
}))
Without ES6:
var keys = Object.keys(values);
var newValues = [];
for(var i = 0; i < keys.length; i++){
newValues.push({
name: keys[i],
value: values[keys[i]]
})
}
If your intention is to use the received data i.e obtain data from DB (e.g MSSql, MySql...) using the connection.query(your_custom_sql_query, (err, rows, fields)
for more info:Node.js MySQL Select From Table
I'll recommend you to use:
const myJson = JSON.stringify(rows[0]);
Related
I’m not sure how to explain this but I’ll write an example on how I can create a new data from this using SQL. this is from MongoDb database and I can't change any thing. I was hoping if any one Knows how to execute this using the Select method.
SELECT * FROM mytable
Original data
[{
"id": "2433-10",
"busiName": "ABC",
"srTypeId": "2433-10",
"nodeType": "0",
"pathName": "home",
"busiSort": 10,
"SampleInfo": "1:sql test question identifiers: itemid:12345;itemname:Ford;itemid:12345; itemlocation=USA/itemDate=2014",
"superTypeId": "002",}]
I want extract just SampleInfo into New data
[{
"1":"sql test question identifiers"
"itemid":"12345";
"itemname":"Ford";
"iteminfo":"it's car";
"itemlocation ":"USA";
"itemDate":"2014";
}]
With some initial sanitization(replacing "=" with ":" and "/" with ";") maybe this is what you need:
( This is assuming that you have only single delimiter between the key/values and single delimiter between key and value )
db.collection.aggregate([
{
$addFields: {
newData: {
"$arrayToObject": {
"$map": {
"input": {
$split: [
"$SampleInfo",
";"
]
},
"as": "newD",
"in": {
"$split": [
"$$newD",
":"
]
}
}
}
}
}
}
])
Explained:
Split the SampleInfo based on delimiter ";" ( considering you have "key1:value1;key2:value2;key3:value3" in new array called newData.
Split the keys and values based on the key/value delimiter ":" , convert them to "key":"value" pair in the newData array field.
playground just aggregation
( If you want to just parse and output )
playground update + agg pipleine 4.2+
( If you want to parse and store back to the database under new field: newData )
But afcourse prefered option as suggested above is to sanitize and parse the data before inserting it to the database ...
Same thing via JavaScript Example:
mongos> function stringToObj (string) { var obj = {}; var stringArray = string.split(';'); for(var i = 0; i < stringArray.length; i++){ var kvp = stringArray[i].split(':'); if(kvp[1]){ obj[kvp[0]] = kvp[1] } } return obj; }
mongos> db.collection.find().forEach(function(d){ d.newData=stringToObj(d.SampleInfo);db.collection.save(d); } )
mongos>
Explained:
Define JS function stringToObj ( Converting the string to object )
Loop over all documents via forEach and use the function to parse and modify the document adding new field newData with the content.
I have been trying to parse JSON, which have 3 different set of data where one element have various number of children and sometimes none. I am getting an error when there is no children present or only one present. I declared the JSON as var data.
JSON A
{
"floorplan": [
{
"title": "plan1",
"url": "https://media.plan1.pdf"
},
{
"title": "plan2",
"url": "https://media.plan2.pdf"
}
]
}
JSON B
{"floorplan": []}
JSON C
{
"floorplan": [
{
"title": "plan1",
"url": "https://media.plan1.pdf"
}
]
}
I parsed the JSON like this:
var items = JSON.parse(data);
return {
floorplan1: items.floorplan[0].url;
floorplan2: items.floorplan[1].url;
}
But, it only returned data for the JSON A, for other 2 it gave TypeError: Cannot read property 'url' of undefined.
I modified the code to check if floorplan have at least one child and then parse data.
var items = JSON.parse(data);
var plan = items.floorplan[0];
if(plan){
return {
floorplan1: items.floorplan[0].url;
floorplan2: items.floorplan[1].url;
}
}
The new code returned data for JSON A and B(as empty row), but gave error for C. C have one child still it got the error.
I also tried this code, still got the error for JSON C.
var items = JSON.parse(data);
var plan = items.floorplan[0];
var plan1;
var plan2;
if(plan){
plan1 = items.floorplan[0].url;
plan2 = items.floorplan[1].url;
}
return{
floorplan1 : plan1 ? plan1 : null;
floorplan2 : plan2 ? plan2 : null;
}
Is there any method I can try to get data returned for all 3 types of JSON?
let data = `
[{"floorplan": [{
"title": "plan1",
"url": "https://media.plan1.pdf"
}, {
"title": "plan2",
"url": "https://media.plan2.pdf"
}]},
{"floorplan": []},
{"floorplan": [{
"title": "plan1",
"url": "https://media.plan1.pdf"
}]}]`;
let json = JSON.parse(data);
//console.log(json);
json.forEach(items=>{
//console.log(items);
let o = {
floorplan1: items.floorplan.length > 0 ? items.floorplan[0].url : '',
floorplan2: items.floorplan.length > 1 ? items.floorplan[1].url : ''
};
console.log(o);
o = {
floorplan1: (items.floorplan[0] || {'url':''}).url,
floorplan2: (items.floorplan[1] || {'url':''}).url
};
console.log(o);
o = {
floorplan1: items.floorplan[0]?.url,
floorplan2: items.floorplan[1]?.url
};
console.log(o);
const {floorplan: [one = {url:''}, two = {url:''}]} = items;
o = {
floorplan1: one.url,
floorplan2: two.url
};
console.log(o);
});
Sure. A few ways, and more than I have here. I have put all the raw data into one string, parsed it into json and then iterated through that. In each loop my variable items will correspond to one of the json variables you created and referenced in your question as items.
In the first example, I check to make sure that items.floorplan has at least enough elements to contain the url I'm trying to reference, then use the ternary operator ? to output that URL if it exists or an empty string if it doesn't.
In the second example, I use the || (OR) operator to return the first object that evaluates to true. If items.floorplan[x] exists, then it will be that node, and if it doesn't I provide a default object with an empty url property on the right hand side, and then just use the url from the resulting object.
In the third, I use the optional chaining operator that was introduced in 2020. This method will return undefined if the url doesn't exist.
In the fourth example, I use destructuring to pull values out of the items variable, and make sure that there is a default value for url in case the items variable doesn't have a corresponding value.
But there are many more ways to go about it. These are just a few, and you can't necessarily say which approach is better. It's dependent on your intent and environment. With the exception of optional chaining (which shows undefined if the property doesn't exist), you can see these produce the same results.
DOCS for optional chaining: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
DOCS for destructuring: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
An article on destructuring: https://javascript.info/destructuring-assignment
I'm using a custom script for importing JSON into Google Sheets through a function. I can import values from propertys without any problem, but I have some problem with a specific array. It is a property which contains more information, but it seems the formatting makes the array into one single value instead of several (something with the slashes?). First, the script:
function getStat(url, propertyName)
{
let content = UrlFetchApp.fetch(url).getContentText();
let parsed = JSON.parse(content);
let processed = parsed.data
.filter(e =>
// Conditions go here:
e.season_format === 'Domestic League' &&
e.season === '2020/2021'
)
.map(e => e.stats[propertyName]);
return processed;
}
I want to get the value after "3" in the array called additional_info (simplified version below). But when I try to get the value, instead I get the third character in the array. I don't get "55" which is the value. I've tried with a bunch of variants. But I can't get it to work. For example, additional_info["3"] returns the third character in the array, not the value. Any tips? I've no problem getting the values of suspended_matches and home_AttackAdvantage.
{
"success": true,
"data": [
{
"season": "2020/2021",
"season_format": "Domestic League",
"stats": {
"suspended_matches": 20,
"homeAttackAdvantage": 3,
"additional_info": "{\"1\":1,\"2\":2,\"3\":55,\"4\"}"
}
}
]
}
The issue was that additional_info is yet another JSON string, so you have to parse it again.
function getStat(url, propertyName, additionalProp)
{
let content = UrlFetchApp.fetch(url).getContentText();
let parsed = JSON.parse(content);
let processed = parsed.data
.filter(e =>
// Conditions go here:
e.season_format === 'Domestic League' &&
e.season === '2020/2021'
)
.map(e => additionalProp
? [
e.stats[propertyName],
JSON.parse(e.stats.additional_info)[additionalProp]
]
: e.stats[propertyName]
);
return processed;
}
This gives you a function you can use in a formula:
=getStat(
"https://api.footystats.org/team?key=example&team_id=93",
"suspended_matches",
"330"
)
If you don't specify the third argument, it will just return a single column.
I am trying to build a custom visual for datastudio, I got it working but there is a step, i can't fix, Datastudio generate a json file like this
export const message = {
"tables": {
"DEFAULT": [
{
"coordinateid": [
"143.4999336,-34.777302"
],
"colorid": [
"169,255,169"
],
"sizeid": [
1
]
},
{
"coordinateid": [
"143.4999358,-34.7773749"
],
"colorid": [
"169,169,169"
],
"sizeid": [
1
]
},
{
in deckgl the relevant code is
const drawViz = (data) => {
var data1 = data.tables.DEFAULT;
getPosition: d => d.coordinateid,
the only way to make it work, is when i remove the quotes from the values inside the array
"coordinateid": [
143.4999336,-34.777302
]
is there a way either to remove the double quotes between the bracket or a way just to parse the values and ignoring the double quotes
DataStudio returns GEO LatLong coordinates as a comma separated string. The correct way to parse this would be the following:
var baseCoordinate = "143.4999336,-34.777302";
// Split out the coordinates into multiple strings
var coordinates = baseCoordinate.split(",");
// Turn the strings into floats
var coordinatesAsNumbers = coordinates.map((coord) => parseFloat(coord));
This will give you the coordinates as floats in an array, which seems to be the format that deckgl is expecting.
find the answer
basically, change the javascript object to string using JSON.stringify the using regex to replace the strings then use Json.parese to change it back to an object
var data1 = data.tables.DEFAULT;
var data2 = JSON.stringify(data1);
var data3 = data2.replace(/\"]/g, "]");
var data4 = data3.replace(/\["/g, "[");
var data4 = JSON.parse(data4);
I have a long list of data, in the following format:
[
{
"ID": "1234",
"date/time": "2016-07-18 18:21:44",
"source_address": "8011",
"lat": "40.585260",
"lng": "-105.084420",
}
]
And I am creating a script to extract the values out of each line. For example, if a line contains "ID": I want to be able to store the value "1234" into a variable, so I can store it in a different format.
Here is my code to detect "ID":
'use strict';
let lineReader = require('line-reader');
//.JSON variables from input file
let id;
//begin creating new object
console.log('var source = {');
//output the file
lineReader.eachLine('dataOut.json', function (line, last) {
//detect ID, and print it out in the new format
if (id =~ /^id:$/) {
console.log('id: "') + console.log('",');
}
//done
if (last) {
console.log('}');
return false; // stop reading
}
});
Once I detect the ID, I'm not sure how I can obtain the value that follows the "ID" on that line.
How can I store the values on a line, after I detect which line they are on?
Unless your json file is stupidly big, you can just require it and then it's an in memory JS object.
var obj = require('./dataOut.json');
// first element
console.log(obj[0]);