I'm trying to wrap my brain around promises and I'm refactoring some nested callbacks into promises. I'm encountering something I don't understand and any help anyone could provide would be appreciated. There's definitely something wrong with my for-loop; I suppose that sort of structure is invalid but I'm not sure what to do about it. Also, the result coming back from insertTickersDb function appears to take my entire array and insert it as a single record - not what I was hoping for. I know I'm doing things wrong - please help me understand which things.
I have bound a function to mongoose like this:
var insertTickersDb = q.nfbind(db.tickers.insert.bind(db.tickers));
I have an insert function that looks like this:
function insertTickers(symbols) {
console.log("inserting tickers");
if (symbols) {
if (!(symbols instanceof Array)) {
symbols = [symbols];
}
var tickersToInsert = [];
symbols.map(function(symbol) {
tickersToInsert.push({
symbol: symbol
});
});
console.log("tickersToInsert = " + JSON.stringify(tickersToInsert));
return insertTickersDb(tickersToInsert);
}
}
and I have a test like this:
describe("tickerIntegrationTests internal testing tools", function() {
it("insertTickers should insert the provided tickers", function(done) {
var tickerList = ["A", "B", "C"];
insertTickers(tickerList).then(function(data) {
console.log("inside insertTickers, data = " + JSON.stringify(data));
for (var d = 0; d < data.length; d++) {
console.log("d = " + d + ",data[d].symbol = " + data[d].symbol);
assert.equal(data[d].symbol, tickerList[d]);
}
}).then(removeTickers(tickerList)).done(function(){done();});
});
});
My output is:
tickerIntegrationTests internal testing tools
inserting tickers
tickersToInsert = [{"symbol":"A"},{"symbol":"B"},{"symbol":"C"}]
inside insertTickers, data = [[{"symbol":"A","_id":"552faf5c0aac9578428320da"},{"symbol":"B","_id":"552faf5c0aac9578428320db"},{"symbol":"C","_id":"552faf5c0aac9578428320dc"}],{"n":0}]
d = 0,data[d].symbol = undefined
It might help if you expand out the json of the inner call
[
[
{
"symbol": "A",
"_id": "552faf5c0aac9578428320da"
},
{
"symbol": "B",
"_id": "552faf5c0aac9578428320db"
},
{
"symbol": "C",
"_id": "552faf5c0aac9578428320dc"
}
],
{
"n": 0
}
]
Now you can see the the data is an array whose first element is the data array you are expecting. If you looked at data[0] you would find the first ticker. d[0].symbol should contain what you are looking for. You might want to look at t
Related
nested json structure
Json Structure:
{
"id": "30080",
"dataelements": {
"Name": "abc",
},
"children": [
{
"id": "33024",
"dataelements": {
"Name": "a",
},
"children": [
{
"id": "33024",
"dataelements": {
"Name": "b"
},
"children": [
{
"id": "33024",
"dataelements": {
"Name": "z"
},
"children": []
}
]
}
]
},
{
"id": "4800",
"dataelements": {
"Name": "d"
},
"children": [
{
"id": "4800",
"dataelements": {
.........................
I have my nested json data as shown in the image. For every child object, I create a node model. A child object can have additional child objects inside it.
if (ele == "dataelements")
{
var categoryNode = new NodeModel(
{
label: row.dataelements.Name,
icons: [{ iconName: 'product'}],
grid: row[ele]
});
}
if(ele == "children")
{
var subCategoryNode;
var subCategoryIndex = 1;
for (var i = 0, len = row.children.length; i<len; i++)
{
subCategoryNode = new NodeModel(
{
label: row.children[i].dataelements.Name,
icons: [{
iconName: '3dpart' }],
grid: row.children[i].dataelements
});
categoryNode.addChild(subCategoryNode);
}
}
This code handles only one level of child nodes.
How do I check for the inner children when I don't know exactly how many child levels are nested inside?
A quick run down on recursive functions and a gotcha to look out for
Recursive functions are great for nested data
They call themselves for each iteration of the input until it hits a base case
They can be tricky to wrap your head around at first
Recursive functions can hit the call stack limit if used poorly or the input is monstrous in size
Look out for variables used in the recursive calls, use let keyword to tell javascript to set the variable in the current scope
The Solution
Let's assume your JSON has been validated and this is the structure in the example below.
If I want to iterate through all elements in the JSON, I want to use a recursive call to make it neat, and simple to debug and simple to build on.
Here is an example of iterating through your given example JSON to print out an exploded view.
How to use the below code
Copy the recursiveSearch function
Call the recursiveSearch function passing in your JSON
Modify it to your needs, I gave you something to build on
CODE
var someJson = {"id": "30080","dataelements": {"Name": "abc"},"children": [{"id": "33024","dataelements": {"Name": "a"},"children": [{"id": "33024","dataelements": {"Name": "b"},"children": [{"id": "33024","dataelements": {"Name": "z"},"children": []}]}]}, {"id": "4800","dataelements": {"Name": "d"},"children": []}]};
//we set level to 0 (optional variable) this means we can omit it in the inital call for neat code
function recursiveScan(json, level=0)
{
//we store all of the output in a log and keep a track of the level to determine indenting
var log = "";
var indent = "";
//based on the current level of the recursion, we indent the text to make it readable
for (let i=0; i<level; i++)
{
indent += " ";
}
//avoid any bad json or invalid data by checking if the name and id is null
if(json.dataelements.Name != null && json.id != null)
{
//we know there is a valid element, write the name and id
log += indent + "ID: " + json.id + "<br>";
log += indent + "Name: " + json.dataelements.Name + "<br>";
//if there is any children
if(json.children.length > 0)
{
//just for neatness, lets draw the paranthesis
log += indent + "{" + "<br>";
//increase the level
level++;
//for each child, recursively call this function to get the next level of children if available
for(let t=0; t<json.children.length; t++)
{
log += recursiveScan(json.children[t], level);
}
//we are dropping our recursion level now, getting ready to return;
level--;
//close the paranthesis for neatness
log += indent + "}" + "<br>";
}
}
//return the final log
return log;
}
//now lets test the code
document.write(recursiveScan(someJson));
The above code produces
ID: 30080
Name: abc
{
ID: 33024
Name: a
{
ID: 33024
Name: b
{
ID: 33024
Name: z
}
}
ID: 4800
Name: d
}
Now a simple run-down without all the noise
function recursiveScan(json)
{
if(json.dataelements.Name != null && json.id != null)
{
//here you have access to id and dataelements
if(json.children.length > 0)
{
for(let t=0; t<json.children.length; t++)
{
//here you have access to each child as json.children[t]
//you could do the logic for the current child
//then pass the current child to the recursive function
recursiveScan(json.children[t]);
}
}
}
return true;
}
I am trying to push some Kubernetes stats to my Firebase Real-time Database (not Firestore) and due to the special character "/" in the keys, Firebase is throwing an error. I tried to search for similar issues here but they are not quite similar to mine (tried so many replace or even delete functions but did not work). Here are my objects:
=====>> THE OBJECT
So i want to change the "/" to something like "-" on order to be able to push the entire object as to Firebase.
Example:
beta.kubernetes.io/arch --> beta.kubernetes.io-arch
beta.kubernetes.io/os --> beta.kubernetes.io-os
kubernetes.io/hostname --> kubernetes.io-hostname
node-role.kubernetes.io/master --> node-role.kubernetes.io-master
Please note that i have to process this in the attached object screenshot. So i have to process this: k8snodes{obj} -> items[arr] -> metadata{obj} -> labels{obj} in order to reach the keys i want to replace, and then push the entire object (k8snodes) to firebase.
I am using Javascript/NodeJS. thank you so much.
This is how you do it according to your data structure.
.reduce() reference: reduce
var k8snodes = {
items: [
{
"metadata": {
"labels": {
"beta.kubernetes.io/arch": "amd",
"beta.kubernetes.io/os": "linux"
}
}
},
{
"metadata": {
"labels": {
"kubernetes.io/hostname": "centos-master-node",
"node-role.kubernetes.io/master": "master"
}
}
}
]
}
k8snodes.items.forEach(function(data){
var newK8snodes = Object.keys(data.metadata.labels).reduce((total,currentValue) => {
var newLabelKey = currentValue.replace(/\//g,'-')
var newLabel = {[newLabelKey]: data.metadata.labels[currentValue]}
total = {...total, ...newLabel}
return total;
}, {});
data.metadata.labels = newK8snodes
});
console.log(k8snodes);
another simple solution is
var a = 'beta.kubernetes.io/arch';
console.log(a.replace('/','-'))
const ob = {
'beta.kubernetes.io/arch': 'amd',
'beta.kubernetes.io/os': 'linux',
'kubernetes.io/hostname': 'centos',
'node-role.kubernetes.io/master': 'master'
}
const newOb = {};
for(var i in ob) {
const newKey = i.replace(/\//g,'-')
newOb[newKey] = ob[i];
}
console.log(newOb);
Okay so I'm using angular to get a json saved to my computer to recreate a github gradebook.
I can get the data with my $http request but for the love of me all I want is to get a count of the number of issues with the label "Not Yet".
Here is the javascript:
$http.get('/api/github/repos/issues/all_issues/00All.json')
.then(function(response) {
console.log(response.data[0]);
var counter = 0;
for(var index = 0; index < response.data.length; index++) {
if(response.data[index].labels[0].name == "Not Yet") {
counter++;
};
};
console.log(counter);
});
That's the latest try, I also tried using lodash to get it earlier:
$http.get('/api/github/repos/issues/all_issues/00All.json')
.then(function(response) {
console.log(response);
mile.notYet.width = _.forEach(response.data, function(n){
var counter = 0;
if(_.result(_.find(n.labels[0], 'name')) == "Not Yet") {
counter++;
}
console.log(counter);
counter = ((counter/10) * 100) + '%';
});
});
This is a bit of the json data:
[
{
"url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11",
"labels_url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11/labels{/name}",
"comments_url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11/comments",
"events_url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11/events",
"html_url": "https://github.com/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11",
"id": 73013825,
"number": 11,
"title": "00 -- Brace Yourself -- BEN GRIFFITH",
"user": {
"login": "Epicurean306",
"id": 11682684,
"avatar_url": "https://avatars.githubusercontent.com/u/11682684?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/Epicurean306",
"html_url": "https://github.com/Epicurean306",
"followers_url": "https://api.github.com/users/Epicurean306/followers",
"following_url": "https://api.github.com/users/Epicurean306/following{/other_user}",
"gists_url": "https://api.github.com/users/Epicurean306/gists{/gist_id}",
"starred_url": "https://api.github.com/users/Epicurean306/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/Epicurean306/subscriptions",
"organizations_url": "https://api.github.com/users/Epicurean306/orgs",
"repos_url": "https://api.github.com/users/Epicurean306/repos",
"events_url": "https://api.github.com/users/Epicurean306/events{/privacy}",
"received_events_url": "https://api.github.com/users/Epicurean306/received_events",
"type": "User",
"site_admin": false
},
"labels": [
{
"url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/labels/Not%20Yet",
"name": "Not Yet",
"color": "e11d21"
}
],
As you can see the labels property is an object, nested in an array, nested in an object, nested in an array, real lovely. Putting labels[0] results in an error for me each time and doesn't get me a count. Can anybody tell me where I'm messing up please? Thank you!
If you need a solution that includes lodash, which is much more performant than the native high order functions then you can try this solution below:
var size = _(response.data)
.pluck('labels')
.flatten()
.where({ name: 'Not Yet' })
.size();
UPDATE:
If you want it to be more reusable, you can save a reference for a cloned chained sequence and simply supply another array for that cloned sequence.
var data1 = [/*array from data1*/];
var data2 = [/*array from data2*/];
var notYetSequence = _(data1)
.pluck('labels')
.flatten()
.where({ name: 'Not Yet' });
notYetSequence.size(); // returns data 1 count
notYetSequence.plant(data2).size(); // returns data 2 count
You don't need lodash for the task
var cnt = response.data
.map(function(i) { return i.labels; })
// here we extract labels object only (and get an array of arrays of objects)
.map(function(i) { return i.filter(function(l) { return l.name == 'Not yet'; }).length; })
// then for every nested array we return a number of items with
// Not Yet names (and get an array of numbers)
.filter(function(c) { return c > 0; })
// then we filter issues that don't have one (and still get an array of numbers)
.length;
// and finally get length (which is a number)
As a comparison, a plain for loop looks like:
var data = response.data;
var count = 0;
var re = /not yet/i;
for (var a, i=0, iLen=data.length; i<iLen; i++) {
a = data[i].labels;
for (var j=0, jLen=a.length; j<jLen; j++) {
if (re.test(a[j].name)) ++count;
}
}
So really not a lot of code either way, the for loop will be compatible with every browser ever (though using xmlHTTPRequest means at least ed 3+) and fastest… untested of course. ;-)
So i've been stuck trying to figure this out. I'm pretty sure I'm lacking a key piece of information. I'm grabbing some values from a JSON response. One contains a list of names. Another contains a list of URLs that correspond to the list of Names.
For instance:
{"names":"john,casey,davey",
"nameUrls":[{
"johnURL":"http://url.com",
"caseyURL":"http://url.com",
"daveyURL":"http://url.com"]}
names = (data.names).split(',');
$.each(data.nameUrls, function(key, val) {
for (var i = 0; i < names.length; i++) {
$("#left").append(val[names[i] + "URL"]);
}
})
Now the first one comes through just fine. But the rest come in undefined. So what am I doing wrong? Thanks in advance for your help.
Edit: Adding more code.
After fixing some syntax errors, here's the code which I tested in console and it's working.
var data = {
"names": "john,casey,davey",
"nameUrls": {
"johnURL": "http://url.com",
"caseyURL": "http://url.com",
"daveyURL": "http://url.com"
}
};
names = (data.names).split(',');
$.each(data.nameUrls, function (key, val) {
for (var i = 0; i < names.length; i++) {
$("#left").append(val[names[i] + "URL"]);
}
});
In above lines, I just fixed the syntax errors, however I believe this might not let you achieve what you want. Try the below code and let me know.
var data = {
"names": "john,casey,davey",
"nameUrls": {
"johnURL": "http://url1.com",
"caseyURL": "http://url2.com",
"daveyURL": "http://url3.com"
}
};
names = (data.names).split(',');
$.each(data.nameUrls, function (key, val) {
$("#left").append(val);
});
It seems to me like you should restructure your data so that there is an easier association amongst it.
Would something like this work for you?
data = [
{"name": "john", "url": "http://url.com"},
{"name": "casey", "url": "http://url.com"},
{"name": "davey", "url": "http://url.com"}
];
$.each(data, function(index, person) {
$('#left').append(person.url);
});
var data = {
"names": "john,casey,davey",
"nameUrls": {
"johnURL": "http://url.com",
"caseyURL": "http://url.com",
"daveyURL": "http://url.com"
}
};
$.each(data.names.split(','), function (i, v) {
$("#left").append( v + " ==> " + data.nameUrls[v + 'URL'] );
});
I have a function that will get a JSON array with objects. In the function I will be able to loop through the array, access a property and use that property. Like this:
Variable that I will pass to the function will look like this:
[{
"id": 28,
"Title": "Sweden"
}, {
"id": 56,
"Title": "USA"
}, {
"id": 89,
"Title": "England"
}]
function test(myJSON) {
// maybe parse my the JSON variable?
// and then I want to loop through it and access my IDs and my titles
}
Any suggestions how I can solve it?
This isn't a single JSON object. You have an array of JSON objects. You need to loop over array first and then access each object. Maybe the following kickoff example is helpful:
var arrayOfObjects = [{
"id": 28,
"Title": "Sweden"
}, {
"id": 56,
"Title": "USA"
}, {
"id": 89,
"Title": "England"
}];
for (var i = 0; i < arrayOfObjects.length; i++) {
var object = arrayOfObjects[i];
for (var property in object) {
alert('item ' + i + ': ' + property + '=' + object[property]);
}
// If property names are known beforehand, you can also just do e.g.
// alert(object.id + ',' + object.Title);
}
If the array of JSON objects is actually passed in as a plain vanilla string, then you would indeed need eval() here.
var string = '[{"id":28,"Title":"Sweden"}, {"id":56,"Title":"USA"}, {"id":89,"Title":"England"}]';
var arrayOfObjects = eval(string);
// ...
To learn more about JSON, check MDN web docs: Working with JSON
.
This is your dataArray:
[
{
"id":28,
"Title":"Sweden"
},
{
"id":56,
"Title":"USA"
},
{
"id":89,
"Title":"England"
}
]
Then parseJson can be used:
$(jQuery.parseJSON(JSON.stringify(dataArray))).each(function() {
var ID = this.id;
var TITLE = this.Title;
});
By 'JSON array containing objects' I guess you mean a string containing JSON?
If so you can use the safe var myArray = JSON.parse(myJSON) method (either native or included using JSON2), or the usafe var myArray = eval("(" + myJSON + ")"). eval should normally be avoided, but if you are certain that the content is safe, then there is no problem.
After that you just iterate over the array as normal.
for (var i = 0; i < myArray.length; i++) {
alert(myArray[i].Title);
}
Your question feels a little incomplete, but I think what you're looking for is a way of making your JSON accessible to your code:
if you have the JSON string as above then you'd just need to do this
var jsonObj = eval('[{"id":28,"Title":"Sweden"}, {"id":56,"Title":"USA"}, {"id":89,"Title":"England"}]');
then you can access these vars with something like jsonObj[0].id etc
Let me know if that's not what you were getting at and I'll try to help.
M
#Swapnil Godambe
It works for me if JSON.stringfy is removed.
That is:
$(jQuery.parseJSON(dataArray)).each(function() {
var ID = this.id;
var TITLE = this.Title;
});
var datas = [{"id":28,"Title":"Sweden"}, {"id":56,"Title":"USA"}, {"id":89,"Title":"England"}];
document.writeln("<table border = '1' width = 100 >");
document.writeln("<tr><td>No Id</td><td>Title</td></tr>");
for(var i=0;i<datas.length;i++){
document.writeln("<tr><td>"+datas[i].id+"</td><td>"+datas[i].Title+"</td></tr>");
}
document.writeln("</table>");