modifying JSON with subarrays - javascript

I'm having an issue getting my data from my "react-hook-form" web form in the correct format for my api
I'm already cheating by entering in the [] date field of the form which isn't ideal but just trying to get passed this step for now.
I need to send it over like the below DesiredData, basically with array brackets around the entire thing and then the apostrophes '["1-2-2020", "1-3,2020"]' for the dates
DesiredData:[
{
name:"bob"
age:"20"
dates: ["1-2-2020", "1-3,2020"]
}]
CurrentData: {
name:"bob"
age:"20"
dates: '["1-2-2020", "1-3,2020"]'
}

var currentData = {
name:"bob",
age:"20",
dates: '["1-2-2020", "1-3,2020"]'
}
currentData.dates = JSON.parse(currentData.dates)
var desiredData = [currentData];
console.log(desiredData)

Related

How can I access multiply nested sub objects in javascript?

I have a larger code which handles and sorts data. In it I want to work with objects to keep it easier and better structured. I have multiple categories and all of them have different nested subobjects, which I have trouble accessing writing/reading.
I searched on the web, w3schools but couldn't find my mistake, so sry for this entry level question!
I wrote a test function to better understand objects!
function test(){
var report, time, name, date, value;
report = 'Income Statement';
time = 'Annually';
name = 'Revenue';
date = '2017';
value = '10000000';
data = {}
data[report] = {}
data[report][time] = {}
data[report][time][name] = {}
data[report][time][name][date] = value;
console.log(data);
}
As to my understanding what this code does is:
-create an empty object data
-create an empty subobject report
-create an empty subsubobject time
-create an empty subsubsubobject name
-gives the subsubsubobject name a key/value pair date:value
(at least that was my intention to do)
First I tried to skip creating empty objects and directly fill data{} with:
data = {}
data[report][time][name][date] = value; but he seems to cannot set properties to this.
So I created like above coded first empty subobjects for all subcategories, is this really necessary or am I falling for a simple syntax mistake?
However he still doesn't log me the desired output which would be:
{ 'Income Statement': { Annually: { Revenue: {2017:10000000} } } }
and instead gives me:
{ 'Income Statement': { Annually: { Revenue: [Object] } } }
Simply put.. what am I doing wrong? :D
Thanks in advance for any kind of help!
Best regards
I don't think you are doing anything wrong. I pasted same code in JS console and it is giving proper result.
Screenshot of console with result of function
Different ways to initialize object
Static Data
let data = {
'Income Statement': {
'Annually': {
'Revenue': {
'2017': '10000000'
}
}
}
}
document.querySelector("#data-result").innerHTML = JSON.stringify(data)
<div id="data-result"></div>
Dynamic Data
var report, time, name, date, value;
report = 'Income Statement';
time = 'Annually';
name = 'Revenue';
date = '2017';
value = '10000000';
let data = {
[report]: {
[time]: {
[name]: {
[date]: value
}
}
}
}
document.querySelector("#object-result").innerHTML = JSON.stringify(data)
<div id="object-result"></div>
You can also consider different ways to store same data.
Example -
let data = [{
report: 'Income Statement'
time: 'Annually'
name: 'Revenue'
date: '2017'
value: '10000000'
}]
So now, if you want data by date in future you can get that by using filter
let data_2017 = data.filter(x => x.date === '2017');
It is correct !! I received { Income Statement: { Annually: { Revenue: {2017:10000000} } } } at console as an output with your given code.
Are u trying to save that data in some variable using test() ??
If yes then you need to use return data at the end of the definition on the function test instead of consol.log(data).

Parsing header row with dates when importing csv data

I'm using d3 to import a CSV file for data visulisation. My CSV file has header rows that I need to convert to dates, and data that needs to be converted to integers:
ISBN,2019-08,2019-09,2019-10
9782749205465,107,488,218
9789423069313,95,87,186
I can import the CSV file and parse the data as integers using:
d3.csv("/assets/2019-20-download-stats.csv").then(function (data) {
data.forEach(function(d) {
d.ISBN = +d.ISBN;
d['201908'] = +d['201908'];
d['201909'] = +d['201909'];
d['201910'] = +d['201910'];
});
});
but the header rows are all strings in the output array, e.g.:
{
"201908": 107,
"201909": 488,
"201910": 218,
"ISBN": 9782749205465,
}
How do I format the header rows when importing the data?
This is almost certainly a XY problem. I can't see any situation where your data should have objects with dates as keys. On top of that, pay attention to the fact that JavaScript will automatically convert your date objects to strings if you pass them as an object's key. If you (for whatever reason) really want a date as key, you should use a Map.
All that being said, here is what you should do: in the row conversion function (you have none in your code), check for a date...
if (!isNaN(new Date(key).getTime()))
... and, if you find one, use new Date to generate the key:
foo[new Date(key)] = +d[key]
Here is a demo using d3.csvParse (which would be exactly the same for your d3.csv):
const csv = `ISBN,2019-08,2019-09,2019-10
9782749205465,107,488,218
9789423069313,95,87,186`;
const data = d3.csvParse(csv, row);
function row(d) {
const newObject = {};
for (var key in d) {
if (!isNaN(new Date(key).getTime())) {
newObject[new Date(key)] = +d[key]
} else {
newObject[key] = +d[key]
}
};
return newObject;
};
console.log(data)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

JSON stringify re-structure

I have a database, with multiple cells, and under each cell, values.
Cells are: id, name, duration, date, and relationid
I have this code:
var result = {}
properties.data.forEach(addToResult); //Get data from database using properties.data
instance.data.datavarb = JSON.stringify(result); //Send data after converted to JSON
function addToResult(pair,isjson){ //operations
if(isjson===true) result[pair.key] = JSON.parse(pair.value); else result[pair.key] = pair.value;
}
I'm facing 2 problems:
1- First problem:
This is how i get the value after converted to JSON:
{"id":"1","name":"Football","duration":"12","date":"02-07-2018","relationid":null}
How i need to be:
{id:1, name:"Football", duration:12, date:"02-07-2018", relationid:null}
Need remove the "" quotes from the numbers (id, duration and relationid) and the id,duration,relationid values.
2- Second problem:
In the problem 1, just for show you I only was parsing one of the three values from my database. What happens when I parse them all? This is how it looks like:
{"id":"1, 2, 3","name":"Football, France, Belgium","duration":"12, 4, 3","date":"02-07-2018, 08-07-2018, 10-07-2018","relationid":", 1, 1"}
Instead of creating one by one, it creates the same identifiers (id,name,duration) and put all the values in the same. For my prupose i need to be:
{id:1, name:"Football", duration:12, date:"02-07-2018", relationid:null},
{id:2, name:"France", duration:4, date:"08-07-2018", relationid:1},
{id:3, name:"Belgium", duration:3, date:"10-07-2018", relationid:1}
Many thanks!!
You can test whether the values look like integers, and parse them.
function addToResult(pair,isjson){ //operations
if(isjson===true) {
result[pair.key] = JSON.parse(pair.value);
} else if (/^\d+$/.test(pair.value)) {
result[pair.key] = Number(pair.value);
} else {
result[pair.key] = pair.value;
}
}

Pull Gmails into a Google Sheet

This script works brilliantly to pull emails into my sheet. My problem is that the function only pulls the first two fields listed. e.g., getPlainBody, getSubject - even though more fields are asked for. So instead of having one function that pulls all the fields I need (getPlainBody, getSubject, getTo, getDate, getFrom) I only get the first two (getPlainBody, getSubject). Is there an obvious modification that will pull all 5 fields into the sheet?
function getEmails_(q) {
sh0.clear();
var emails = [];
var threads = GmailApp.search(q);
for (var i in threads) {
var msgs = threads[i].getMessages();
for (var j in msgs) {
emails.push([msgs[j].getPlainBody(), [msgs[j].getSubject(), [msgs[j].getDate(), [msgs[j].getTo(), [msgs[j].getFrom()
]]]]]);
}
}
return emails;
}
function appendData_(sh0, array2d) {
sh0.getRange(sh0.getLastRow() + 1, 1, array2d.length, array2d[0].length).setValues(array2d);
}
function saveEmails() {
var array2d = getEmails_(SEARCH_QUERY);
if (array2d) {
appendData_(sh0, array2d);
}}
Your code is fine the problem is how you are constructing the 2D array.
in the .push() method, your use of the square brackets - [] - is building an array within an array within another array within another array within another array within another array, it's easier to see it in the screenshot below.
What you need is 1 array of horizontals cells with an array of vertical rows.
So change:
emails.push([msgs[j].getPlainBody(), [msgs[j].getSubject(), [msgs[j].getDate(), [msgs[j].getTo(), [msgs[j].getFrom()]]]]]);
to
emails.push([msgs[j].getPlainBody(), msgs[j].getSubject(), msgs[j].getDate(), msgs[j].getTo(), msgs[j].getFrom()]);
On a personal note, I usually always format the date to something a little more readable. You can use Utilities to do this. Ex: format: Thu Jun 15 2017 11:18:18 GMT+0700 (ICT) to 15/06/2017 # 11:18
var formatDate = Utilities.formatDate(emails[i][2], 'GMT+07:00', 'dd/MM/yyyy # HH:mm')

Turn Observable Array into nested JSON

I'm having a problem getting an array of information stored properly as JSON.
I made a fiddle to illustrate the problem. Enter a set of tags and take a look at the console to see the output.
More explanation:
So I have an input that takes in a comma-separated list of tags, which I then format.
function createTagArray() {
// given an input value of 'tag1, tag2, tag3'
// returns array = ['tag1', 'tag2', 'tag3']
}
I thought what I needed to do next was the following:
loop over the array and create a 'tag' object for each item which also includes an id for the tag and the id of the contact the tag is associated with.
Each object is pushed to tags, an observable array.
function single_tag(id, contactId, tagLabel) {
var self = this;
self.id = id;
self.contactId = contactId;
self.tagLabel = tagLabel;
}
function createTags() {
var array = createTagArray();
for (var i = 0; i < array.length; i++) {
self.tags().push(new single_tag(uuid.generate(), self.contactId, array[i]));
}
}
Then, I converted it into JSON
self.contactInformation = function() {
return ko.toJS({
"id": self.contactId,
"firstname": self.firstname(),
"lastname": self.lastname(),
... other fields ...
"tags": self.tags(),
})
}
But, when I inspect the console output of calling this function, tags is a collection of arrays, not a nice json object.
How do I get it formatted correctly?
I tried this suggestion, and the tag json is structured correctly, but it is stored with escaped quotes, so that seems wrong.
Thanks for all the help!
I would recommend you knockout.mapping plugin for KO, it allow map complicated JSON structure to view model, even without declarations.
From the documentation
Let’s say you have a JavaScript object that looks like this:
var data = {
name: 'Scot',
children: [
{ id : 1, name : 'Alicw' }
]
}
You can map this to a view model without any problems:
var viewModel = ko.mapping.fromJS(data);
Now, let’s say the data is updated to be without any typos:
var data = {
name: 'Scott',
children: [
{ id : 1, name : 'Alice' }
]
}
Two things have happened here: name was changed from Scot to Scott and children[0].name was changed from Alicw to the typo-free Alice. You can update viewModel based on this new data:
ko.mapping.fromJS(data, viewModel);
And name would have changed as expected. However, in the children array, the child (Alicw) would have been completely removed and a new one (Alice) added. This is not completely what you would have expected. Instead, you would have expected that only the name property of the child was updated from Alicw to Alice, not that the entire child was replaced!
...
To solve this, you can specify which key the mapping plugin should use to determine if an object is new or old. You would set it up like this:
var mapping = {
'children': {
key: function(data) {
return ko.utils.unwrapObservable(data.id);
}
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
In the jsfiddle you were using Knockout 3.0 which doesn't have support for textInput. This was added in 3.2. To use version 3.2 you need to use a cdn such as this: http://cdnjs.com/libraries/knockout
There was typeo in your binding. sumbit should be submit.
There was a problem with your constructor for single_tag. id was not used so I removed it:
function single_tag(contactId, tagLabel) {
var self = this;
self.contactId = contactId;
self.tagLabel = tagLabel;
}
Currently also contactId is not set because the observable has not been set to a value.
To convert to JSON you need to use ko.toJSON instead of ko.toJS:
self.contactInformation = function() {
return ko.toJSON({
"firstname": self.firstname(),
"tags": self.tags(),
})
}
Now when the console writes out an array appears:
{
"firstname":"test",
"tags":[
{"tagLabel":"test1"},
{"tagLabel":"test2"},
{"tagLabel":"test3"}
]
}
JsFiddle
So my problem was more basic than I was realizing. I'm using JSON Server to serve up my data, and I was pulling information from two parts of the database (contacts & tags).
When I tried to update my tags, I was trying to apply them to a property that didn't exist on the contact JSON in my database. Posting the tags separately worked though.

Categories

Resources