How to iterate through firebase object childeren - javascript

I am new to firebase and javascript but I am trying to iterrate through my firebase database which really just has 1 object and some childeren under it. I followed some tutorials but feel like im in a rabbit hole right now. I only get the top levels back and not the childeren
This is what i tried:
var ref = database.ref('Exercise');
ref.on('value', gotData, errData);
function writeData(){
firebase.database().ref("Exercise").set({
nameExercise: exerciseName.value,
setAm: setAmount,
// setAm: {
// HoeveelheidArr,
// Gewicht,
//}
repetitie: Gewicht,
hoeveelheidKilogram:Gewicht,
});
}
var ref = database.ref('Exercise');
ref.on('value', gotData, errData);
function gotData(data){
//console.log(data.val());
var exercise = data.val();
var keys = Object.keys(exercise);
console.log(keys);
for( var i = 0; i < keys.length; i++){
var k = keys[i];
var exerciseID = scores[k].nameExercise.value;
var sets = scores [k].setAm.value;
var reps = scores[k].repetitie.value;
var kg = scores [k].hoeveelheidKilogram.value;
console.log(exerciseID, sets,reps,kg);
}
}
function errData(err){
console.log('Error!');
console.log(err);
}
the write function works well but not the gotData where im trying to display every value of the object in the console:
but all im getting back is teh variable names from the writeData function. Do you see what i do wrong?

As far as I can see you have only a single exercise under /Exercise, which means that the for( var i = 0; i < keys.length; i++){ loop is not needed.
An example of how to access/log various parts of your JSON:
function gotData(data){
var exercise = data.val();
console.log(exercise);
console.log(exercise.hoeveelheidKilogram);
exercise.hoeveelheidKilogram.forEach(function(value) {
console.log(value);
});
}

Related

JS - object contains array name

I have the following challenge:
I have an object which contains data from internal projects. Some projects are billable and some are not.
This data is gathered from the API in Google Spreadsheets which would like to push into an array so I can display it on my sheets.
When a project [i] is not a billable project jsonObject.data[i].budget.hours.amount_budget] would not be in the object. and thefore it would return an error.
Is there a way to ask in Javascript/AppScript if the array item contains budget.hours.amount_budget for item `[i]?
Thanks in advance
var i = 0
var arrayProjectManagerName = [];
var arrayOrganizationName = [];
var arrayProjectName = [];
var arrayBudgetHoursAmountBudget = [];
var arrayBudgetHoursAmountSpent = [];
var arrayBudgetHoursValuBudget= [];
var arrayBudgetHoursValueSpent= [];
var arrayBudgetCostsValueBudget = [];
var arrayBudgetCostsValueSpent = [];
var arrayBudgetTotalValueBudget = [];
var arrayBudgetTotalValueSpent= [];
var arrayBudgetTotalValueInvoiced= [];
for (i; i < jsonObject.data.length; i++){
arrayProjectManagerName.push([jsonObject.data[i].project_manager.name])
arrayOrganizationName.push([jsonObject.data[i].organization.name])
arrayProjectName.push([jsonObject.data[i].name])
//arrayBudgetHoursAmountBudget.push([jsonObject.data[i].budget.hours.amount_budget])
//arrayBudgetHoursAmountSpent.push([jsonObject.data[i].budget.hours.amount_spent])
//arrayBudgetHoursValuBudget.push([jsonObject.data[i].budget.hours.value_budget])
//arrayBudgetHoursValueSpent.push([jsonObject.data[i].budget.hours.value_spent])
arrayBudgetCostsValueBudget.push([jsonObject.data[i].budget.costs.value_budget])
arrayBudgetCostsValueSpent.push([jsonObject.data[i].budget.costs.value_spent])
arrayBudgetTotalValueBudget.push([jsonObject.data[i].budget.total.value_budget])
arrayBudgetTotalValueSpent.push([jsonObject.data[i].budget.total.value_spent])
arrayBudgetTotalValueInvoiced.push([jsonObject.data[i].budget.total.value_invoiced])
}
You can use Object.prototype.hasOwnProperty
You can nest this in line like
jsonObject.data[i].hasOwnProperty('budget') && jsonObject.data[i].budget.hasOwnProperty('hours') && jsonObject.data[i].budget.hours.hasOwnProperty('amount_budget')
Alternatively you could make a helper function which will check deep for you to avoid repeating this logic again and again
hasProperty = (obj, property) => {
if(!property){
return true;
}
let props = property.split('.');
return obj.hasOwnProperty(props[0]) && hasProperty(obj[props[0]], props.splice(1).join('.'));
}
You can find further suggestions in this SO question

Cant access variable inside of firebase gotData() function outside

I want to get the value of power_level value on the last line of the below mentioned code but it is not showing anything. I need that value for further use what to do.
var config = {
//
};
firebase.initializeApp(config);
var database = firebase.database();
var ref = database.ref("power");
ref.on("value", gotData, errData);
var power_level;
function gotData(data) {
var power = data.val();
// Grab the keys to iterate over the object
var keys = Object.keys(power);
console.log(keys);
for (var i = keys.length - 1; i < keys.length; i++) {
var key = keys[i];
// Look at each fruit object!
var power_level = power[key];
console.log(power_level);
}
}
console.log(power_level);
The reason you don't get the value on the last line is because it is asynchronous. Basically you do ref.on and it runs the gotData() function if (and more importantly WHEN) it is successful, but your last console.log() runs regardless of whether gotData() is finished.
An easy way to handle this is by defining a separate function which takes power_level as a parameter and handles the power_level, and run that at the end of gotData().
Something like this:
var config = {
//
};
firebase.initializeApp(config);
var database = firebase.database();
var ref = database.ref("power");
ref.on("value", gotData, errData);
var power_level;
function gotData(data) {
var power = data.val();
// Grab the keys to iterate over the object
var keys = Object.keys(power);
console.log(keys);
for (var i = keys.length-1; i < keys.length; i++) {
var key = keys[i];
// Look at each fruit object!
var power_level = power[key];
console.log(power_level);
////////// call handlePowerlevel here to handle logic further
handlePowerlevel(power_level)
}
}
function handlePowerlevel(pl) {
console.log(pl);
// actual logic
}

Why is Data Null?

I came across an error today, and I am not sure why it occurred. At the second for loop, the access to data will be undefined instead of the data that was inserted as a parameter into the function. Somehow the data gets the value of null, instead of the Object that was passed to this function. Does anyone know why? The error I get is "data is not defined".
createDataObject: function (data) {
let dataObj = data.source[0];
let backedData = data.backedData;
for (let i in dataObj) {
let d = dataObj[i];
d.data = { source: d.data };
}
for (let i = 0; i < data.backedData.length; i++) {
let bd = data.backedData[i]; //<- this is where the error occurrs
let data = bd.data[0];
}
}
Here is some code outside of the object, if you want to try, that I was using, this will work on your console or in node. Seems like I have come across a Javascript compiler bug. I am not sure.
createDataObject({source: [[{data: 1}]], backedData: [1,2,3, 4]});
The code above will work if I do the following
createDataObject: function (data) {
let dataObj = data.source[0];
let backedData = data.backedData; //create the backedData variable here
for (let i in dataObj) {
let d = dataObj[i];
d.data = { source: d.data };
}
for (let i = 0; i < backedData.length; i++) {
let bd = backedData[i]; // no Error
let data = bd.data[0];
//.....
}
}
in the second for loop you create another data object. Data is not created on the first line in the for loop.
Try using
for (let i = 0; i < data.backedData.length; i++) {
let bd = data.backedData[i];
let d= bd.data[0]; // Convert data to d or another variable name
//.....
}

js Array undefined after json declaration

I m new a web developer and i face up the following problem:
"Cannot read property 'length' of undefined"
my code:
var data=();
for(var i;i<parseInt(window.localStorage["numOfInserts"]);i++){
data["category_name"]=localStorage.getItem(("category_name_"+i).toString());
data["category_id"]=localStorage.getItem(("category_id_"+i).toString());
data["provider_name"]=localStorage.getItem(("provider_name_"+i).toString());
data["provider_id"]=localStorage.getItem(("provider_id_"+i).toString());
data["appointment_date"]=localStorage.getItem(("appointment_date_"+i).toString());
data["appointment_time"]=localStorage.getItem(("appointment_time_"+i).toString());
}
$scope.allAppointments=dataArray;
for(var i=0;i<dataArray.length;i++){
$scope.showme[i]=false;
}
After some research I understand that the problem caused to the fact that data is an array but I try to turn it to json, but
var data ={};
gives me the same error as before.
Please Help me
I think this is what you're looking for, see code comments:
// Create an array using []
var data = [];
// Get the count once
var count = parseInt(window.localStorage["numOfInserts"]);
// Be sure to initialize `i` to 0
for (var i = 0; i < count; i++) {
// Create an object to push onto the array, using the information
// from local storage. Note that you don't need toString() here.
// Once we've created the object (the {...} bit), we push it onto
// the array
data.push({
category_name: localStorage.getItem("category_name_"+i),
category_id: localStorage.getItem("category_id_"+i),
provider_name: localStorage.getItem("provider_name_"+i),
provider_id: localStorage.getItem("provider_id_"+i),
appointment_date: localStorage.getItem("appointment_date_"+i),
appointment_time: localStorage.getItem("appointment_time_"+i)
});
}
This does the same thing, it's just more verbose and so could help you understand more clearly what's going on:
// Create an array using []
var data = [];
// Get the count once
var count = parseInt(window.localStorage["numOfInserts"]);
// Be sure to initialize `i` to 0
for (var i = 0; i < count; i++) {
// Create an object to push onto the array
var obj = {};
// Fill it in from local storage. Note that you don't need toString() here.
obj.category_name = localStorage.getItem("category_name_"+i);
obj.category_id = localStorage.getItem("category_id_"+i);
obj.provider_name = localStorage.getItem("provider_name_"+i);
obj.provider_id = localStorage.getItem("provider_id_"+i);
obj.appointment_date = localStorage.getItem("appointment_date_"+i);
obj.appointment_time = localStorage.getItem("appointment_time_"+i);
// Push the object onto the array
data.push(obj);
}
You need to create an array(dataArray before the loop), and create a new object in each iteration and set the property values for that object then add the object to the array like below
var dataArray = [],
data, numOfInserts = parseInt(window.localStorage["numOfInserts"]);
for (var i = 0; i < numOfInserts; i++) {
data = {};
data["category_name"] = localStorage.getItem(("category_name_" + i).toString());
data["category_id"] = localStorage.getItem(("category_id_" + i).toString());
data["provider_name"] = localStorage.getItem(("provider_name_" + i).toString());
data["provider_id"] = localStorage.getItem(("provider_id_" + i).toString());
data["appointment_date"] = localStorage.getItem(("appointment_date_" + i).toString());
data["appointment_time"] = localStorage.getItem(("appointment_time_" + i).toString());
dataArray.push(data)
}
$scope.allAppointments = dataArray;
for (var i = 0; i < dataArray.length; i++) {
$scope.showme[i] = false;
}
It looks like you're trying to create an associative array, so the first line should indeed be
var data = {};
The next part is fine, but then it looks like you want to enumerate the keys
for(var i=0;i<Object.keys(data).length;i++){
$scope.showme[i]=false;
}

Best way to iterate and make an async call during each iteration

If you have to loop and make a bunch of calls to a repository or gateway in my case, how do I do that asynchronously meaning not wrapping my async calls inside a synchronous for loop?
For example, what would be a better approach (restructuring this code) to loop through a set of ids, and make the call to find() below like I'm trying to do?
The goal: I want to take an array of ids, iterate them, and during each iteration, use the id to call find() on my gateway to go get the object for that id, then stuff it into a final array in which I'll return when all said and done.
What I'm using:
q (for promises)
co-pg (to hit the database)
someModule.js
var _gateway = require('./database/someGateway');
var cars = [];
var car;
for (var i = 0; i < results.docs.length; i++){
var carId = results.docs[i].carId;
_gateway.find(carId)
.then(function(data){
console.log('data[0]: ' + data[0].id);
cars.push(data[0]);
})
.done();
}
console.log("cars: " + cars.length); // length here is 0 because my asyn calls weren't done yet
result(cars);
someGateway.js
'use strict';
var Q = require('q');
var _carModel = require('../../models/car');
module.exports = {
models: {
car: _carModel
},
find: _find
};
function _find(carId)
{
return _carModel.find(carId);
};
carModel.js
'use strict';
var Q = require('q');
var pg = require('co-pg')(require('pg'));
var config = require('../../models/database-config');
var car = module.exports = {};
car.find = Q.async(function *(id)
{
var query = 'SELECT id, title, description FROM car WHERE id = ' + id;
var connectionResults = yield pg.connectPromise(config.connection);
var client = connectionResults[0];
var done = connectionResults[1];
var result = yield client.queryPromise(query);
done();
console.log("result.rows[0].id: " + result.rows[0].id);
return result.rows;
});
so I need help understanding how to refactor my code in someModule.js to get that working properly, so that I make a call to find() for each id, stuff each found car into the array, then return the array. The carModel code is async. It goes out to a physical database to perform the actual query lookup.
UPDATE #1
Ok after a couple more hours of trying all sorts of sh** (q.all(), and a ton of other combinations of callback code, etc.) here's what I have at this point:
someModule.js
var _data;
var Q = require('q');
var _solrClient = require('../models/solr/query');
var _solrEndpoint = "q=_text&indent=true&rows=10";
var _postgreSQLGateway = require('./database/postgreSQLGateway');
module.exports = {
data: function(data){
_data = data;
},
find: function (text, result){
if(!searchText){
result(null);
};
_solrClient.query(endpoint, function(results){
var carIds = [];
var cars = [];
var car;
for (var i = 0; i < results.docs.length; i++){
carIds.push(results.docs[i].carId);
}
for (var i = 0; i < carIds.length; i++) {
var car = _postgreSQLGateway.find(carIds[i], function(o){
console.log("i: " + i);
});
};
});
}
};
someGateway.js
'use strict';
var Q = require('q');
var _carModel = require('../../models/postgreSQL/car');
module.exports = {
models: {
car: _carModel
},
find: _find
};
function _find(carId, foundCar)
{
console.log("CALL MADE");
_carModel.find(carId)
.then(function(car){
console.log("car: " + car[0].id);
foundCar(car);
});
};
carModel.js
[same code, has not changed]
Of course I noticed that the for loop fires off all my function calls asyncronously and so when I console.write the i, it's 10 because the for loop is done but then as we know, the rest of the console.logs happen later after the callbacks are done.
So I still can't get this working right...
Also when I was playing around I started down this path but it ended at a brick wall:
var find = Q.async(function(carIds, cars)
{
var tasks = [];
var foundCars = [];
for (var i = 0; i < carIds.length; i++) {
tasks.push(_postgreSQLGateway.find(carIds[' + i + ']));
};
Q.all([tasks.join()]).done(function (values) {
for (var i = 0; i < values.length; i++) {
console.log("VALUES: " + values[0]);
foundCars.push(values[0]);
}
cars(foundCars);
});
});
I ended up with [object promise] every time for values[i] instead of a car for value[i]
I don't know the Q promises library, but here's a solution using generic Promises built into node.js. This runs all the requests in parallel and then when all results have been collected, it runs the final .then() handler with all the results:
var _gateway = require('./database/someGateway');
var promises = [];
for (var i = 0; i < results.docs.length; i++) {
promises.push(_gateway.find(results.docs[i].carId).then(function (data) {
console.log('data[0]: ' + data[0].id);
return data[0];
}));
}
Promise.all(promises).then(function(cars) {
// cars will be an array of results in order
console.log("cars: " + cars.length);
result(cars);
});
Individual promise libraries (like the one I know Bluebird) have features built in that lets you do this kind of activity in even less code, but I've intentionally kept this answer to just using standard promise features.
This is potentially really easy with the vanilla Promise API from es6 (and replicated by Bluebird and other libs). First map the IDs to an array of promises:
var promises = results.docs.map(function(doc) {
return _gateway.find(doc.carId);
});
Then create a promise for the aggregate result:
var allDone = Promise.all(promises);
Then inside the done() callback of the aggregate promise, you'll have a final array of results, in the same length and order as the carId array:
allDone.then(function(results) {
// do something with "results"
});

Categories

Resources