How to access elements of Firebase Snapshot? - javascript

I have a Firebase database that looks like this:
masterSheet
0
0: 0
1: "What is your favorite type of dog?"
2: "Some values"
3: "Some more values"
4: "Blah blah"
5: "Animals"
1
0: 1
1: "What's 2 + 2?"
I'm using this code to retrieve a snapshot of the databse.
var database = firebase.database();
var ref = database.ref('masterSheet')
ref.on("value", function (snapshot) {
snapshot.forEach(function(childSnapshot) {
var data = childSnapshot.val();
console.log(data);
})
})
This seems to work, as when I run it in a browser and do inspect element > console, I can see:
(6) [0, "What is your favorite type of dog?", "Some values", etc
(6) [1, "What's 2 + 2?", "Some values", etc
The problem is that I can't seem to access this data like a normal JavaScript object. I'm using this for a web app quiz, and need to be able to access each question individually and the associated values.
If I try to access the first value in the object with console.log(data[0]), this is the result:
0
1
2
3
4
etc
Which seems right, but if I do data[1], the result is "undefined."
What am I doing wrong here? Basically I need to make a list of dictionary objects, or a nested dictionary, or something where I can access each question by calling the index/number associated with it. I would like to be able to make an object where the keys are the question numbers (0-indexed) and then the rest of the values are in nested dictionaries within that object.
But for the last couple days I've been trying to figure out how to access this Firebase snapshot and just can't figure out the structure.
Edit: Here is the structure of my JSON.
{
"masterSheet" : [ [ 0, "What's 2+2?", "22", "4", "6", "Math question" ], [ 1, "What's the capital of Nevada?", "Reno", "Las Vegas", "Carson City", "Geography" ], [ 2, "What's the meaning of life?", "40", "41", "42", "Philosophy" ] ]
}

Related

JSON.parse: unexpected character at line 1 column 2 of the JSON data

I'm trying to make a quiz with HTML, CSS and JavaScript.
Now i'm trying to see if the jsonData works but i get this error message
but i can't find where the unecpected character is (it says line 1 column 2) but don't see it
Other thing am i doing it good?
I just started this year with coding
var jsonData = [
{
"q1": {
"question": "what is the Capital city of Australia ",
"answers": {
"a": "Melbourne",
"b": "Sydney",
"c": "Caneberra",
"d": "Brisbane"
},
"correctAnswers": "c"
}
},
]
const me = JSON.parse(jsonData)
console.log(me.correctAnswers);
The problems have already been pointed out in the comments by T.J Crowder and Samball, but I wanted to show you the difference between a JavaScript data structure and a JSON string that needs to be parsed so you can better understand their comments.
A JSON string needs to be parsed to JavaScript data structure (array, objects, values) for you to be able to work with the data stored in the file properly
A JavaScript object/ array etc. that you define in JavaScript is already an JavaScript data structure so no need to parse it. Please note, any valid JSON is also valid JavaScript, but not the other way round.
Here a small program to illustrate what I've just written.
// this needs to be parsed so you can access it as JS data structures
const stringData = `[
{
"q1": {
"question": "what is the Capital city of Australia ",
"answers": {
"a": "Melbourne",
"b": "Sydney",
"c": "Caneberra",
"d": "Brisbane"
},
"correctAnswers": "c"
}
}
]`;
// no need for this to be parsed, as it already is a JS data strucure (an array in this case)
const alreadyJavaScript = [
{
"q1": {
"question": "what is the Capital city of Australia ",
"answers": {
"a": "Melbourne",
"b": "Sydney",
"c": "Caneberra",
"d": "Brisbane"
},
"correctAnswers": "c"
}
}, // In JavaScript this comma is fine, in JSON it is not!
]
// parse string
const me = JSON.parse(stringData)
// now print both to see that they are in fact identical
// Keep in mind it's an array not an object!
console.log(me[0]);
console.log(alreadyJavaScript[0])
Note: While it is perfectly fine to put a , at the end of the last element in JavaScript, JSON does not allow that!

Code by Zapier to loop through an array of objects, pulling out one value per object and then average those values

Using JavaScript for Zapier, I am trying to calculate the average value of a property from an array of object.
Here is one of the objects...
{
"code": 0,
"data": [
{
"id": "28737",
"owner": "1",
"date": "1581945706",
"dla": "0",
"dlm": "1582551517",
"system_source": "3",
"source_location": null,
"ip_addy": null,
"ip_addy_display": null,
"import_id": "0",
"contact_cat": "*/*",
"bulk_mail": "1",
"bulk_sms": "0",
"bindex": "76",
"f1849": "9898983",
"f1850": "Foundation Course 2: Lecture 1 QUIZ",
"f1851": "0",
"f1853": "John Doe",
"f1854": "TRUE",
"f1855": "93", // <= calculate average for this property
"f1859": "292",
"f1862": "0",
"f1867": "Kajabi",
"f1868": "0",
"unique_id": "7WB77PT"
},
...
]
}
I need to pull out the value for the property named f1855 for each object, then calculate the average and return that value via POST.
I don't think this is hard to do with JavaScript but I am not used to the rules and limits of Zapier.
Any help appreciated!
**Seeing the edited version of your post, I am now not sure if your input data is the data array inside the example or it is an array of those objects. If the second, then I don't know if you want an average for each object's data prop. or something else. But the code below could be part of the solution in either case.
I don't know anything about Zapier, but the JavaScript part could look something like this:
const inputData = //your array of objects
const reducer = (sum, theObject) => sum + parseFloat(theObject.f1855)
const sumF1855 = inputData.reduce(reducer, 0)
const avgF1855 = sumF1855 / inputData.length
This code does not handle error conditions (like if on of the objects were missing the f1855 property or divide by zero if inputData were empty). Hopefully it gives you an idea to get started.

How to acces to the data from several json objects inside an array position

I'm making a little app in nodejs, I'm struggling trying to print some data provenient from a json which has the following structure:
{
"courses": [
{
"java": [
{ "attendees": 43 },
{ "subject": "Crash course" }
]
},
{
"python":
{
"occurrences": [
{ "attendees": 24 },
{ "subject": "another crash course" },
{ "notes": "completed with issues" }
,
{ "attendees": 30 },
{ "subject": "another crash course" },
{ "notes": "completed with issues" }
]
}
}
],
}
If I want to print the attendees at 'java' I do:
console.log(myJSON.courses[0]['java'][0]['attendees']);
which prints
43
and if I want to print the notes of the 2nd occurrence of the python course I do:
console.log(myJSON.courses[1]['python']['occurrences'][2]['notes']);
which prints:
completed with issues
The before mentioned cases are correct, but what I want to do is to print the keys of 'java' ('attendees' and 'subject'), as you can see Java is an array and in its unique position it has two json objects, I've tried with:
console.log(myJSON.courses[0]['java'][0].keys;
and with
console.log(myJSON.courses[0]['java'].keys;
but they print "undefined" and "[Function: keys]" respectively.
What I'm missing here?
Could anybody help me please?:(
myJSON.courses[0]['java'] is an array with indexes. Where each index holds an object with keys. Your array doesn't exactly have the keys you want (the keys of an array are its indexes: 0, 1 etc...)
Instead, you want to access all the keys from the objects in the myJSON.courses[0]['java'] array.
You can do this by using .map and Object.keys. .map will allow you to get and convert every object in your myJSON.courses[0]['java'] array. Object.keys() will allow you to get an array of keys from the given object (in your case your array will be of length 1, and so you can access index 0 of this array).
const myJSON = {courses:[{java:[{attendees:43},{subject:"Crash course"}]},{python:{occurrences:[{attendees:24},{subject:"another crash course"},{notes:"completed with issues"},{attendees:30},{subject:"another crash course"},{notes:"completed with issues"}]}}]};
const myKeys = myJSON.courses[0]['java'].map(obj => Object.keys(obj)[0]);
console.log(myKeys);
If you have multiple keys in your objects within an array, you can also use .flatMap (take note of browser support):
const myJSON = {courses:[{java:[{attendees:43},{subject:"Crash course"}]},{python:{occurrences:[{attendees:24},{subject:"another crash course"},{notes:"completed with issues"},{attendees:30},{subject:"another crash course"},{notes:"completed with issues"}]}}]};
const myKeys = myJSON.courses[0]['java'].flatMap(Object.keys);
console.log(myKeys);

Using nested mapping within Observable subscription - Angular6

I am fetching some data via an API call (within my dataservicse.ts file) - and the response I get is a sort of complex JSON structure. I am able to fetch a specific part of the response as follows in my corresponding Component file as follows -
Here is one of the JSON object response that represents the general structure -
{
"address": {
"building": "1234",
"coord": [0, 0],
"street": "123 Main Street",
"zipcode": "00000"
},
"address2": "Test Suite 000",
"grades": [{
"grade": "A",
"score": 3
}, {
"grade": "B",
"score": 4
}, {
"grade": "A",
"score": 2
}],
"name": "John Doe",
"_id": "1212121"
}
Now - my goal is to acquire the 'name' attribute as well as the first 'grade' value within the grades attribute from each response object - and map them into separate Arrays so that I can display them in table columns using *ngFor.
This is my Component code
export class TestDataComponent implements OnInit {
name$: Object;
grade$: Object;
constructor(private data: DataService, private data2: DataService) { }
ngOnInit() {
//getAPIData is returning the API response from the dataservices.ts file
this.data.getAPIData().subscribe(
data=>console.log(data.response.map(name=>name.name))
); //this works fine - I get the names in an array
this.data2.getAPIData().subscribe(
data2=>console.log((data2.response.map(grade=>grade.grades)).map(grades
=> {grades.map((value, index) => value.grade})) //this returns an undefined value
);
}
Now - if I console.log((data2.response.map(grade=>grade.grades))
I get an Array of Array objects such as -
Array - [Array(3), Array(3), Array(2)]
and each of them consist of the 'grades' attribute Array of objects.
(taking the first array from above) -
Array(3)
0:{"grade": "A","score": 3}
1:{"grade": "B", "score": 4}
2:{"grade": "A", "score": 2}
Thus - I further map my initial response to achieve the 'grade' value. Also - I only want the first grade - thus I have a simple condition added as follows -
console.log((data2.response.map(grade=>grade.grades))
.map(grades
=> {grades.map((value, index) =>{if(index<1) value.grade})}))
As mentioned in the comment - I get an undefined value.
I undestand this issue may be fairly complex but I've tried my best to explain it as clearly as possible. My goal is to get the first 'grade' values from each object and display them in an Array - just as the names, so that I can use it to display it on a table.
I am fairly new to Angular6, just switching from Angular 1.6 - so I am pretty sure I am messing something up.
What would be the best way to get the grade values into an Array by nested mapping within subscribe? Or is there a better approach to the same ?
Also - for the sake of simplicity, ignore the fact that the first subscription is present (for the name attribute) - I showed it here so as to make it clear as to what I want to achieve.
Here is what I think you're asking for since you never gave a concrete example of what you're trying to map/reduce. Also, this is vanilla JavaScript but could easily be translated into RxJS.
// I am assuming that a call to `DataServce.getAPIData()` returns an array
const api_response = [{
"address": {
"building": "1234",
"coord": [0, 0],
"street": "123 Main Street",
"zipcode": "00000"
},
"address2": "Test Suite 000",
"grades": [{
"grade": "A",
"score": 3
}, {
"grade": "B",
"score": 4
}, {
"grade": "A",
"score": 2
}],
"name": "John Doe",
"_id": "1212121"
}];
// Map and pluck the values you need
const result = api_response.map(v => [v.name, v.grades[0].score])
// Or as an array of objects
const obj_result = result.map(([name, score]) => ({ name, score }))
// Is this what you want?
console.log('Array', result);
console.log('Objects', obj_result);
Quick Update
Thanks for accepting the answer. Just wanted to give a quick of what this might look like using RxJS. I say might because the code snippet below is untested.
this.nameAndScores$ = data.getAPIData().pipe(
map(({ response }) => response),
map(({ name, grades }) => ( { name, score: grades[0].score } ))
)
Assuming that nameAndScores$ is a property of your component instance, you can do *ngFor item in nameAndScores$ | async and avoid any explicit subscriptions in your code.
You are using curly braces with a fat arrow in second map function. While using curly braces, you should return a value using the return keyword.

Year as an index

I had this dictionary
"name" : {
"2016" : {
"1" : "info"
}
}
I added it to sessionStorage using json.stringfy and it worked perfectly. I then appended another dictionary to the first one:
name: {
2016: {
1: {
info: {
0: {
"question": "qs1",
"information": "info1"
},
1: {
"question": "qs12",
"information": "info2"
},
}
}
}
}
and I did the same convert to a string using json.stringfy. Then I noticed this:
name: {
0 : "2016",
1 : null,
2 : null, //until 2016
2016: {
1: {
info: {
0: {
"question": "qs1",
"information": "info1"
},
1: {
"question": "qs12",
"information": "info2"
},
}
}
}
I don't know why it's counting when the typeof tells me that it's a string, not a number. Also, I don't understand why it didn't do this with the first dictionary.
Here is the code:
(function($){
x = {
"info": {
"0": {
"question": "qs1",
"information": "info1"
},
"1": {
"question": "qs12",
"information": "info2"
},
}
}
var sesion = {};
var stringinfo;
sesion["name"]=["2016"];
sesion["name"]["2016"]=["1"];
sesion["name"]["2016"]["1"] = x;
stringinfo = json.stringfy(sesion);
console.log(sesion);
console.log(stringinfo)
}(jQuery))
Try it and tell me if using a number(string) as an index does that! How can I resolve this? Thank you.
you are confusing arrays ([]) and objects ({}). At the beginning you say:
I got this array:
"name" : {
"2016" : {
"1" : "info"
}
But this is an object.
Your question is a bit difficult to follow. But if you instantiate an empty array, and tell it that numer 2016 should have a certain value, it will fill up the rest with empty (null) values.
You want to use an object, rather than an array.
Look at your code where objects and arrays get mixed up. You want to be using an object, with the key "2016", not an array which uses numbers as indexes.
added information after reviewing supplied code
(btw I fixed spelling of 'sesion' to 'session' in explanation below)
the line:
var session = {}
makes an empty object. The line:
session["name"]=["2016"];
sets the property "name" of this object to be an array containing the only string "2016".
Now it gets interesting; you just made the name property an array, so the line
session["name"]["2016"]=["1"];
makes the compiler use the following logic; since session["name"] is an array, you probably don't mean to set a property on it when you refer to session["name"]["2016"]; the string "2016" gets coerced to a number and it puts a new array on it, containing the string "1".
At this point I must point out that your code is not running, and after fixing it the output is not like you put it in your question. What happens after is the same as before, just you put in the new array at the 1st spot your object in x.
The main problem in your code as stated before sits in mixing arrays and objects.
replace the line
session["name"]=["2016"];
for example with:
session["name"] = {}
to instantiate an object on which you can put properties such as "2016", and I am not sure what the exact objective is, but if you want to make an array under this property, do it something like:
session["name"]["2016"]=[x];

Categories