So I have 2 different JSONs.
Books
{
"books": [{
"name": "Lord of the rings",
"author": 1,
"year": 1937,
"genre": 3,
"imageUrl": "https://cdn.lifehack.org/wp-content/uploads/2015/03/9780618640157_custom-s6-c30.jpg",
"availability": true
}]
}
and, the other one, Authors
{
"authors": [{
"id": 1,
"name": "J.R.R. Tolkien"
}, {
"id": 2,
"name": "Harper Lee"
}, {
"id": 3,
"name": "J.K. Rowling"
}]
}
I want to have the author like an id, so when I'll display the author for the a book, I want the name(that's in the second json), not the id.
How can I do that?
Not sure if matters, but I'm working in VUE.
You could use loash's find method to do this e.g.
Documentation: https://lodash.com/docs/4.17.11#find
_.find(authors, { 'id': 1 });
I'd use the native Array.filter method, like so:
let tolkien = authors.filter(author => !!author.id === 1)
Using .filter means you don't need to include a library like lodash just for this one method.
You can create a new object with keys mapped to authors (i.e author[1] = {id: 1, ...}) which will let you quickly and easily access any author by his/her id. Example:
let authorByIds = {};
authors.forEach(author => {
authorByIds[author.id] = {...author};
});
let firstBook = books[0];
console.log(authorByIds[firstBook.author]);
// will output author with id = 1, i.e J.R.R. Tolkien
Related
Hi I got a bit stuck at trying to understand how to fetch data of a JSON file.
environment.ts:
export const environment = {
production: false,
urlListBooks: "/assets/list-books.json",
urlGetBooks: "/assets/edit-book.json?:id",
urlGetTags: "/assets/edit-book.json?:tags",
urlPostBooks: "/assets/edit-book.json",
urlListTags: "/assets/list-tags.json",
urlPostTags: "/assets/edit-tag.json"
};
edit-book.json:
"book":{
"id": 1,
"title": "The Shining",
"authorId": 1,
"tags": [{"name":"new"}, {"name":"test"}]
},
"authors":[
{
"id": 1,
"prename": "Stephen",
"surname": "King"
},
{
"id": 3,
"prename": "Algernon",
"surname": "Blackwood"
},
{
"id": 4,
"prename": "Edgar Allan",
"surname": "Poe"
},
{
"id": 5,
"prename": "Howard Phillips",
"surname": "Lovecraft"
}
],
"tags":[
{
"name": "new"
},
{
"name": "Horror"
},
{
"name": "Romance"
}
]
}
service:
getBookTags(n: String) Observable<Tag[]>{
return this.http.get<Tag[]>(environment.urlGetTags.)
}
what I want getBookTags(n: String) to do is returning the tags array of the book with title n defined in the edit-book.json (e.g. "tags": [{"name":"new"}, {"name":"Horror"}] ) so that I can later use the function to check which tags a book has and select them.
Your help would be very appreciated :)
Ok I think I've solved this for you, I'm going to walk through my process with you so you understand what the goal is. You can see my solution here: https://codesandbox.io/s/thirsty-minsky-g6959f?file=/assets/edit-book.json:0-752
First thing is that your JSON you provided doesn't really make much sense, it shows multiple authors and just one "book". I think instead you want multiple books. Secondly, it's gotta be wrapped in a curly brace as shown:
{
"books": [
{
"id": 1,
"title": "The Shining",
"authorId": 1,
"tags": [{ "name": "new" }, { "name": "test" }]
},
{
"id": 2,
"title": "The Wendigo",
"authorId": 2,
"tags": [{ "name": "Horror" }]
}
],
"authors": [
{
"id": 1,
"prename": "Stephen",
"surname": "King"
},
{
"id": 3,
"prename": "Algernon",
"surname": "Blackwood"
},
{
"id": 4,
"prename": "Edgar Allan",
"surname": "Poe"
},
{
"id": 5,
"prename": "Howard Phillips",
"surname": "Lovecraft"
}
],
"tags": [
{
"name": "new"
},
{
"name": "Horror"
},
{
"name": "Romance"
}
]
}
Now, in your Typescript code we want to have typings for the json you're going to fetch. This will make your code more readable, it will give you intellisense, and help you catch some errors before you try to run your code. So we are going to go ahead and type the properties of the JSON as follows:
type Tag = {
name: string;
};
type Book = {
id: number;
title: string;
authorId: number;
tags: Tag[];
};
type Author = {
id: number;
prename: string;
surname: string;
};
type BookData = {
books: Book[];
authors: Author[];
tags: Tag[];
};
Basically what I said is we have bookdata which is made up of books, authors, and tags. Books have properties given under type Book, same thing with Author and Tag.
Now for the actual running code, we are going to use the fetch api to get the json data at the url.
async function getBookTags(n: string): Promise<Book[]> {
return fetch(url)
.then<BookData>((res) => res.json())
.then((data) => data.books)
.then((books) => books.filter((b) => doesBookHaveTag(b, n)));
}
First thing we do is fetch the data from the api, this returns a promise which when resolved (this is what .then does) we take the response and parse it for a json. Then when that promise resolves we get the books in the data. Then when that promise resolves we filter in books that have the matching tag.
doesBookHaveTag is just a little helper function I defined:
function doesBookHaveTag(book: Book, n: string): boolean {
// just return if book has at least one tag matching n
return book.tags.some((t) => t.name.toLowerCase() === n.toLowerCase());
}
If you don't understand promises you should watch some videos on it, but basically the browser sends out an http request and then when it resolves it queues a task to execute the function [see endnote] in .then when it has time. So when we want to call your async function and say log all books with the tag "horror" we do it as shown:
getBookTags("horror").then(console.log); // returns the one book.
I hope this makes sense and you can sort of see how to fetch the data, how to handle the promise it returns, and how to type your response. The only thing I'm not sure on is how Angular changes this for you (I'm a react guy), but this is really just non-library specific Javascript/Typescript.
[endnote] when I say function in .then, what I mean is that .then(data => data.books) is passing a function into the .then function. data => data.books is actually a function the same as:
function(data: BookData): Book[] {
return data.books
}
I would like to convert an json to tree of objects.
For example
{
"id": 2,
"label": "BEAUTY",
"description": "",
"parent_id": 0,
},
{
"id": 5,
"label": "SunGlass",
"description": "",
"parent_id": 2,
},
{
"id": 6,
"label": "Shirts",
"description": "",
"parent_id": 2,
},
{
"id": 41,
"label": "black Glasses",
"description": "electronique",
"parent_id": 5,
},
{
"id": 34,
"label": "T-shirts",
"description": "electronique",
"parent_id": 6,
},
{
"id": 3,
"label": "Phones",
"description": "",
"parent_id": 0,
"embedded_parent": null,
}
What I want is to convert this list to a tree object based on label attribute,Like this result :
const TREE_DATA = {
BEAUTY: {
'SunGlass': {'black Glasses':null},
'Shirts': null,
},
Phones: {
'Sbardilate': null,
'T-shirts': null,
'Balons': null,
},
};
I need a recursive function to make this result,to pass this result to my component widget in angular.
Thank you in advance
As #jonrsharpe mentioned, you should always provide your solution. Show us what you have done and where exactly you are stuck. It won't help you to just copy and paste solutions from StackOverflow.
For your exact problem I give you some hints. First create some Interfaces that makes the development easier. For the Node you can define a recursive interface as follows:
interface Item {
id: number,
label: string,
parent_id: number,
description: string
}
interface Node {
[label: string]: Node | null;
}
The next thing you should do is to group your elements by the parent_id. This enables you to quickly access all of the information in one Node by doing groupedByParentId[id] with an access time of O(1).
const groupedByParentId = array.reduce(
(acc, cur) => {
const parentId = cur.parentId;
const groupedItems = acc[parentId] == [];
return {...acc, [parentId]: [...groupedItems, cur]}
},
{} as {[id: string]: Item[]}
);
Defining a function for having a starting point for your tree root is a good idea as well:
const rootNodeId = 0;
function makeTree(): Node {
const node = makeNode(rootNodeId);
return node;
}
Then only the makeNode function is left. Since you haven't tried anything on your own yet, I won't provide the full solution, but here are some hints so that you can proceed hopefully easily:
The functions API is makeNode(id: number) and it returns a Node
Get the children of the current node with above data structure
If there are no children, you already know what to return ;)
If there are children, make a node for each of them and store the node in a property defined by the label
Finally return the node
Good luck! :)
I have a nested JSON returned from an API that I am hitting using a GET request, in POSTMAN chrome app. My JSON looks like this.
{
"resultset": {
"violations": {
"hpd": [
{
"0": {
"ViolationID": "110971",
"BuildingID": "775548",
"RegistrationID": "500590",
"Boro": "STATEN ISLAND",
"HouseNumber": "275",
"LowHouseNumber": "275",
"HighHouseNumber": "275",
"StreetName": "RICHMOND AVENUE",
"StreetCode": "44750",
"Zip": "10302",
"Apartment": "",
"Story": "All Stories ",
"Block": "1036",
"Lot": "1",
"Class": "A",
"InspectionDate": "1997-04-11",
"OriginalCertifyByDate": "1997-08-15",
"OriginalCorrectByDate": "1997-08-08",
"NewCertifyByDate": "",
"NewCorrectByDate": "",
"CertifiedDate": "",
"OrderNumber": "772",
"NOVID": "3370",
"NOVDescription": "§ 27-2098 ADM CODE FILE WITH THIS DEPARTMENT A REGISTRATION STATEMENT FOR BUILDING. ",
"NOVIssuedDate": "1997-04-22",
"CurrentStatus": "VIOLATION CLOSED",
"CurrentStatusDate": "2015-03-10"
},
"count": "1"
}
]
}
},
"count": "1",
"total_page": 1,
"current_page": 1,
"limit": [
"0",
"1000"
],
"status": "success",
"error_code": "",
"message": ""
}
I am trying to test whether my response body has "ViolationID":"110971".
I tried the below code in postman:
var jsonData =JSON.parse(responseBody);
tests["Getting Violation Id"] = jsonData.resultset.violations.hpd[0].ViolationID === 110971;
Two issues I noticed in the provided data. The following suggestions might help you:
Add missing closing braces at the end.
Add missing 0 in the index like this: resultset.violations.hpd[0].0.ViolationID
If the hpd array always contains only 1 member, the test might be pretty straightforward:
pm.test('Body contains ViolationID', () => {
const jsonBody = pm.response.json();
const violationId = jsonBody.resultset.violations.hpd[0]["0"].ViolationID;
pm.expect(parseInt(violationId)).to.eql(110971);
})
However, if hpd array might contain more than one member, it gets a bit trickier. I would suggest mapping only ViolationID keys from nested objects:
pm.test('Body contains ViolationID', () => {
const jsonBody = pm.response.json();
const violationIds = jsonBody.resultset.violations.hpd.map(hpd => hpd["0"].ViolationID);
pm.expect(violationIds).to.contain('110971');
})
I have a http get call which will populate the entire student list with id, name and class. Can anyone help me on how to find the id of the kid for a name?
The response will be in the below mentioned format.
[
{
"id": 1,
"SchoolName": "Cp",
"StudentList": [
{
"id": 1,
"name": "jerin",
"class": 1,
},
{
"id": 2,
"name": "john",
"class": 2,
}
]
}
]
This will be as big as the number of students. If i need to find the id of Jerin, how to proceed ?
This can be solved easily.
This is a json array. so we can use jsonArray and we can parse through it.
Hey guys so I am currently using jqgrid with json data and it currently reads in fine but i am having some difficulties getting an embeded object to read into the grid. So my json data looks something like this:
{"total":1,"page":"1","records":1,"rows":[{"Cell1":1,"Cell2":"stuff","Cell3":{"date":"2013-06-02 10:56:00","timezone_type":3,"timezone":"UTC"}}]}
Does anyone know how i can get jqgrid to read in Cell3 as one piece of data and interpret it to just display the date and time?
my current json reader is as follows:
jsonReader : {
root:"rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
id: "0"
}
Thanks again everyone
First of all the options jsonReader: {repeatitems: false, id: "0"} are incorrect. Integer values of id can be used in case of usage default repeatitems: true setting. In the case the data which represent the row of the grid looks like array ["1", "Cell2"] and not as object with named properties {"Cell1": 1, "Cell2": "stuff"}. You should use jsonReader: {repeatitems: false, id: "Cell1"} if Cell1 contains the value which you want to use as unique id of the row of the grid.
Now back to your main question. I recommend you to change format of the data from
{
"total": 1,
"page": "1",
"records": 1,
"rows": [
{
"Cell1": 1,
"Cell2": "stuff",
"Cell3": {
"date": "2013-06-02 10:56:00",
"timezone_type": 3,
"timezone": "UTC"
}
}
]
}
to
{
"total": 1,
"page": "1",
"records": 1,
"rows": [
{
"Cell1": 1,
"Cell2": "stuff"
}
],
"userdata": {
"1": {
"date": "2013-06-02 10:56:00",
"timezone_type": 3,
"timezone": "UTC"
}
}
}
I want comment my suggestion so that it could be clear for other users too. The column Cell1 contains the id. The structure of userdata which I suggest is the map from rowid (the value of Cell1) and the custom information which you need save as "Cell3" originally.
If you need somewhere in your code to have the "Cell3" value the code will be like below
onSelectRow: function (rowid) {
var cell3 = $(this).jqGrid("getGridParam", "userData")[rowid];
// now you can use cell3 which coniains the object like
// {
// "date": "2013-06-02 10:56:00",
// "timezone_type": 3,
// "timezone": "UTC"
// }
}