How to get all child and super-child data into main parent data as a childList as basic of commentId
and _id
on loop in an array of javascript recursion method.
If commentId
is null means it's a parent data else commentId
is same as another data's _id
means it's a child of that item.
let Data = [
{
"comment": "P1.c1.s1.z1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-10T10:36:44.254 0000",
"_id": 177,
"commentId": 175,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "p1.c1.s1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:26:17.791 0000",
"_id": 176,
"commentId": 175,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "p1.c1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:26:07.097 0000",
"_id": 175,
"commentId": 172,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false,
"isHaveChildComment": true
},
{
"comment": "p2.c1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:25:55.963 0000",
"_id": 174,
"commentId": 173,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "p2",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:25:48.146 0000",
"_id": 173,
"commentId": null,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": null,
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "p1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:25:41.066 0000",
"_id": 172,
"commentId": null,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": null,
"opid": 843,
"opname": "king m",
"isReplyClick": false
}
]
final output need to be: all child and super child data need to be added into main parent data as childList of parent data whose commentId is null.
let finalOutput = [
{
"comment": "p2",
"childList": [
{
"comment": "p2.c1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:25:55.963 0000",
"_id": 174,
"commentId": 173,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false
}
],
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:25:48.146 0000",
"_id": 173,
"commentId": null,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": null,
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "p1",
"ChildList": [
{
"comment": "p1.c1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:26:07.097 0000",
"_id": 175,
"commentId": 172,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false,
"isHaveChildComment": true
},
{
"comment": "p1.c1.s1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:26:17.791 0000",
"_id": 176,
"commentId": 175,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "P1.c1.s1.z1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-10T10:36:44.254 0000",
"_id": 177,
"commentId": 175,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false
}
],
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:25:41.066 0000",
"_id": 172,
"commentId": null,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": null,
"opid": 843,
"opname": "king m",
"isReplyClick": false
}
]
CodePudding user response:
Mapping objects to their ._id and getFurthestAncestor()
You may first have an object mapping each object found in the data
array to its corresponding _id
property value so that you'll have a criteria to filter items by furthest ancestor.
//maps the id to each object in objs
const mapById = objs.reduce((map, obj) => {map[obj._id] = obj; return map;}, {});
//returns the object being the furthest ancestor of the passed obj
function getFurthestAncestor(obj, mapById){
let parent = obj;
while(parent.commentId !== null){
parent = mapById[parent.commentId];
}
return parent._id;
}
Folding ancestors objects pushing their descendents in .descendents
Then you can just filter out the root elements (objects having commentId
property as null) and on them add the descendents
property as an array including all the elements having that corresponding furthest ancestor:
//returns the array of elements having .commentId == null
//(root elements with no parent)
const rootObjs = data.filter((obj) => obj.commentId === null);
//adds the property descendents to each objects in rootObjs
//valued with an array containing the list of descendents
const result =
rootObjs.map(rootObj => {
rootObj['descendents'] = objs.filter(obj =>
getFurthestAncestor(obj, mapById) === rootObj._id && obj._id != rootObj._id
);
return rootObj;
});
Demo
Here in this demo the entry point just runs as:
const result = getFoldedAncestors(data);
console.log( result );
And will print on console the object as what you expected in your question:
const data = [
{
"comment": "P1.c1.s1.z1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-10T10:36:44.254 0000",
"_id": 177,
"commentId": 175,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "p1.c1.s1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:26:17.791 0000",
"_id": 176,
"commentId": 175,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "p1.c1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:26:07.097 0000",
"_id": 175,
"commentId": 172,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false,
"isHaveChildComment": true
},
{
"comment": "p2.c1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:25:55.963 0000",
"_id": 174,
"commentId": 173,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": "king m",
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "p2",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:25:48.146 0000",
"_id": 173,
"commentId": null,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": null,
"opid": 843,
"opname": "king m",
"isReplyClick": false
},
{
"comment": "p1",
"upvoteCount": null,
"downvoteCount": null,
"createdDate": "2023-01-09T12:25:41.066 0000",
"_id": 172,
"commentId": null,
"isUpvoted": false,
"isDownvoted": null,
"repliedCommentUserName": null,
"opid": 843,
"opname": "king m",
"isReplyClick": false
}
];
const result = getFoldedAncestors(data);
console.log( result );
//returns the object being the furthest ancestor of the passed obj
function getFurthestAncestor(obj, mapById){
let parent = obj;
while(parent.commentId !== null){
parent = mapById[parent.commentId];
}
return parent._id;
}
//returns an array of objs with ancestors on top and descendents as items of their descendents prop
function getFoldedAncestors(objs){
//maps the id to each object in data
const mapById = objs.reduce((map, obj) => {map[obj._id] = obj; return map;}, {});
//returns the array of elements having .commentId == null (root elements with no parent)
const rootObjs = data.filter((obj) => obj.commentId === null);
//adds the property descendents to each objects in rootObjs with the list of descendents
const result =
rootObjs.map(rootObj => {
rootObj['descendents'] = objs.filter(obj =>
getFurthestAncestor(obj, mapById) === rootObj._id && obj._id != rootObj._id
);
return rootObj;
});
return result;
}