Find and update nested JSON value - javascript

I need to find and update json object from nested json object. Consider the original json object.
var originaldata=[
{
"sc_iden": "331",
"sc_name": "Scene 1",
"sc_type": "",
"sc_status": "Draft",
"sc_owner": "",
"children": [
{
"sc_iden": "332",
"Sc_name": "Scene1.1",
"sc_type": "",
"sc_status": "Draft",
"sc_priority": "3",
"sc_owner": "",
"children": []
}
]
},
{
"sc_iden": "334",
"sc_name": "Scene2",
"sc_type": "",
"sc_status": "Draft",
"sc_priority": "2",
"sc_owner": "",
"children": []
}]
Find the below findUpdate record from originaldata(JSON) and update their values.
var findUpdate = {
"sc_iden": "332",
"Sc_name": "My Scene",
"sc_type": "New Type",
"sc_status": "Opened",
"sc_priority": "5",
"sc_owner": "Admin",
"children": []
}
Based on sc_iden ="332" search the originaldata and update new values(findUpdate) by using jquery or angularjs.

Have a look on this plunker .
var update = function(jsonArray, updatedJson) {
if (jsonArray.length !== 0) {
jsonArray.forEach(function(obj) {
if (obj.sc_iden === updatedJson.sc_iden) {
obj.sc_name = updatedJson.sc_name;
//....update
} else {
//try to update children
update(obj.children, updatedJson);
}
});
}
};
It will modify the original data, so keep a copy if you still need that.

Check the console output (in the example only Sc_name is changed):
var originaldata=[
{
"sc_iden": "331",
"sc_name": "Scene 1",
"sc_type": "",
"sc_status": "Draft",
"sc_owner": "",
"children": [
{
"sc_iden": "332",
"Sc_name": "Scene1.1",
"sc_type": "",
"sc_status": "Draft",
"sc_priority": "3",
"sc_owner": "",
"children": []
}
]
},
{
"sc_iden": "334",
"sc_name": "Scene2",
"sc_type": "",
"sc_status": "Draft",
"sc_priority": "2",
"sc_owner": "",
"children": []
}];
var findUpdate = {
"sc_iden": "332",
"Sc_name": "My Scene",
"sc_type": "New Type",
"sc_status": "Opened",
"sc_priority": "5",
"sc_owner": "Admin",
"children": []
}
for (i in originaldata) {
var obj = originaldata[i];
if (obj['sc_iden'] == '332') {
obj['Sc_name'] = findUpdate['Sc_name'];
//...
} else {
for (m in obj['children']) {
var k = obj['children'][m];
if (k['sc_iden'] == '332') {
k['Sc_name'] = findUpdate['Sc_name'];
//...
}
}
}
}
console.log(originaldata);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Related

Updating array of objects with recursive function (Mapping replies to comments dynamically)

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))

How to compare array and object in Javascript?

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());

How to extract values from nested JSON with different formatting using Javascript of Jquery?

var cart =
[
{
"Items": "",
"category": "",
"contents":
[
{
"Apple iPhone": "222",
"French": "Bounjour",
"id": 1234,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag":"false"
}
]
},
{
"Items": "No 2",
"category": "2nd",
"contents":
[
{
"redmi": "333",
"French": "some text",
"id": 345787,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag":"true"
},
{
"samsung": "333",
"French": "some text",
"id": 86787876,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag":"disabled"
}
]
}
];
Can anyone help me to get the "id" value and "pricetag" value from the above JSON ? It is nested one and can be in different format. But in each, i need to extract id value and pricetag value. I tried so many things but not getting exact output. Can someone please help me ? Sorry for the bad formatting ..
use .map() to iterate and return the desired keys :
var cart = [{
"Items": "",
"category": "",
"contents": [{
"Apple iPhone": "222",
"French": "Bounjour",
"id": 1234,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag": "false"
}]
},
{
"Items": "No 2",
"category": "2nd",
"contents": [{
"redmi": "333",
"French": "some text",
"id": 345787,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag": "true"
},
{
"samsung": "333",
"French": "some text",
"id": 86787876,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag": "disabled"
}
]
}
];
let values = cart.map((e) => {
return e.contents.map((a) => {
return {
id: a.id,
pricetag: a.pricetag
}
})
})
console.log(values)
This should work for you :
var items=[];
var some_var;
const map1 = cart.map(function(item){
const map2=item.contents.map(function(contentItem){
//some_var=contentItem.id;
return{
pricetag:contentItem.pricetag,
id:contentItem.id
}
})
items=items.concat(map2)
});
console.log(items);
Sample output:
[ { pricetag: 'false', id: 1234 },
{ pricetag: 'true', id: 345787 },
{ pricetag: 'disabled', id: 86787876 } ]

How to merge and flat arrays at the same time

I have two arrays of data, one has tree structure and another is just a nested array with details..
What I want to do now is to flat this details array and merge it to tree's structure.
Both details and tree have records with same unique ID.
var tree = [{
"Children": [{
"Children": [],
"ID": "1",
"PendingChange": true,
}],
"ID": "22",
"PendingChange": false,
}];
var details = [{
"Address": {
"Jurisdiction": {
"Name": "United Kingdom"
},
"City": "Waltham Cross"
},
"ID": "1",
"Name": "J"
}];
var finalArray = _.map(tree, function(e) {
return _.extend(e, _.omit(_.findWhere(details, {
ID: e.ID
}), 'ID'));
});
console.log(finalArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
Desired output
var tree = [{
"Children": [{
"Children": [],
"ID": "1",
"PendingChange": true,
"Name": "J"
"Address_City": "Waltham Cross"
"Address_Jurisdiction_Name": "United Kingdom"
}],
"ID": "22",
"PendingChange": false,
}];
Underscore is not a must, I am just stuck with it - https://jsfiddle.net/ey8hqn19/
You could create recursive function with for...in loop that will loop deep tree object and then use find to find object with same id in details and add properties.
var tree = [{
"Children": [{
"Children": [],
"ID": "1",
"PendingChange": true,
}],
"ID": "22",
"PendingChange": false,
}];
var details = [{
"Address": {
"Jurisdiction": {
"Name": "United Kingdom"
},
"City": "Waltham Cross"
},
"ID": "1",
"Name": "J"
}];
function makeTree(data) {
for (var i in data) {
if (typeof data[i] == 'object') makeTree(data[i])
if (i == 'ID') {
var f = details.find(function(e) {
return e.ID == data[i]
})
if (f) {
Object.assign(data, {
"Name": f.Name,
"Address_City": f.Address.City,
"Address_Jurisdiction_Name": f.Address.Jurisdiction.Name
})
}
}
}
}
makeTree(tree)
console.log(tree)

Jquery : transform nested json object to another json object

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)

Categories

Resources