I'm fetching data in React from a MySQL database. MySQL auto-escapes my values including nested objects. I'm using the .json() function on the top-level but i'm not able to use this on sub-levels, nor JSON.parse(response[0].data) will work.
What is the right way of doing this?
fetch(`http://localhost:3000/getQuiz${window.location.pathname}`, requestOptions)
.then(response => response.json())
.then(response => {
console.log(response)
// {
// "id": 1,
// "url": "asd2q13",
// "data": "{name: \"Marie\", answers:[\"1\", \"3\", \"0\"]}"
// }
console.log(typeof response)
// object
console.log(response[0].data)
// {name: "Marie", answers:["1", "3", "0"]}
console.log(typeof response[0].data)
// string
console.log(response[0].data.name)
// undefined
})
The response.data is not a valid JSON string. You can try:
const response = {
"id": 1,
"url": "asd2q13",
"data": "{name: \"Marie\", answers:[\"1\", \"3\", \"0\"]}"
}
console.log(eval('(' + response.data + ')'))
Or Better:
const response = {
"id": 1,
"url": "asd2q13",
"data": "{name: \"Marie\", answers:[\"1\", \"3\", \"0\"]}"
}
function looseJsonParse(obj) {
return Function('"use strict";return (' + obj + ')')();
}
console.log(looseJsonParse(response.data))
But,
Warning: Executing JavaScript from a string is an enormous security risk. It is far too easy for a bad actor to run arbitrary code when you use eval(). See Never use eval()!, below.
I suggest you serialize the data correctly on the backend. I think the MySQL database driver can do this. Also, see Parsing JSON (converting strings to JavaScript objects)
MySQL (MySQL2) for Node was the big problem here. It's suppose to serialize "automatically", but somehow it ends up all wrong.
If I do JSON.Stringify() explicitly for the nested part before storeing it in the database it works!
const sendToDatabase = () => {
let nested = JSON.stringify({ name: "Marie", answers: ["2", "1", "0"] })
let post = { url: "asd2q13", data: nested}
var query = connection.query(
"INSERT INTO users SET ? ", post,
function (error, results, fields) {
if (error) throw error;
}
);
console.log(query.sql);
};
Then I call this on the front end
console.log(JSON.parse(response[0].data).name)
// Marie (string)
console.log(JSON.parse(response[0].data).answers)
// ["2", "1", "0"] (array)
The raw output from this is
{"name":"Marie","answers":["2","1","0"]}
insted of
{name: \"Marie\", answers:[\"1\", \"3\", \"0\"]}
Related
I have a JSON file with some items. I'd like to randomly select one to display using Javascript. Here's the JSON file:
{
"keywords": [
{
"name": "item1",
"property1": "value1",
"property2": "value2",
"property3": "value3"
},
{
"name": "item2",
"property1": "value4",
"property2": "value5",
"property3": "value6"
}
]
}
I fetch the file as follows:
let data;
function fetchJSON() {
fetch('../keyworddata.json')
.then(response => {
if(!response.ok) throw new Error("HTTP status " + response.status);
return response.json();
})
.then(jsonData => {
data = jsonData;
})
.catch(error => {
console.error('Error:', error);
});
}
fetchJSON();
myData = JSON.parse(data);
lengthOfMyData = Object.keys(myData.keywords[0]).length;
console.log(lengthOfMyData);
However, I get the following error:
JSON Parse error: Unexpected identifier "object"
Can you help me? I'd like to find the number of items in the JSON file and then pick a random item from the list.
There's some weirdness going on here: you're using a global variable for data associated with a function, your second then is wrong in terms of what you named things (response.json() parses JSON, it does not return JSON. It returns a normal JS datastructure, leading to the next bit) and you're trying to parse regular JS data as if it's JSON.
So let's fix all of that:
function fetchJSON(filename) {
return fetch(filename)
.then(response => response.json())
.catch(error => {
// Log error, and return an object that the consuming
// code can still work with, but is effectively "empty"
console.error({error});
return { keywords: [] };
});
}
const { keywords } = await fetchJSON(`../keywords.json`);
console.log(keywords.length);
Although it would make far more sense to not make fetchJSON handle the errors, and instead have the calling code have a try/catch so that if the fetch fails for whatever reason, your calling code knows where to branch next.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 20 days ago.
Improve this question
SOLVED!:
The api had weird characters copied that were being sent over and breaking my javascript. always double check the values you are being sent!
To give full context on this:
to give the full context, i have a post api that is giving me the above structure in postman. i need to check the number and the code and if there are multiple objects returned. when i try to simply return the json i get the following error :json.parse()SyntaxError: Expected property name or '}' in JSON at position 2. Ive been trying to create work arounds to get the value but the best i can do is get it returned as a string using the code above. My goal is to check the code and the number of each object so i can validate against it. thank you for your help!
when returning my data from a post API I'm getting the response as a string. It's a formatted like an array of objects but I'm having difficulty parsing it due to the structure. the structure is as follows:
{
"items": [
{
"number": 119777777,
"code": "S",
"name": "name Full award ",
"year": 2021,
"updatedate": "04-JAN-2023"
},
{
"number": 119777777,
"code": "H",
"name": "Hospital funding.",
"year": 2021,
"updatedate": "04-JAN-2023"
}
]
}
how can I transform this into something usable? I need to check the values of the code in each object for validation.
heres my code:
function GetFunding() {
var responseClone; // 1
fetch('my url',{
method: "POST"
})
.then(function (response) {
responseClone = response.clone(); // 2
return response.json();
})
.then(function (data) {
// Do something with data
}, function (rejectionReason) { // 3
console.log('Error parsing JSON from response:', rejectionReason, responseClone); // 4
responseClone.text() // 5
.then(function (bodyText) {
console.log('Received the following instead of valid JSON:', bodyText); // 6
});
});
};
let fetchRes = fetch(
"https://jsonplaceholder.typicode.com/todos/1")
fetchRes.then(res =>
res.json()).then(data => {
console.log(data)
})
Your response is also correct but you can simplify using my code and for error handle you can write catch block.
You are saying that you are getting response in string but you should know that a object always have keys as a string , Even if you pass a number as a key to object , It will always go to string to object.
I think something like this could work out:
function GetFunding() {
fetch('my url',{
method: "POST"
})
.then(response => response.json())
.then(data => {
const items = data.items;
items.forEach(item => {
if (item.code === 'S') {
// do something
} else if (item.code === 'H') {
// do something else
}
});
})
.catch(error => console.error(error));
};
const string = '{ "items": [ { "number": 119777777, "code": "S", "name": "name Full award ", "year": 2021, "updatedate": "04-JAN-2023" }, { "number": 119777777, "code": "H", "name": "Hospital funding.", "year": 2021, "updatedate": "04-JAN-2023" } ] }';
const obj = JSON.parse(string);
const arrayOfObjects = obj.items;
Been delivered some confusing JSON data with a problem I haven't seen before.
The JSON is formatted similar to this structure:
[
{
"title": "Event",
"start_date": "2022-08-20 15:00:00",
"end_date": "2022-08-20 16:00:00",
"branch": {
"85": "branchname"
},
"room": {
"156": "roomname"
},
"age_group": {
"5": "Youth",
"6": "Teen"
}
},
{
"title": "Event02",
"start_date": "2022-08-20 15:00:00",
"end_date": "2022-08-20 16:00:00",
"branch": {
"72": "branchname"
},
"room": {
"104": "roomname02"
},
"age_group": {
"5": "Youth",
"6": "Teen"
}
}
]
I'm trying to pull roomname out of the data, but it's nested in an object that has a random index number. If I manually put in the index number, I can retrieve the data, but the number changes every entry.
If I can figure out how to retrieve the number and store it in a variable, then use it again, or just somehow wildcard to just show any child of any key under the parent node "room" it would work perfect, but I don't know of a way to do this in javascript.
I'm limited to vanilla javascript, no external libraries or jquery.
here is the code that will output correctly if I manually enter the index numbers, but it only works for a single entry.
<script>
const url = 'example.json';
fetch(url)
.then((response) => {
return response.json();
})
.then((json) => {
json.map(function(event) {
console.log(`${event.start_date}`);
console.log(`${event.title}`);
console.log(`${event.room[156]}`);
return element;
});
}, 80);
</script>
EDIT: Forgot to point out, there is always only 1 entry in the "room" tag, but it's index is randomized, so if you just select the room tag it returns undefined or invalid. If I could wildcard the index so it just tries them all, or somehow retrieve the index number and store it in a variable, it would fix the issue.
I think this will work:
Here as you don't know the key so, instead of just guessing, you can use Object.values(JSONObjName) to get the list/array of values in that json.
Here I'm also using optional chaining (?.) to handle the case when the json has no key value pairs.
<script>
const url = 'example.json';
fetch(url)
.then((response) => {
return response.json();
})
.then((json) => {
json.map(function(event) {
const roomName = Object.values(event.room)?.[0];
console.log(`${event.start_date}`);
console.log(`${event.title}`);
console.log(`${roomName}`);
return {...event, room: roomName};
});
}, 80);
</script>
As long as you always want the first key you can fetch it like this
room = event.room[Object.keys(event.room)[0]]
if you want to get just roomname, you could do Object.values(room)[0]
or if you want the index and value you could go for Object.entries(room)[0]
arr?.map(({ room }) => {
for(let [key, value] of Object.entries(room)) {
console.log('Random Key : ',key)
console.log('Roomname : ', value)
console.log('Using random key : ',room[key])
}
})
By this way you can find the value of room against the random key.
Or you can try this if it is more relevant to you.
arr.map(({ room }) => {
for(let key of Object.keys(room)) {
console.log('Random Key : ',key)
console.log('Using random key : ',room[key])
}
})
Since you may want to do this for branch as well, here's an alternative solution which uses the object key as a computed property name (aka "dynamic key") to get the value.
And since, in this example it's done more than once, I've added that to a function that you can call in the destructuring assignment.
const data=[{title:"Event",start_date:"2022-08-20 15:00:00",end_date:"2022-08-20 16:00:00",branch:{85:"branchname"},room:{156:"roomname"},age_group:{5:"Youth",6:"Teen"}},{title:"Event02",start_date:"2022-08-20 15:00:00",end_date:"2022-08-20 16:00:00",branch:{72:"branchname02"},room:{104:"roomname02"},age_group:{5:"Youth",6:"Teen"}}];
// Get first key from an object
function getKey(obj) {
return Object.keys(obj)[0];
}
const out = data.map(obj => {
// Destructure the object and call `getKey` with the
// object to get its only key, and use that
// as a computed property to get its value, which
// we then relabel e.g. `roomName`
const {
branch: { [getKey(obj.branch)]: branchName },
room: { [getKey(obj.room)]: roomName },
...rest
} = obj;
// Now just return a new object with your new keys/values
return { ...rest, branchName, roomName };
});
console.log(out);
Additional documentation
Rest parameters
Spread syntax
I'm new in Vue js, and I have data in array object like below when I use vue-multiselect.
[
{
"id": 1,
"add_on_type": "Xtra",
"name": "test",
"price": 12,
"created_at": "2020-06-25 10:12:43",
"updated_at": "2020-06-25 10:12:43"
},
{
"id": 3,
"add_on_type": "Xtra",
"name": "Some x",
"price": 120,
"created_at": "2020-06-30 05:47:52",
"updated_at": "2020-06-30 05:47:52"
}
]
but in my function I need to access like key:value like below
"xtra": {
// key: value
0: 1
1: 3
}
but I get all array object instead of id only. I need to get the ID only in array, below is my code. I don't know how to get only id from array using below code.
this.$axios
.get("items/" + this.item)
.then(res => {
// below line is how I get the array object, but I need only id in array.
data.xtra = this.extra;
console.log(data);
})
.catch(err => {
throw err;
});
this maybe easy for some people, but I cannot find the way to to do. any help would be appreciated. thanks in advance
If I understood correctly your question, this.item is holding an object retrieved from the array. If is like this, it should be as easy as:
.get("items/" + this.item.id)
if you want to create new array you can do this at your return from axios
.then(res => {
let arr = res.data
this.xtra = arr.map(x =>
x.item.id)
})
First declare Items as reactive array in setup function
const tools = reactive([]);
Then in methods, retrieve
axios.get("/user-items").then(response => {
var items = [];
response.data.forEach((item, index) => {
items.push(item.id);
})
Object.assign(this.items, items);
});
I'm using a callable function from a client app to retrieve some data from firestore. The data is created using:
projectData = {
created: firebase.firestore.FieldValue.serverTimestamp(),
...otherData
}
firebase.firestore().collection(projectsCollection).add(projectData)
And I can see the timestamp is correctly saved in the firestore console. The callable function does some other things and has error handling, but the data retrieval is done like this (using lodash to expand each document into an object to return to the client):
const projectRef = firestore.collection(gProjectsCollection).orderBy('created')
return projectRef.get().then(snapshot => {
return {
projects: _.chain(snapshot.docs)
.keyBy('id')
.mapValues(s => s.data())
.value()
}
})
This mostly works, but the returned object has a mangled created property (shown here in functions shell output):
RESPONSE RECEIVED FROM FUNCTION: 200, {
"result": {
"projects": {
"XcRyQyaxLguRdbNmxQdn": {
"name": "c",
"description": "c",
"created": {
"_seconds": 1543405587,
"_nanoseconds": 169000000
}
}
}
}
}
I'm presuming this is because the callable function uses JSON.stringify() internally, and the server timestamp isn't converted correctly. I tried explicitly converting the timestamp to a date like this:
return projectRef.get().then(snapshot => {
return {
exVersion,
exId,
projects: _.chain(snapshot.docs)
.keyBy('id')
.mapValues(s => s.data())
.forEach(d => { d.created = d.created.toDate() })
.value()
}
})
but now I get an empty object back:
RESPONSE RECEIVED FROM FUNCTION: 200, {
"result": {
"projects": {
"XcRyQyaxLguRdbNmxQdn": {
"name": "c",
"description": "c",
"created": {}
}
}
}
}
I suspect the real problem here is that callable functions aren't set up to return date objects. If I go one more step and convert the timestamp into a string, I finally get something back in the client:
return projectRef.get().then(snapshot => {
return {
exVersion,
exId,
projects: _.chain(snapshot.docs)
.keyBy('id')
.mapValues(s => s.data())
.forEach(d => { d.created = d.created.toDate().toISOString() })
.value()
}
})
gives:
RESPONSE RECEIVED FROM FUNCTION: 200, {
"result": {
"exVersion": 9,
"exId": null,
"projects": {
"XcRyQyaxLguRdbNmxQdn": {
"name": "c",
"description": "c",
"created": "2018-11-28T11:46:27.169Z"
}
}
}
}
I couldn't find anything in the documentation for callable functions about special handling for dates, but am I missing something in how this should be done?
Some further analysis in the callable function suggests JSON.stringify() is involved, but isn't the whole problem:
console.log(JSON.stringify(d.created)):
info: {"_seconds":1543405587,"_nanoseconds":169000000}
JSON.stringify(d.created.toDate())
into: "2018-11-28T11:46:27.169Z"
So calling d.created.toDate() should be sufficient. But I've had other cases where Date objects are just not returned by callable functions, e.g.:
const testObject = {
some: 'thing',
d: new Date()
}
console.log('JSON:', JSON.stringify(testObject))
return projectRef.get().then(snapshot => {
return {
testObject,
projects: _.chain(snapshot.docs)
.keyBy('id')
.mapValues(s => s.data())
.forEach(d => { console.log('d.created is:', JSON.stringify(d.created.toDate())); d.created = d.created.toDate() })
.value()
}
})
Note in the output below, the logged results of JSON.stringify() on date objects seems to work, but when those objects are contained within the object returned from the function, they both come out as empty objects:
firebase > getAllProjects({uid: 1234})
Sent request to function.
firebase > info: User function triggered, starting execution
info: JSON: {"some":"thing","d":"2018-11-28T13:22:36.841Z"}
info: Got 1 projects
info: d.created is: "2018-11-28T11:46:27.169Z"
info: Execution took 927 ms, user function completed successfully
RESPONSE RECEIVED FROM FUNCTION: 200, {
"result": {
"testObject": {
"some": "thing",
"d": {}
},
"projects": {
"XcRyQyaxLguRdbNmxQdn": {
"description": "c",
"created": {},
"name": "c"
}
}
}
}
From the documentation:
To send data back to the client, return data that can be JSON encoded.
Since Date is not a JSON type, you will have to use your own serialization format for it (at least if you want it to be reliable/portable). From the linked answer it sounds like Date.toJSON is a great candidate for that.