I am trying to construct my own JSON object from multiple online image/photography sources. The below code should explain what I am trying to accomplish:
var searchUnsplash = require('./apis/unsplash');
var searchFlickr = require('./apis/flickr');
function combineObjs(callback) {
var obj = {}
var key = 'item';
obj[key] = [];
searchFlickr.searchFlickr(searchTerm, searchCount, searchPage,
function (callback) { // each API call is in a separate file with these functions exported
obj[key].push(flickrObj); // this does not work
// console.log(flickrObj) // this works
});
searchUnsplash.searchUnsplash(searchTerm, searchCount, searchPage,
function (callback) {
obj[key].push(unsplashObj);
// console.log(unsplashObj)
});
console.log(obj)
}
combineObjs();
The goal is to end up with a JSON object like below:
["item": {
"id": 1,
"title": 2,
"content": 3,
"source": "flickr"
},
"item": {
"id": 1,
"title": 2,
"content": 3,
"source": "unsplash"
}]
etc, which I can use to power my front end.
I am a beginner to javascript and I am just working off what I have learned in tutorials and articles, so I might be using the wrong approach entirely for what I am aiming to achieve. Happy to take any pointers
search function:
function searchUnsplash(term, count, page, callback) {
request(`https://api.unsplash.com/search/photos/?per_page=${count}&page=${page}&query="${term}"&client_id=KEY&`,
function searchResult(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body)
for ( var i = 0; i < info.results.length; i++) {
obj = {
id: `us-${info.results[i].id}`,
}
callback(obj);
}
}
})
}
module.exports.searchUnsplash = searchUnsplash;
First, your intended result is not correct. You can't name "item" the individual array entries. A corrected and working example would be this one.
[ {
"id": 1,
"title": 2,
"content": 3,
"source": "flickr"
},
{
"id": 1,
"title": 2,
"content": 3,
"source": "unsplash"
}]
Second, you mistake JSON for your data structure. JSON is just the text notation. So, let's see first how to build a suitable data array.
let results = [];
results.push( { id:1, title:2, content:3, source:"flickr" });
results.push( { id:2, title:4, content:6, source:"unsplash" });
And then with JSON.stringify(results) will code your results into JSON.
Finally, you mix up the aynchronous calls in your code with synchronous invocations. You need to save the results on the callback of the individual functions, that is when you really obtain the responses asynchronously. Also, you need to count the pending results and invoke the final callback when all done.
So, putting all the pieces together, in a contrived fake example, we just invoke twice the search functions and so we callback when two results are combined.
function combineObjs(callback) {
let results = [];
function partialResult(obj) {
results.push(obj);
if (results.length=2) callback(results);
};
searchFlickr(searchTerm, searchCount, searchPage, partialResult);
searchUnsplash(searchTerm, searchCount, searchPage,partialResult);
}
combineObjs( function(results) { console.log(JSON.stringify(results)) });
This is excessive but it would work. It can be used over and over and over again. :D
Run the snippet to see a result
class JSONBuilder
{
constructor(contents=null)
{
if(!contents)
{
//Private objecy hash that isn't publicly accessible
var objectHash = {};
//Get stashed item
this.GetItem = function(key)
{
if(!key) throw new Error("Null or Underfined Key Passed.");
let value = objectHash[key];
if(!value) throw new Error(`Key : ${key} Not Found in JSON objectHash`);
return value;
}
//Set an item in the objecy hash
this.SetItem = function(key, value)
{
if(!key) throw new Error("Null or Underfined Key Passed.");
if(!value) throw new Error("Null or Underfined Key Not Found.");
objectHash[key] = value;
}
//Remove item from the hash
this.DeleteItem = function(key)
{
if(!key) throw new Error("Null or Underfined Key Passed.");
if(!objectHash[key]) throw new Error(`Key : ${key} Not Found in JSON objectHash`);
objectHash.DeleteItem(key);
}
//Turn items into a JSON object
this.Build = function()
{
return JSON.stringify(objectHash);
}
}
else
{
//If a string is passed as a paremeter, reconstruct from that
try
{
objectHash = JSON.parse(contents);
}
catch(Err)
{
console.log("Parsing of JSON Content Failed.");
throw Err;
}
}
}
}
class Item
{
constructor(id, source, content, title)
{
this.Id = id;
this.Source = source;
this.Content = content;
this.Title = title;
}
}
let builder = new JSONBuilder();
let itemContainer = [];
itemContainer.push(new Item(1, 'flicker', 'stuff', 'item1'));
itemContainer.push(new Item(2, 'flicker', 'morestuff', 'item2'));
builder.SetItem('items', itemContainer);
console.log(builder.Build());
Related
Boris has a list of all the beers available in his pub, but it's a huge mess. He would like to see the beers grouped by brands. Boris also told you that the Function should return an array of objects which contains the Brand name and an array of beer IDs of that Brand.
JSON file with data:
https://challenge.codingsans.com/beers.json
Output Example:
[
{
"brand": "brandName2",
"beers": [
"beerID3",
"beerID4"
]
},
{
"brand": "brandName1",
"beers": [
"beerID2",
"beerID1"
]
}
]
//
I have done this:
(So basically nothing. I just would like to get some idea how to solve it.)
request = new XMLHttpRequest;
request.open('GET', 'https://challenge.codingsans.com/beers.json', true);
var data = [];
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Date Parse
data = JSON.parse(request.responseText);
// Success!
// Arrays
var beerIDs = [];
var beerBrand = [];
// Iteration
for (var key in data) {
beerIDs.push(data[key].id);
beerBrand.push(data[key].brand);
// console.log(beerIDs);
// console.log(beerBrand);
}
console.log(beerIDs);
console.log(beerBrand);
//final list
var finalList = [];
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
Try this:
request = new XMLHttpRequest;
request.open('GET', 'https://challenge.codingsans.com/beers.json', true);
var data = [];
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Date Parse
data = JSON.parse(request.responseText);
// Success!
const organizedBeers = data.reduce((acc, beers) => {
const findIndex = acc.findIndex(beer => beer.brand === beers.brand)
if(findIndex > -1) {
acc[findIndex].beersId.push(beers.id)
} else {
acc.push({
brand: beers.brand,
beersId: [beers.id],
})
}
return acc;
}, [])
console.log(organizedBeers)
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
So basically, you can create a new array which will be final output(in our case let's say 'aBeerNBrands'). And you can push new object with required properties (like 'brand': string, ids: array) there.
And then you can loop over main array(in your case :'data') element and in nested loop you can check if that brand object is present in new array('aBeerNBrands') or not, if it is present then push the id to ids array present inside aBeerNBrands's object; else create new object inside 'aBeerNBrands' with required properties. Below code works fine for your requirement.
request = new XMLHttpRequest;
request.open('GET', 'https://challenge.codingsans.com/beers.json', true);
var data = [];
request.onload = function() {
debugger;
if (request.status >= 200 && request.status < 400) {
// Date Parse
data = JSON.parse(request.responseText);
// Success!
// Arrays
var aBeerNBrands = [];
// Iteration
for (var key in data) {
if(aBeerNBrands.length > 0){
for(var key2 in aBeerNBrands){
if(aBeerNBrands[key2].brand === data[key].brand){
aBeerNBrands[key2].ids.push(data[key].id);
break;
}
if(key2 == aBeerNBrands.length - 1 && aBeerNBrands[key2].brand !== data[key].brand){
var oBrandObject = {
brand: data[key].brand,
ids: [data[key].id]
};
aBeerNBrands.push(oBrandObject);
}
}
} else{
var oBrandObject = {
brand: data[key].brand,
ids: [data[key].id]
};
aBeerNBrands.push(oBrandObject);
}
// console.log(beerIDs);
// console.log(beerBrand);
}
console.log(aBeerNBrands);
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
Follow below steps :
Grouping input array of objects by brand and resulting with an object using Array.reduce() method.
Structuring the output based on the reduced brand object we have.
Working Demo :
const data = [
{
"id": "ccw-1",
"name": "Coding Challenge White",
"brand": "Coding Challenge Brewery"
}, {
"id": "sw-1",
"name": "Share White",
"brand": "Share",
}, {
"id": "bspa-1",
"name": "Beer Sans Pale Ale",
"brand": "Beer Sans Brewery"
}, {
"id": "ccb-1",
"name": "Coding Challenge Brown",
"brand": "Coding Challenge Brewery"
}, {
"id": "ccw-2",
"name": "Coding Challenge Wheat",
"brand": "Coding Challenge Brewery"
}];
// result array
const resultArr = [];
// grouping by brand and resulting with an object using Array.reduce() method
const groupByBrand = data.reduce((group, item) => {
const { brand } = item;
group[brand] = group[brand] ?? [];
group[brand].push(item.id);
return group;
}, {});
// Finally structuring the output based on the brand object we have.
Object.keys(groupByBrand).forEach((item) => {
resultArr.push({
'brand': item,
'beers': groupByBrand[item]
})
})
// Result
console.log(resultArr);
I have data in this format. This is gamesparks data that is BaaS using for game development.
I am sending this data to the IOS person but he said he can not fetch this type of data so he told me to change the data
This is my actual data
{
"Details": [{
"5d4c2c28dcf224127a30457b": {
"displayName": "ewqeqw"
},
"5d4c4699dcf224127a3045e0": {
"displayName": "mmmmmmmmmm"
}
}]
}
and I need to change data in this format
{
"Details": [{
"ID": "5d499b0fdcf224127a303d61",
"displayName": "qweqewq"
},
{
"ID": "5d499b0fdcf224127a303d61",
"displayName": "qweqewq"
}
]
}
This is my code:
var group = Spark.getData().group;
var API = Spark.getGameDataService();
var all1 = new Array();
var entry = API.getItem("playerFriends", Spark.getPlayer().getPlayerId());
var friendsList = {};
if (entry.error()) {
Spark.setScriptError("ERROR", error);
Spark.exit();
} else {
var data = entry.document().getData();
if (group === "all") {
for (var friendOBJ in data) {
//Set details of player ID and display name in new friendsList
object
friendsList[friendOBJ] = {};
friendsList[friendOBJ].displayName = data[friendOBJ].displayName;
friendsList[friendOBJ].playerId = data[friendOBJ].playerId;
}
all1.push(friendsList);
} else {
for (var friendOBJ in data) {
if (data[friendOBJ].group === group && data[friendOBJ].status ===
"accepted") {
friendsList[friendOBJ] = {};
friendsList[friendOBJ].displayName = data[friendOBJ].displayName;
}
}
}
Spark.setScriptData("Details", all1);
Can you not just make a function to convert the data into the desired shape? Something like this should work:
function formatData(details) {
var formattedDetails = [];
for (var id in details) {
formattedDetails.push({
ID: id,
displayName: details[id].displayName
});
}
return formattedDetails;
}
var data = {
"Details": [
{
"5d4c2c28dcf224127a30457b": {
"displayName": "ewqeqw"
},
"5d4c4699dcf224127a3045e0": {
"displayName": "mmmmmmmmmm"
}
}
]
};
var formattedData = formatData(data.Details[0])
this is the output you want
{
"Details": [{
"ID": "5d499b0fdcf224127a303d61",
"displayName": "qweqewq"
}
}
and this is my code i am explaining each line with comment
var count = 0;
var tmp = { AcceptedFriendList: []}; //make object and inside empty array
for (var friendOBJ in data) { // retrieving data
if(data[friendOBJ].status === "accepted"){ // your condition
var tempObj = {"displayName" :"","playerid": ""}; //this is format you want
tempObj.displayName = data[friendOBJ].displayName; // putting data in spicify format object
tempObj.playerid = data[friendOBJ].ID;
tmp.AcceptedFriendList[count] = tempObj; //assign object back to array
count++; // iterate it so the next data come further.
}}
I need to make a new object out of a multiple record parse.com object in javascript.
This is how I get the entire fetched object:
function(articleID, callback) {
"use strict";
var Comment = Parse.Object.extend('Comment');
var query = new Parse.Query(Comment);
query.descending('createdAt');
query.equalTo('commentFor', {__type:"Pointer", className:"Article", objectId:articleID});
query.equalTo('commentApproved', true);
query.find().then(function(results) {
callback(results);
}, function(error){
callback({error: error});
});
}
Now, the problem is, that this returns (callback()) an object which contains some sensitive data, such as the emails of all commenters, so I want to return a new object with, say, just 'name', 'date', and 'comment'. I just don't know how to build an object like this with a multiple record object as the master.
I am making this in node.js, if that helps in any way.
I'd like something along the line of
[
{
"name": "Robert",
"date": "2016-01-18T17:59:27.378Z",
"comment": "Hello World!"
},
{
"name": "Bob",
"date": "2016-01-15T16:37:35.226Z",
"comment": "Bees knees"
}
]
I've tried this, but it doesn't seem to work - I don't get the output I'd expect:
var test = function(articleID, callback) {
"use strict";
var Comment = Parse.Object.extend('Comment');
var query = new Parse.Query(Comment);
query.descending('createdAt');
query.equalTo('commentFor', {__type:"Pointer", className:"Article", objectId:articleID});
query.equalTo('commentApproved', true);
query.find().then(function(results) {
var object = {};
for(var i = 0; i < results.length; i++) {
object += {
commentName: results[i].get('commentName'),
commentWebsite: results[i].get('commentWebsite'),
commentContent: results[i].get('commentContent'),
createdAt: results[i].get('createdAt')
};
}
callback(object);
}, function(error){
callback({error: error});
});
};
And then I discovered query.select()
This is a case of RTFM! https://parse.com/docs/js/guide#queries-query-constraints
Controller returns Java.lang.stackoverflow error when calling from ajax.
My Ajax function is like this.
$.ajax({
url: '${pageContext.servletContext.contextPath}/exam/test',
type: 'POST',
data: 'examName='+examName,
success: function(response) {
alert(response);
}
});
Controller
#RequestMapping(value = "/exam/test", method = RequestMethod.POST)
public #ResponseBody List<SchoolExam> examsTest(#ModelAttribute(value = "examName") String examName, BindingResult result, WebRequest webRequest, ModelMap map, Principal principal) {
User loggedUser = userService.getUserByUserName(principal.getName());
***********************
Some code here
***********************
List<SchoolExam> schoolExams = new ArrayList<SchoolExam>();
for (School school : schools) {
if (student) {
Set<Student> students = school.getStudents();
for(Student std : students) {
if (std != null && !std.isEmpty()) {
schoolExams.add(new SchoolExam(std, true));
}
}
}
if (teacher) {
Set<Teacher> teachers = school.getEvents();
for (Teacher tchr : teachers) {
if (loggedUser.equals(tchr.getOwner())) {
schoolExams.add(new SchoolExam(tchr, true));
}
}
}
if (exam) {
Set<Exam> exams = school.getCampaigns();
for (Exam exam1 : exams) {
if (loggedUser.equals(exam1.getOwner())) {
schoolExams.add(new SchoolExam(exam1, true));
}
}
}
}
return schoolExams;
}
SchoolExam
public SchoolExam(Object obj, boolean editable) {
this.editable = editable;
if (obj instanceof Student) {
Student student = (Student) obj;
this.id = student.getId();
this.name = student.getName();
this.type = Constants.Student;
this.obj = student; // <-- This is causing issue here
}
if (obj instanceof Teacher) {
Teacher teacher = (Teacher) obj;
this.id = teacher.getId();
this.name = teacher.getName();
this.type = Constants.Teacher;
this.obj = teacher; // <-- This is causing issue here
}
if (obj instanceof Exam) {
Exam exam = (Exam) obj;
this.id = exam.getId();
this.name = exam.getName();
this.type = Constants.Exam;
this.obj = exam; // <-- This is causing issue here
}
}
Issue:
This is working fine when a form is submit then I can use all data by running foreach loop in jsp but when I tried to return list in my function then ajax work successfully and it also return me response
response in ajax
[
{
"id":"2123244",
"name":"UK School",
"type":"exam",
"editable":true,
"obj":
{
"id":"2123244",
"authorizationRequired":false,
"owner":
{
"id":"5676764554",
"company":
{
"id":"55435435345",
"name":"SchoolTest Software",
"enabled":true,
"size":3,
"sector":null,
"phone":"1231231232",
"schoolFees":5000,
"location":"US",
"users":
[
{
"id":"5676764554",
"company": // <-- Start Repeating here
{
"id":"55435435345",
"name":"SchoolTest Software",
"enabled":true,
"size":3,
"sector":null,
"phone":"1231231232",
"schoolFees":5000,
"location":"US",
"users":
[
{
"id":"5676764554",
"company": // <-- Repeating again
{
"id":"55435435345",
"name":"SchoolTest Software",
"enabled":true,
"size":3,
"sector":null,
"phone":"1231231232",
"schoolFees":5000,
"location":"US",
"users":
[
{
"id":"5676764554",
"company":// <-- It keeps repeating it self
but when I tried to print list value in controller it's only printing one value.
e.g:
for (SchoolExam schoolExam : schoolExams) {
System.out.println("Name: " + schoolExam.getName());
System.out.println("ID: " + schoolExam.getId());
Exam exam = (Exam) schoolExam.getObj();
System.out.println("Exam Name: " + exam.getName());
}
Output:
Name: UK School
ID: 2123244
Exam Name: UK School
Note:
If I comment obj line then everything works fine for me.
e.g:
this.obj = student;
this.obj = teacher;
this.obj = exam;
But I need to use this to get data as It contain data for different table.
Please find this file for error log that I'm getting in console.
So, What I'm doing wrong which cause this issue or I need to use any other way to prevent this issue.
Any suggestion or link will be helpful.
According to your error log file, you have a cyclic recursion in your Java classes. So Jackson try to serialize some objects infinitely.
The main problem is here : com.school.model.Company_$$_javassist_8["users"]->org.hibernate.collection.PersistentSet[0]->com.school.model.User["company"]->com.school.model.Company_$$_javassist_8["users"]
You have a property users containing a set of User containing a property ompany containr a Company containing the same users. So infinity loop.
I want to list all leaves ids where group name is i.e. "group110"
So, output for this example is 014, 288, 223 and 244.
Here is content of my JSON file:
{
"name": "visualization",
"children": [
{
"name": "group100",
"children": [
{
"name": "group110",
"children": [
{
"name": "group111",
"children": [
{"id":"014","link":"-","name":" Animals/70","decade":"-"}
]
},
{
"name": "group112",
"children": [
{"id":"288","link":"-","name":"Heidelberg platen press","decade":"1960s"}
]
},
{
"name": "group113",
"children": [
{"id":"223","link":"-","name":"Camera Praktica Super TL – shutter release","decade":"1960s"},
{"id":"244","link":"-","name":"Mechanical calculator, Facit","decade":"1950s"}
]
}
]
},
Try this way. Find the group using a recursive method and collect leaf nodes using another recursive method.
function getLeafNodes(leafNodes, obj){
if(obj.children){
obj.children.forEach(function(child){getLeafNodes(leafNodes,child)});
} else{
leafNodes.push(obj);
}
}
function findIds(json,name){
if(json.children){
if(json.name==name) {
var leafNodes = [];
getLeafNodes(leafNodes,json);
console.log(leafNodes.map(function(leafNode){ return leafNode.id; })); //Logs leaf node ids to the console
} else {
json.children.forEach(function(child){
findIds(child,name);
});
}
}
}
Execution of following code will print ["014", "288", "223", "244"]
findIds(actualJSON,"group110");
The following code traverses the tree recursively. If param has children, then its children will be traversed. Otherwise, its id will be appended to the results array, thus, at the end results will contain the id of the leaves. getResults returns results to simplify its usage.
var results = [];
function getResults(param) {
if (!!param.children) {
for (var child in param.children) {
getResults(param.children[child]);
}
} else {
results[results.length] = param.id;
}
return results;
}
Here is a generic terse recursive answer for finding nodes using some jquery ($.map).
Watch out for stack overflows if the data is deep though!
Also it will not continue searching inside a matching node for more matching sub nodes, so it's only applicable if the search term does not nest logically.
This method makes use of the array flattening feature of $.map.
var found = (function walk(obj, searchKey, searchTerm) {
if(!$.isPlainObject(obj)) return null;
return obj[searchKey] === searchTerm ? [obj] : $.map(obj, function (lev) {
return walk(lev, searchKey, searchTerm);
});
})(data, 'name', 'group110');
Expanding on that to solve the specific problem above...
var found = (function walk(obj, searchTerm) {
if(!$.isPlainObject(obj)) return null;
return obj.name == searchTerm
? $.map(obj.children, function(c){
return $.map(c.children, function(f){ return f.id; }); })
: $.map(obj.children, function (lev) {
return walk(lev, searchTerm); });
})(data, 'group110');
Or rather
var found = (function walk(obj, lambda, term) {
if(!($.isPlainObject(obj) || $.isArray(obj))) return null;
return lambda.call(obj, term)
? $.map(obj.children, function(c){
return $.map(c.children, function(f){ return f.id; }); })
: $.map(obj.children, function (lev) {
return walk(lev, searchTerm); });
})(data, function(a){ return this.name == a; }, 'group110');