getting information from the inner depths of a JSON object - javascript

I have a JSON object from the CrunchBase API giving me a bunch of info from a given company. Right now I am trying to go through the JSON object and create a list of their investors. The investors can fall into one of three categories, "company", "financial_org", or "person". All three types will be appended to the same list, finalInvestorList
The script runs without error, but only produces a list of investors from the first listed round. I have logged everything I think might help. the logs are in same-line comments.
Basically my problem is that it is only looping through one time, and therefor only adding the investors from the first round. Any help would be greatly appreciated. Let me know if you need more info!
var investorList = function(data, num) {
var fundingRounds = data["funding_rounds"];
var finalInvestorList = []
console.log(fundingRounds.length) // 3
for (i=0; i < fundingRounds.length; i++) {
var investments = data["funding_rounds"][i]["investments"];
console.log(data["funding_rounds"][1]["investments"]); //correctly logs the index 1 round for spling (2nd round)
var round = data["funding_rounds"][i];
console.log('round' + i); //only logs round0, never loops around for round1, round2
for (i=0; i < investments.length; i++) {
var angelObject = round["investments"][i]["person"];
if (angelObject != null) {
console.log("angel fired"); //fires for "Mitch Blumenfeld"
var angel = angelObject["first_name"] + " " + angelObject["last_name"];
finalInvestorList[i] = angel;
}
var financialOrgObject = round["investments"][i]["financial_org"];
if (financialOrgObject != null) {
console.log("financial_org fired"); //fires for "Bucknell Venture Plan Competition"
console.log(financialOrgObject['name']); //Bucknell VPC
var financialOrg = financialOrgObject["name"]
finalInvestorList[i] = financialOrg
}
var companyObject = round['investments'][i]["company"];
if (companyObject != null) {
console.log('company fired'); //i haven't bothered with this yet.. just logging it so ill know if its firing
}
}
}
console.log(finalInvestorList); //["Bucknell Venture Plan Competition", "Mitch Blumenfeld"]
}
The JSON object represented by the data is as follows
I have shortened it with just the bit needed. The object inside the JSON response data is represented by data["funding_rounds"]
this data was retrieved using the crunch API and can be found in full form at http://api.crunchbase.com/v/1/company/spling.js
"funding_rounds":
[{"round_code": "seed",
"source_url": "",
"source_description": "",
"raised_amount": 50000.0,
"raised_currency_code": "USD",
"funded_year": 2011,
"funded_month": 2,
"funded_day": 1,
"investments":
[{"company": null,
"financial_org":
{"name": "Bucknell Venture Plan Competition",
"permalink": "bucknell-venture-plan-competition",
"image": null},
"person": null},
{"company": null,
"financial_org": null,
"person":
{"first_name": "Mitch",
"last_name": "Blumenfeld",
"permalink": "mitch-blumenfeld",
"image": null}}]},
{"round_code": "seed",
"source_url": "http://techcrunch.com/2011/09/08/dreamit-ventures-launches-its-fall-2011-philadelphia-class/",
"source_description": "",
"raised_amount": 25000.0,
"raised_currency_code": "USD",
"funded_year": 2011,
"funded_month": 9,
"funded_day": 1,
"investments":
[{"company": null,
"financial_org":
{"name": "DreamIt Ventures",
"permalink": "dreamit-ventures",
"image":
{"available_sizes":
[[[150,
57],
"assets/images/resized/0002/7773/27773v5-max-150x150.jpg"],
[[250,
96],
"assets/images/resized/0002/7773/27773v5-max-250x250.jpg"],
[[251,
97],
"assets/images/resized/0002/7773/27773v5-max-450x450.jpg"]],
"attribution": null}},
"person": null}]},
{"round_code": "a",
"source_url": "http://techcrunch.com/2011/12/05/new-content-sharing-network-spling-launches-announces-400k-series-a/",
"source_description": "New Content Sharing Network Spling Launches, Announces $400K Series A",
"raised_amount": 400000.0,
"raised_currency_code": "USD",
"funded_year": 2011,
"funded_month": 12,
"funded_day": 5,
"investments":
[{"company": null,
"financial_org":
{"name": "Deep Fork Capital",
"permalink": "deep-fork-capital-2",
"image":
{"available_sizes":
[[[150,
20],
"assets/images/resized/0008/0167/80167v1-max-150x150.png"],
[[250,
34],
"assets/images/resized/0008/0167/80167v1-max-250x250.png"],
[[450,
62],
"assets/images/resized/0008/0167/80167v1-max-450x450.png"]],
"attribution": null}},
"person": null},
{"company": null,
"financial_org": null,
"person":
{"first_name": "John",
"last_name": "Ason",
"permalink": "john-ason",
"image": null}},
{"company": null,
"financial_org": null,
"person":
{"first_name": "Mitchell",
"last_name": "Blumenfeld",
"permalink": "mitchell-blumenfeld",
"image": null}},
{"company": null,
"financial_org": null,
"person":
{"first_name": "Gianni",
"last_name": "Martire",
"permalink": "gianni-martire",
"image":
{"available_sizes":
[[[138,
150],
"assets/images/resized/0006/3720/63720v4-max-150x150.jpg"],
[[230,
250],
"assets/images/resized/0006/3720/63720v4-max-250x250.jpg"],
[[414,
450],
"assets/images/resized/0006/3720/63720v4-max-450x450.jpg"]],
"attribution": ""}}}]}]
Thanks for the help!

You are using the same variable name for the counter in each loop, so when the inner loop completes and the outer loop gets to its second iteration, i is investments.length, not 1. Use different variable names for each loop:
for (var roundIdx = 0; roundIdx < fundingRounds.length; roundIdx++) {
...
for (var invIdx = 0; invIdx < investments.length; invIdx++) {
...
Also, don't populate your array using array[i] = value notation, just use array.push(value). You don't need to keep track of the indexes.
But, I'd recommend iterating your arrays using Array.forEach() and using dot syntax instead of square bracket notation:
function investorList(data, num) {
var finalInvestorList = [];
data.funding_rounds.forEach(function (round, i) {
round.investments.forEach(function (investment, i) {
if (investment.person) {
finalInvestorList.push(investment.person.first_name + " " +
investment.person.last_name);
}
else if (investment.financial_org) {
finalInvestorList.push(investment.financial_org.name)
}
else if (investment.company) {
finalInvestorList.push(investment.company.name)
}
}
}
}
For older browsers that don't natively support Array.forEach(), use the implementation here to shim the browser.

Related

Lodash - Remove one property for every element in array without specify index

I'm building a component that allows me to compare two objects. It accepts a list of fields to compare and a list of fields that need to be ignored in string format
Here is an example of the object that will be compared:
{
// (..... More elements above .....)
taskData: {
"uniqueId": "OrdenTrabajo48",
"id": 48,
"position": 1,
"name": "Dirección Obra Civil",
"description": "Dirección Obra Civil Afecta: Sorda, Roberto",
"startDate": "2021-10-16T11:00:00.000Z",
"endDate": "2022-06-01T11:00:00.000Z",
"duration": 227,
"progress": 73,
"hours": 0,
"realHours": 15,
"predecessor": null,
"child": [],
"resourceInfo": [
{
"uniqueId": "Persona_1MJ0VE9G0",
"id": "OrdenTrabajo48Persona_1MJ0VE9G0",
"name": "Sorda, Roberto",
"group": "Subgerencia de Planes y Proyectos - SUB_PLAN_PROY_SIT",
"unit": 4.1667,
"startDate": "2021-10-16T03:00:00.000+00:00",
"endDate": "2022-06-01T02:59:59.000+00:00",
"hours": 0,
"realHours": 15,
"avatar": "http://localhost:8091/images/llama.jpg"
}
],
"comments": null,
"etiquetas": [],
"baseLineStartDate": null,
"baseLineEndDate": null
}
// (..... More elements below .....)
}
(But to clarify, it could be any object. The component is abstract and can be used anywhere)
The component doesn't know the structure of the object to compare, just the object and the paths in string format
I want to remove in every element of the array resourceInfo, the properties avatar, icon, label and color regardless the length of the array, but I don't know if there is a syntax to do that.
Also I want to remove the property realHours
This is what I tried:
const ignoredFields = [
'taskData.resourceInfo[?].avatar', //<--- It's not working
'taskData.resourceInfo[].icon', //<--- Neither this
'taskData.resourceInfo.label', //<--- Or this
'taskData.resourceInfo[0].color', //<--- This hardcode is working, but I don't know the length in that scope
'taskData.realHours' // <-- No problems here
];
const currentComparableObject = _.omit(obj, ignoredFields);
const oldComparableObject = _.omit(prev, ignoredFields);
var fieldsToOmit=[];
var resourceInfoFields=['avatar','icon','label','color'];
var globalFields=['realHours'];
taskData.resourceInfo.forEach((item,index)=>{
resourceInfoFields.forEach((field)=>{
fieldsToOmit.push(`resourceInfo[${index}].${field}`)
})
})
console.log( _.omit(taskData, fieldsToOmit.concat(globalFields)))
You do not need lodash to delete fields from an array. I mean you can if you really want to but, it is trivial to loop through the array and delete the fields you want.
#Yasser CHENIK isn't wrong just doesn't do a good job of explaining the solution.
Below I have included a thorough example so you can test for yourself.
NOTE this solution mutates the original array but, it is not difficult to use this concept to make an immutable version.
const taskData = {
"uniqueId": "OrdenTrabajo48",
"id": 48,
"position": 1,
"name": "Dirección Obra Civil",
"description": "Dirección Obra Civil Afecta: Sorda, Roberto",
"startDate": "2021-10-16T11:00:00.000Z",
"endDate": "2022-06-01T11:00:00.000Z",
"duration": 227,
"progress": 73,
"hours": 0,
"realHours": 15,
"predecessor": null,
"child": [],
"resourceInfo": [
{
"uniqueId": "Persona_1MJ0VE9G0",
"id": "OrdenTrabajo48Persona_1MJ0VE9G0",
"name": "Sorda, Roberto",
"group": "Subgerencia de Planes y Proyectos - SUB_PLAN_PROY_SIT",
"unit": 4.1667,
"startDate": "2021-10-16T03:00:00.000+00:00",
"endDate": "2022-06-01T02:59:59.000+00:00",
"hours": 0,
"realHours": 15,
"avatar": "http://localhost:8091/images/llama.jpg"
},
{
"uniqueId": "Persona_1MJ0VE9G0",
"id": "OrdenTrabajo48Persona_1MJ0VE9G0",
"name": "Sorda, Roberto",
"group": "Subgerencia de Planes y Proyectos - SUB_PLAN_PROY_SIT",
"unit": 4.1667,
"startDate": "2021-10-16T03:00:00.000+00:00",
"endDate": "2022-06-01T02:59:59.000+00:00",
"hours": 0,
"realHours": 15,
"avatar": "http://localhost:8091/images/llama.jpg"
},
{
"uniqueId": "Persona_1MJ0VE9G0",
"id": "OrdenTrabajo48Persona_1MJ0VE9G0",
"name": "Sorda, Roberto",
"group": "Subgerencia de Planes y Proyectos - SUB_PLAN_PROY_SIT",
"unit": 4.1667,
"startDate": "2021-10-16T03:00:00.000+00:00",
"endDate": "2022-06-01T02:59:59.000+00:00",
"hours": 0,
"realHours": 15,
"avatar": "http://localhost:8091/images/llama.jpg"
},
],
"comments": null,
"etiquetas": [],
"baseLineStartDate": null,
"baseLineEndDate": null
}
const fieldsToOmit = [
'avatar',
'icon',
'label',
'color',
'realHours'
]
console.log(taskData.resourceInfo);
taskData.resourceInfo.forEach(info => {
fieldsToOmit.forEach(field => {
delete info[field];
})
});
console.log(taskData.resourceInfo);
You can remove properties in a functional manner (immutable) by using destructuring:
const {realHours, ...result} = {
...taskData,
resourceInfo: taskData.resourceInfo.map(
({avatar, icon, label, color, ...keep}) => keep
)
};
console.log(result);
Thanks for the answers to all.
To solve partially the problem, I created a function that does the following:
It filters the references that contains [?] (i.e: taskData.resourceInfo[?].avatar)
Then obtain the first part of the string (That is, the path to reach the array) and the second part (property name)
Using _.get from lodash it retrieves the length of the array and creates a new fieldReference with the index, so loadash can read it.
private sanitizeArrays(obj: any, fieldReferences: string[]): string[] {
const fieldsDup = [...fieldReferences];
// Get Elements that contains [?] in the property name
const arrays = fieldsDup.filter(ignoredField => ignoredField.match(/\[\?]/g));
// Remove elements that contain [?] from ignoredFieldsDuplicated
fieldsDup.forEach((ignoredField, index) => {
if (ignoredField.includes('[?]')) {
fieldsDup.splice(index, 1);
}
});
// Get the properties names without [?]
const arrayPropertyName = arrays.map(ignoredField => ignoredField.split('[')[0]);
const afterArrayPropertyName = arrays.map(ignoredField => ignoredField.split(']')[1]);
// For each array that I have...
arrayPropertyName.forEach((array, index) => {
const length = _.get(obj, array).length;
for (let i = 0; i < length; i++) {
fieldsDup.push(array + '[' + i + ']' + afterArrayPropertyName[index]);
}
});
return fieldsDup;
}
Example input (if the object contains only one element in resourceInfo):
'taskData.resourceInfo[?].avatar',
'taskData.resourceInfo[?].icon',
'taskData.resourceInfo[?].label',
'taskData.resourceInfo[?].color',
'taskData.resourceInfo[?].fontColor',
'taskData.realHours'
Example output:
taskData.resourceInfo[?].icon
taskData.resourceInfo[?].color
taskData.realHours
taskData.resourceInfo[0].avatar
taskData.resourceInfo[0].icon
taskData.resourceInfo[0].label
taskData.resourceInfo[0].color
taskData.resourceInfo[0].fontColor
(javascript includes() isn't playing nice deleting the [?])
Also it doesn't work for nested arrays...

Google Sheets: API returning undefined for json tag

I've been trying to use an online API (albion-online-data.com) for a while in sheets, creating a little function to try to grab a specific identifier, sell_price_min, but the function keeps returning undefined.
I've been looking around for ages but haven't been able to find out what's wrong. Sorry, I'm new to APIs and google sheets in general. I used Logger.log, and it shows the correct contents after Json.parse, but when trying to use
return w.sell_price_min;
it always returns undefined.
Here's the code:
/**
* Retrieve the current price for a given city.
*
*/
function CURRENTPRICE(name, location, quality) {
name = encodeURI(name);
location = encodeURI(location);
quality = encodeURI(quality);
var response = UrlFetchApp.fetch("http://www.albion-online-data.com/api/v2/stats/Prices/" + name + "?locations=" + location + "&qualities=" + quality);
var w = JSON.parse(response.getContentText());
return w.sell_price_min;
}
and the API is:
https://www.albion-online-data.com/api/v2/stats/prices/T4_BAG,T5_BAG?locations=Caerleon,Bridgewatch&qualities=2
which returns the following: (reformatted here with indentation and line breaks for readability)
[
{
"item_id": "T4_BAG",
"city": "Bridgewatch",
"quality": 2,
"sell_price_min": 4000,
"sell_price_min_date": "2019-09-02T22:20:00",
"sell_price_max": 4444,
"sell_price_max_date": "2019-09-02T22:20:00",
"buy_price_min": 0,
"buy_price_min_date": "0001-01-01T00:00:00",
"buy_price_max": 0,
"buy_price_max_date": "0001-01-01T00:00:00"
},
{
"item_id": "T4_BAG",
"city": "Caerleon",
"quality": 2,
"sell_price_min": 5571,
"sell_price_min_date": "2019-09-03T11:05:00",
"sell_price_max": 5571,
"sell_price_max_date": "2019-09-03T11:05:00",
"buy_price_min": 2375,
"buy_price_min_date": "2019-09-03T08:41:00",
"buy_price_max": 4020,
"buy_price_max_date": "2019-09-03T08:41:00"
},
{
"item_id": "T5_BAG",
"city": "Bridgewatch",
"quality": 0,
"sell_price_min": 20000,
"sell_price_min_date": "2019-09-01T14:00:00",
"sell_price_max": 22100,
"sell_price_max_date": "2019-09-01T14:00:00",
"buy_price_min": 0,
"buy_price_min_date": "0001-01-01T00:00:00",
"buy_price_max": 0,
"buy_price_max_date": "0001-01-01T00:00:00"
},
{
"item_id": "T5_BAG",
"city": "Caerleon",
"quality": 2,
"sell_price_min": 23897,
"sell_price_min_date": "2019-09-03T11:03:00",
"sell_price_max": 26376,
"sell_price_max_date": "2019-09-03T11:03:00",
"buy_price_min": 15000,
"buy_price_min_date": "2019-09-02T22:21:00",
"buy_price_max": 22550,
"buy_price_max_date": "2019-09-02T22:21:00"
}
]
and the results should be: 4000?
Sorry for any hassle... I've been stumped for literally hours .-.
You are accessing a JSON array. So it should be
for(var i = 0; i < w.length; i++) {
var obj = w[i];
console.log(obj.sell_price_min);
}
If you want to get the first value of the array put
return w[0].sell_price_min

Javascript Function Output

I'm practicing how to maniupulate data in JS in this article: http://learnjsdata.com/combine_data.html
var articles = [
{"id": 1, "name": "vacuum cleaner", "weight": 9.9, "price": 89.9, "brand_id": 2},
{"id": 2, "name": "washing machine", "weight": 540, "price": 230, "brand_id": 1},
{"id": 3, "name": "hair dryer", "weight": 1.2, "price": 24.99, "brand_id": 2},
{"id": 4, "name": "super fast laptop", "weight": 400, "price": 899.9, "brand_id": 3}
];
var brands = [
{"id": 1, "name": "SuperKitchen"},
{"id": 2, "name": "HomeSweetHome"}
];
articles.forEach(function(article) {
var result = brands.filter(function(brand){
return brand.id === article.brand_id;
});
delete article.brand_id;
article.brand = (result[0] !== undefined) ? result[0].name : null;
});
I'm confused with the last part: article.brand = (result[0] !== undefined) ? result[0].name : null;
I understand the conditional operation: it wants to have null value if result[0] is not defined. But I'm wondering what result[0] refers to. I thought it would take first object: {"id":2, "name": "HomeSweetHome"} so there should be for loop to iterate all objects in order to see if objects meet the condition? Could you inform me what I'm missing or/and what result[0] refers to?
Thanks,
result[0] will be undefined in case there is no element in result. result is expected to be an array of brands filtered by the filter operation
The filtered array result will have same brand as that of the current article in the outer foreach loop. The filter condition is going to achieve that.
It looks like in this particular case you will get only one element in result array always as there are unique brand ids. It might have more elements in case of duplicated brand ids.
result[0] points to first element in the array result

Values from a JSON response in ajax returning as undefined

I'm having some problems when trying to retrieve values from a JSON response sent via the $.post() method in jQuery. Here is the script:
var clickedName = $('#customerId').val();
$.post("/customer-search", { name: clickedName }).done( function(response) {
var results = $.parseJSON(response);
console.log(results);
$('#account-name').html(results.firstname + ' ' + results.lastname);
$('#email').html(results.email);
$('#telephone').html(results.telephone);
if (results.fax) {
$('#fax').html(results.fax);
} else {
$('#fax').html('n/a');
}
$('#personal').fadeIn();
return false;
});
Just to explain, I'm using twitter typeahead in a Symfony2 project, and basically this script will fire when a name is clicked (selected) from the list after typing. The customer-search URL runs a search of the database as follows:
$q = $request->request->get('name');
$em = $this->getDoctrine()->getManager();
$customer = $em->getRepository('AppBundle:Oc73Customer')->findLikeName($q);
$addresses = $em->getRepository('AppBundle:Oc73Address')->findByCustomerId($customer[0]['customerId']);
$results = array();
$results['customer'] = $customer;
$results['addresses'] = $addresses;
return new Response(json_encode($results));
Which will successfully return a Json encoded response, and the value of 'response' which is printed in the console (as per the jquery above) is:
{
"customer": [{
"firstname": "Mike",
"lastname": "Emerson",
"email": "xxxx#xxxx.co.uk",
"telephone": "01234 5678910",
"fax": null,
"password": "8e1f951c310af4c20e2cd6b68dee506ac685d7ae",
"salt": "e2b9e6ced",
"cart": null,
"wishlist": null,
"newsletter": 0,
"addressId": 84,
"customerGroupId": 1,
"ip": null,
"status": 1,
"approved": 1,
"token": null,
"dateAdded": {
"date": "2016-02-16 12:59:28.000000",
"timezone_type": 3,
"timezone": "Europe/Berlin"
},
"availCredit": null,
"customerId": 75
}],
"addresses": [{}]
}
I am trying to retrieve the customer details by using the method I always use, so to get the firstname, I use results.firstname where results is a parsed JSON string, as written in my jQuery response.
However, all I get from results.firstname is undefined, even when it clearly is defined. So, basically, I'm wondering what I am doing wrong?
Hope someone can shed some light on my problem.
The properties you're trying to access are objects in the customer array, not on the parent object itself. Assuming that the response only ever contains one customer object then you can use result.customer[0], like this:
$.post("/customer-search", { name: clickedName }).done(function(response) {
var results = $.parseJSON(response);
var customer = response.customer[0];
$('#account-name').html(customer.firstname + ' ' + customer.lastname);
$('#email').html(customer.email);
$('#telephone').html(customer.telephone);
$('#fax').html(customer.fax ? customer.fax : 'n/a');
$('#personal').fadeIn();
});
If it's possible that multiple customer objects will be returned in the array the you would need to amend your code to loop through those objects and build the HTML to display them all - without using id attributes.
I was able to access it like "results.customer[0].firstname"
var cus =
{
"customer": [{
"firstname": "Mike",
"lastname": "Emerson",
"email": "xxxx#xxxx.co.uk",
"telephone": "01234 5678910",
"fax": null,
"password": "8e1f951c310af4c20e2cd6b68dee506ac685d7ae",
"salt": "e2b9e6ced",
"cart": null,
"wishlist": null,
"newsletter": 0,
"addressId": 84,
"customerGroupId": 1,
"ip": null,
"status": 1,
"approved": 1,
"token": null,
"dateAdded": {
"date": "2016-02-16 12:59:28.000000",
"timezone_type": 3,
"timezone": "Europe/Berlin"
},
"availCredit": null,
"customerId": 75
}],
"addresses": [{}]
}
alert(cus.customer[0].firstname);

I'd like to push non-existing items inside an already declared object if they don't already exist using lodash in angular

I'm new with lodash but as the title states 'I'd like to push non-existing items inside an already declared object if they don't already exist' that is if I have
var lessdata = {
"id": 1004,
"name": "some event",
"bookmarked": false //not in moredata and I'd like to keep the var as is
};
var moredata = {
"id": 1004,
"name": "some event",
"time": { //from here
"hours": 2,
"minutes": 00,
"currency": "USD"
},
"place": "some place" //to here is new without '"bookmarked": false'
};
I'd like to have my result loaded back into the lessdata variable and have my result look like so
var lessdata = {
"id": 1004,
"name": "some event",
"time": {
"hours": 2,
"minutes": 00,
"currency": "USD"
},
"place": "some place",
"bookmarked": false
};
I stuck knowing know to use lodash apprpriatly in angular and wasnt sure if I need to use angualar's forEach or not.
I've dabbled with two approaches.
version 1
lessdata= _.uniq(lessdata, function(moredata) {
return moredata;
});
version 2
angular.forEach(lessdata, function(lkey, lvalue) {
console.log("[-]lessdata---lkey: " + lkey + ", lvalue: " + lvalue)
angular.forEach(moredata, function(mkey, mvalue) {
console.log("[+]moredata---mkey: " + mkey + ", mvalue: " + mvalue)
lessdata=_.uniq(lessdata, function(moredata) {
return moredata;
});
})
})
$scope.event = lessdata
Im assuming using _.uniq is the best approach? any help would be appreciated and I created a codepen here.
TLDR: just read the title
That's what lodash.defaults does:
Assigns own and inherited enumerable properties of source objects to the destination object for all destination properties that resolve to undefined.
lodash.defaults(lessdata, moredata);

Categories

Resources