I am receiving a list of comments from a graphql backend in the following format:
[
{
"__typename": "Comment",
"id": "1",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "test 1"
},
{
"__typename": "Comment",
"id": "2",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "this is a comment"
},
{
"__typename": "Comment",
"id": "34",
"userId": "1",
"postId": "1",
"parentCommentId": "1",
"content": "reply to test1"
},
{
"__typename": "Comment",
"id": "35",
"userId": "1",
"postId": "1",
"parentCommentId": "34",
"content": "nested reply to \"reply to test1\"\n\n"
},
{
"__typename": "Comment",
"id": "36",
"userId": "1",
"postId": "1",
"parentCommentId": "34",
"content": "test?"
}
]
The comments with parentCommentId === null are the highest level comments, while comments where parentCommentId !== null are replies to a comment where id === parentCommentId
I would like to transform this data structure to something like:
[{
"__typename": "Comment",
"id": "1",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "test1",
"replies": [{
"__typename": "Comment",
"id": "34",
"userId": "1",
"postId": "1",
"parentCommentId": "1",
"content": "reply to test1",
"replies": [{
"__typename": "Comment",
"id": "35",
"userId": "1",
"postId": "1",
"parentCommentId": "34",
"content": "reply to test1"
}]
}]
},
{
"__typename": "Comment",
"id": "2",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "this is a comment",
"replies": []
}
]
I have the following function to do the data transformation:
function formatData(comments: Array < IComment > ) {
let commentList = Array < IComment > ();
// add comments without `parentCommentId` to the list.
// these are top level comments.
for (let i = 0; i < comments.length; i++) {
if (!comments[i].parentCommentId) {
commentList.push({ ...comments[i],
replies: []
});
}
}
for (let i = 0; i < comments.length; i++) {
if (comments[i].parentCommentId) {
const reply = comments[i];
mapReplyToComment(commentList, reply);
}
}
return commentList;
function mapReplyToComment(
commentList: Array < IComment > ,
reply: IComment
): any {
return commentList.map((comment) => {
if (!comment.replies) {
comment = { ...comment,
replies: []
};
}
if (comment.id === reply.parentCommentId) {
comment.replies.push(reply);
return comment;
} else {
return mapReplyToComment(comment.replies, reply);
}
});
}
}
However this only works for one level deep into the object tree. so I am getting the replies of a main comment, but replies to replies are not added to the object.
this is what I am getting now:
[{
"__typename": "Comment",
"id": "1",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "test1",
"replies": [{
"__typename": "Comment",
"id": "34",
"userId": "1",
"postId": "1",
"parentCommentId": "1",
"content": "reply to test1"
// -- I should have here another node of "replies"
}]
},
{
"__typename": "Comment",
"id": "2",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "this is a comment",
"replies": []
}
]
Could you please point out what am I doing wrong and provide some explanation?
Thanks in advance
Edit:
based on #Nina Scholz's comment I came up with this solution:
function formatData(data: Array < IComment > , root: string) {
const temp: any = {};
data.forEach((comment: IComment) => {
const parentCommentId = comment.parentCommentId ? ? root;
if (temp[parentCommentId] == null) {
temp[parentCommentId] = {};
}
if (temp[parentCommentId].replies == null) {
temp[parentCommentId].replies = [];
}
if (temp[comment.id] == null) {
temp[parentCommentId].replies.push(
Object.assign((temp[comment.id] = {}), comment)
);
} else {
temp[parentCommentId].replies.push(
Object.assign(temp[comment.id], comment)
);
}
});
return temp[root].replies;
}
You could take a single iteration with the help of an object which keeps the references of parent to children and children to parent.
const
getTree = (data, root) => {
const t = {};
data.forEach(o =>
((t[o.parentCommentId] ??= {}).replies ??= []).push(
Object.assign(t[o.id] ??= {}, o)
)
);
return t[root].replies;
},
data = [{ __typename: "Comment", id: "1", userId: "1", postId: "1", parentCommentId: null, content: "test 1" }, { __typename: "Comment", id: "2", userId: "1", postId: "1", parentCommentId: null, content: "this is a comment" }, { __typename: "Comment", id: "34", userId: "1", postId: "1", parentCommentId: "1", content: "reply to test1" }, { __typename: "Comment", id: "35", userId: "1", postId: "1", parentCommentId: "34", content: "nested reply to \"reply to test1\"\n\n" }, { __typename: "Comment", id: "36", userId: "1", postId: "1", parentCommentId: "34", content: "test?" }],
tree = getTree(data, null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Since the other answer was hard to understand for me, I will post mine as well which splits the steps into standalone functions:
(Note that I added the replies array in your sample data)
let data = [{ "__typename": "Comment", "id": "1", "userId": "1", "postId": "1", "parentCommentId": null, "content": "test 1", "replies": [] },
{ "__typename": "Comment", "id": "2", "userId": "1", "postId": "1", "parentCommentId": null, "content": "this is a comment", "replies": [] },
{ "__typename": "Comment", "id": "34", "userId": "1", "postId": "1", "parentCommentId": "1", "content": "reply to test1", "replies": [] },
{ "__typename": "Comment", "id": "35", "userId": "1", "postId": "1", "parentCommentId": "34", "content": "nested reply to \"reply to test1\"\n\n", "replies": [] },
{ "__typename": "Comment", "id": "36", "userId": "1", "postId": "1", "parentCommentId": "34", "content": "test?", "replies": [] }
]
function findLowestComment(dataArray) {
for (let i = 0; i < dataArray.length; i++) {
let comment = dataArray[i]
isLowest = true
if (comment.parentCommentId == null) {
continue
}
for (let j = 0; j < dataArray.length; j++) {
if (dataArray[j].id != comment.id &&
dataArray[j].parentCommentId == comment.id &&
dataArray[j].parentCommentId != null) {
isLowest = false;
break
}
}
if (isLowest) {
return i
}
}
}
function insertIntoParent(dataArray, commentIndex) {
for (let j = 0; j < dataArray.length; j++) {
if (dataArray[j].id == dataArray[commentIndex].parentCommentId) {
dataArray[j].replies.push(dataArray[commentIndex])
dataArray.splice(commentIndex, 1)
break
}
}
}
function mapComments(dataArray) {
for (let j = 0; j < dataArray.length; j++) {
let lowestIndex = findLowestComment(dataArray)
insertIntoParent(dataArray, lowestIndex)
}
}
mapComments(data)
console.log(JSON.stringify(data, undefined, 2))
Related
I use a fake api with this json, I still haven't been able to with this function, I need to convert the structure to look like this and I need to convert this data and then unconvert when saving
so that I change the parameters blockId to id, blockParent to parent.
{
"blocks": [
{
"blockId": "12",
"name": "Sierra",
"abrv": "Sir",
"blockParent": "0"
},
{
"blockId": "23",
"name": "Velasco",
"abrv": "Vel",
"blockParent": "12"
},
{
"blockId": "32",
"name": "UnitOne",
"abrv": "Uni",
"blockParent": "23"
},
{
"blockId": "48",
"name": "Vani",
"abrv": "Van",
"blockParent": "12"
},
{
"blockId": "57",
"name": "UnitTwo",
"abrv": "UniTwo",
"blockParent": "48"
}
]
}
const flatToTree = (blocks: IListBlocks[]) => {
const array: IListBlocks[] = []
const children: IListBlocks[] = []
blocks.forEach((block) => {
if (block.blockParent === block.blockId) {
array.push(block)
} else {
children.push(block)
}
})
array.forEach((block) => {
block.children = children.filter(
(child) => child.blockParent === block.blockId,
)
})
return array
}
{
"id": "12",
"title": "Sierra",
"subtitle": "Sir",
"parent": "0",
"children": [
{
"id": "13",
"title": "Sierra",
"subtitle": "Sir",
"parent": "12",
}
]
}
I have structure like below:
{
0: [{
"id": "1",
"parentId": "root",
"path": "root"
"children": [{
"id": "2",
"parentId": "1",
"path": "1/2",
"children": [
"id": "4",
"parentId": "2",
"path": "2/4"
]
}, {
"id": "3",
"parentId": "1",
"path": "1/3"
}]
}]
}
I have key "path" and now it's "parentId/id", but I would like to have path from root to this element, so it should looks "root/parentId/id/parentId/it..." etc. For example path: "root/1/2/4".
How can I dynamically put a value inside key "path" to get full path to root element?
Your data structure does not respect the childhood of each element, but considering this is not a part of the question, here is a simple recursive solution:
const data = [{
"id": "1",
"parentId": "root",
"path": "root",
"children": [{
"id": "2",
"parentId": "1",
"path": "1/2",
"children": [{
"id": "4",
"parentId": "2",
"path": "2/4"
}
]
}, {
"id": "3",
"parentId": "1",
"path": "1/3"
}
]
},
{
"id": "4",
"parentId": "2",
"path": "2/4"
}
];
function assignPath(tree, index, array, currentPath) {
tree.path = currentPath || 'root';
tree.children && tree.children.forEach(child => {
assignPath(child, null, null, `${tree.path}/${child.id}`);
});
}
data.forEach(assignPath);
console.log(data);
You will need to identify the root node and start with its path.
Then add each consecutive child id to the path end.
let obj = {
0: [{
"id": "1",
"parentId": "root",
"path": "root",
"children": [{
"id": "2",
"parentId": "1",
"path": "1/2",
"children": [{
"id": "4",
"parentId": "2",
"path": "2/4"
}]
}, {
"id": "3",
"parentId": "1",
"path": "1/3"
}]
}]
};
console.log(getRoute(obj[0][0], true)); // Identify root
function getRoute(node, isRoot) {
return node != null
? (isRoot
? (node.path + '/')
: ''
) + node.id + (node.children
? '/' + getRoute(node.children[0], false)
: '')
: '';
}
Recursive solution:
updatePath(array, 'root');
function updatePath(array, path) {
array.forEach((element, i) => {
element.path = path + '/' + (i + 1);
if(element.hasOwnProperty('children')) {
updatePath(element.children, element.path);
}
});
}
I have two json array and object
I would like to compare two json and push another object
obj1 = ["user1", "user2"]
obj2 = [
{
"userName": "user1",
"id": "14"
},
{
"userName": "user2",
"id": "9",
},
{
"userName": "user3",
"id": "3",
},
{
"userName": "user4",
"id": "1",
}
]
I would like to get the result as below
[
{
"userName": "user1",
"id": "14"
},
{
"userName": "user2",
"id": "9",
}
]
After, I tried to compare two arrays and get a result what I need.
var obj1 = ["user1","user2"]
var obj2 = [
{
"userName": "user1",
"id": "14"
},
{
"userName": "user2",
"id": "9",
},
{
"userName": "user3",
"id": "3",
},
{
"userName": "user4",
"id": "1",
}
]
var objArray = [];
for (var i = 0; i < obj.length; i++) {
if (obj1[i] === obj2.userName) {
objArray.push(obj2[i]);
}
return objArray;
Please help me to solve the issue.
Thanks in advance
You could filter by checking the name with Array#includes.
var array1 = ["user1", "user2"],
array2 = [{ userName: "user1", id: "14" }, { userName: "user2", id: "9", }, { userName: "user3", id: "3", }, { userName: "user4", id: "1", }],
result = array2.filter(({ userName }) => array1.includes(userName));
console.log(result);
You need two loops:
iterate through obj1[i], and for each index of obj1...
iterate through obj2[] and test each object to see whether the username property's value equals that of obj[i].
var obj1 = ["user1","user2"]
var obj2 = [
{
"userName": "user1",
"id": "14"
},
{
"userName": "user2",
"id": "9",
},
{
"userName": "user3",
"id": "3",
},
{
"userName": "user4",
"id": "1",
}]
function myFunction(){
var objArray = [];
for (var i=0; i < obj1.length; i++) {
for (var userIndex=0; userIndex < obj2.length; userIndex++){
if (obj1[i] === obj2[userIndex].userName){
objArray.push( obj2[userIndex] );
}
}
}
return objArray;
};
console.log(myFunction());
I have a json arry
{
"result": "sucess",
"senderids": [{
"id": "2",
"senderid": "powers",
"status": "0",
"type": "2",
"availa": "0",
"user": "admin"
}, {
"id": "3",
"senderid": "powert",
"status": "0",
"type": "2",
"availa": "0",
"user": "admin"
}, {
"id": "4",
"senderid": "powerd",
"status": "0",
"type": "2",
"availa": "0",
"user": "admin"
}, {
"id": "5",
"senderid": "pavank",
"status": "0",
"type": "1",
"user": "pavan"
}]
}
Javascript:
var res = xhr.responseText;
var s = res.senderids;
for (i = 0; i < s.senderids.length; i++) {
var contact = JSON.parse(s.senderids[i].senderid);
alert(contact);
}
How i can parse this json array using JSON.parse. I have tried this code
thanks in advance
Try this:
var res = JSON.parse(xhr.responseText);
var s = res.senderids;
for (i = 0; i < s.senderids.length; i++) {
var contact = s.senderids[i].senderid;
alert(contact);
}
In javascript/jquery how do i achieve following
old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
Using jquery iterate over the above and change to following
new_dataset = [
{
"dob":"xyz",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
},{
"dob":"er",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
}]
If someone can give the code to transform the data it would help me to understand the iteration
You could do something like:
function transformDataset(oldDataset) {
var newDataset = [];
var newObj;
for (var i = 0; i < oldDataset.length; i++) {
newObj = transformObj(oldDataset[i]);
newDataset.push(newObj);
}
return newDataset;
}
function transformObj(obj) {
var children = obj.children;
obj.name = obj.name.first + ' ' + obj.name.last;
obj.start_date = obj.start_date.month + ' ' + obj.start_date.day + ' ' + obj.start_date.year;
obj.children = [];
for (var i = 0; i < children.length; i++) {
obj.children.push(children[i].child.id);
}
return obj;
}
var new_dataset = transformDataset(old_dataset);
Note that new_dataset will have an array of child id instead of an object with multiple child_id properties.
You also had a typo in old_dataset.start_date.month (was written moth)(or maybe that was intentional).
use map first to iterate the array data (old_dataset), replace element name & start_date with new value then return the array
const old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
let new_dataset = old_dataset.map((arr) => {
arr.name = `${arr.name.first} ${arr.name.last}`
arr.start_date = `${arr.start_date.moth} ${arr.start_date.day} ${arr.start_date.year}`
return arr
})
console.log(new_dataset)