Find by key and replace by value in nested json object - javascript

I have an json object It can be nested and I have an second object containing key/value pair. I want to replace the second object's value by first one by matching key both object's key.
let firstObj = {
"enquiry": {
"Lead": {
"SubLead": {
"DealerRef": "test",
"DealerFloor": "test",
"Region": "test",
"Source": {
"Special": "test",
"TestDrive": "test",
"TradeIn": "test",
"Finance": "test"
}
},
"Contact": {
"Info": {
"FirstName": "test",
"Surname": "test",
"Email": "test",
"OfficePhone": "test",
"CellPhone": "test"
}
},
"Seeks": {
"Stock": {
"Used": "test",
"Brand": "test",
"Model": "test",
"StockNr": "test"
}
}
}
}
}
Its my array
let secondObj = {
DealerRef: '18M',
DealerFloor: 'UCP',
Region: 'Western Cape',
FirstName: 'abc',
Surname: 'xyz',
Email: 'test#ctm.co.za',
OfficePhone: '2343243',
CellPhone: '2343243',
Used: '1',
Brand: 'QAE',
Model: 'test',
StockNr: 'SEDONA',
Special: '2013 Kia Sedona',
TestDrive: '0',
TradeIn: '0',
Finance: '0'
};
I have tried many ways [http://jsfiddle.net/FM3qu/7/][1] this way i'm able to get solution in Jsfiddle, In my express application when I try to process it gives me an empty object.
I want something like this
"enquiry": {
"Lead": {
"SubLead": {
"DealerRef": "18M",
"DealerFloor": "UCP",
"Region": "Western Cape"....
Thank you

You could first save all references and then assign the data, you have.
function update(object, data) {
function getAllKeys(o) {
Object.keys(o).forEach(function (k) {
if (typeof o[k] === 'object') {
return getAllKeys(o[k]);
}
keys[k] = o;
});
}
var keys = Object.create(null);
getAllKeys(object);
Object.keys(data).forEach(function (k) {
if (keys[k] && k in keys[k]) { // check if key for update exist
keys[k][k] = data[k];
}
});
}
var object = { "enquiry": { "Lead": { "SubLead": { "DealerRef": "test", "DealerFloor": "test", "Region": "test", "Source": { "Special": "test", "TestDrive": "test", "TradeIn": "test", "Finance": "test" } }, "Contact": { "Info": { "FirstName": "test", "Surname": "test", "Email": "test", "OfficePhone": "test", "CellPhone": "test" } }, "Seeks": { "Stock": { "Used": "test", "Brand": "test", "Model": "test", "StockNr": "test" } } } } },
data = { DrNo: 666, DealerRef: '18M', DealerFloor: 'UCP', Region: 'Western Cape', FirstName: 'abc', Surname: 'xyz', Email: 'test#ctm.co.za', OfficePhone: '2343243', CellPhone: '2343243', Used: '1', Brand: 'QAE', Model: 'test', StockNr: 'SEDONA', Special: '2013 Kia Sedona', TestDrive: '0', TradeIn: '0', Finance: '0' };
update(object, data);
console.log(object);

You can iterate through firstObj and replace key/value with secondObj
function iterateObj(obj){
for(var key in obj){
if(obj.hasOwnProperty(key)){
if(typeof obj[key] === 'object'){
iterateObj(obj[key]);
}
else if(secondObj[key]!=undefined){
obj[key] = secondObj[key]
}
}
}
}
iterateObj(firstObj)
console.log(firstObj); // this will give proper results

Related

Why only last element is showing of an array instead of all elements in JavaScript

I am trying to retrieve certain information from a json data and want to make a new key-value pair array. But its only returning the last element instead of all elements.
My code is following:
const input =
{
"file1": {
"function1": {
"calls": {
"105": {
"file": "file1",
"function": "function2"
},
"106": {
"file": "file1",
"function": "function3"
}
},
"points": {
"106": "106"
}
},
"function2": {
"calls": {
"109": {
"file": "file1",
"function": "function2"
}
},
"points": {
"109": "111"
}
},
"function3": {
"calls": {},
"points": {
"132": "135"
}
}
}
}
function transformData(input) {
let res = [];
Object.entries(input).map(([fileName, fileObject]) => {
Object.entries(fileObject).map(([functionName, functionObject]) => {
Object.entries(functionObject).map(([functionKey, functionValue]) => {
if(functionKey === "calls") {
Object.entries(functionValue).map(([callKey, callObject]) => {
res = {"source": functionName, "target": callObject['function']}
//console.log(res); // here all elements get printed out
});
}
});
});
});
return res;
}
const result = transformData(input);
console.log(result) // only giving {source:"function2", target:"function2"}
Here as the result I want new source, target pairs where the source is the key under file (function1, function2). Target is the value of the nested key "function" inside the key "calls" (function2, function3, function2). Here the number of files and functions will be more. But some functions may not have "calls" data at all.
So, the result will look like following:
[
{
source: "function1",
target: "function2"
},
{
source: "function1",
target: "function3"
},
{
source: "function2",
target: "function2"
}
]
Can anyone please help me out to get the correct output. Thank you for your time.
you need to edit one line as follows
res = [...res,{"source": functionName, "target": callObject['function']}]
I'm not sure how "guaranteed" your object structure is, but assuming you want to iterate through all file* key and get the function mappings, this should do the trick.
const input =
{
"file1": {
"function1": {
"calls": {
"105": {
"file": "file1",
"function": "function2"
},
"106": {
"file": "file1",
"function": "function3"
}
},
"points": {
"106": "106"
}
},
"function2": {
"calls": {
"109": {
"file": "file1",
"function": "function2"
}
},
"points": {
"109": "111"
}
},
"function3": {
"calls": {},
"points": {
"132": "135"
}
}
}
}
const result = [];
for(const key in input) {
if (key.includes('file')) {
const functions = Object.keys(input[key]);
for (const func of functions) {
const funcObject = input[key][func];
for (const call in funcObject.calls) {
const callObj = funcObject.calls[call];
result.push({source: func, target: callObj.function});
}
}
}
}
console.log(result);
Looks like res = needs to be something like res += i.e. don't overwrite your array each time, instead add the next item found to it.
let inputArray = {
users: [
{
firstName: 'Will',
lastName: 'Jacob',
email: 'sample#sample.com',
_id: '5e324187b5fdf167a91dfdbb',
roles: [ 'ward', 'hospital', 'hr' ],
},
{
firstName: 'Theatre',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf2f0c631a8788be59fc4',
roles: [ 'ward' ],
},
{
firstName: 'Cinema',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['hospital', 'hr' ],
},
{
firstName: 'Cinema2',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['ward', 'hr' ],
},
{
firstName: 'Cinema3',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: ['hospital', 'hr' ],
},
{
firstName: 'Cinema4',
lastName: 'Manager',
email: 'sample#sample.com',
_id: '5e3cf62cc631a8788be59fc5',
roles: [ 'ward', 'hospital', 'hr' ],
}
]};
let finalData = {};
inputArray.users.forEach((node) => {
node.roles.forEach((role) => {
finalData[role] ? finalData[role].push(node) : finalData[role] = [];
})
})
console.log(finalData);

How to link nested json relationship values objects with lodash?

i'm trying to assign/merge (really don't know which lodash function) to nested json objects.
I have the following json structure:
{
"sports": [{
"id": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d",
"name": "Soccer",
"slug": "soccer"
}],
"competitions": [{
"id": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe",
"name": "English Premier League",
"sportId": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d"
}],
"contests": [{
"id": "09cee598-7736-4941-b5f5-b26c9da113fc",
"name": "Super Domingo Ingles",
"status": "live",
"competitionId": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe"
}]
}
I want to get one contest object with their relationship linked nested. The expected object is something like this:
{
"id": "09cee598-7736-4941-b5f5-b26c9da113fc",
"name": "Super Domingo Ingles",
"status": "live",
"competition": {
"id": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe",
"name": "English Premier League",
"sport": {
"id": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d",
"name": "Soccer",
"slug": "soccer"
}
}
}]
}
How can I get this kinda of relationship done using lodash ? It can be using pure javascript as well.
You don't need any special assignment operator, or lodash. You just use the =.
ogObject = {
"sports": [{
"id": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d",
"name": "Soccer",
"slug": "soccer"
}],
"competitions": [{
"id": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe",
"name": "English Premier League",
"sportId": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d"
}],
"contests": [{
"id": "09cee598-7736-4941-b5f5-b26c9da113fc",
"name": "Super Domingo Ingles",
"status": "live",
"competitionId": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe"
}]
};
newObject = ogObject.contests[0];
for(var i = 0; i<ogObject.competitions.length;i++){
if(ogObject.competitions[i].id == newObject.competitionId){
newObject.competition = ogObject.competitions[i];
for(var j = 0; j<ogObject.sports.length;j++){
if(ogObject.sports[j].id == newObject.competition.sportId){
newObject.competition.sport = ogObject.sports[j];
break;
}
}
break;
}
}
console.log(newObject)
This might be a builtin from lodash but I doubt it. It would require predefined knowledge of your schema vis-a-vis the relationship between sportId and sports, competitionId and competitions etc...
You really need to show us what you have tried so that we can advise you about the problems that you are facing, otherwise you are just asking for a code writing service ($).
However, in ES2016 you could do this.
'use strict';
const obj = {
sports: [{
id: 'c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d',
name: 'Soccer',
slug: 'soccer',
}],
competitions: [{
id: '4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe',
name: 'English Premier League',
sportId: 'c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d',
}],
contests: [{
id: '09cee598-7736-4941-b5f5-b26c9da113fc',
name: 'Super Domingo Ingles',
status: 'live',
competitionId: '4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe',
}],
};
const transformed = obj.contests.map((contest) => {
const competition = obj.competitions.find(item => item.id === contest.competitionId);
const sport = obj.sports.find(item => item.id === competition.sportId);
const sportLevel = { ...sport };
const competitionLevel = { ...competition, sport: sportLevel };
delete competitionLevel.sportId;
const contestLevel = { ...contest, competition: competitionLevel };
delete contestLevel.competitionId;
return contestLevel;
});
console.log(JSON.stringify(transformed, null, 2));
There's no built-in lodash function that can be used to flatten relational JSON structures. But something like this should work for you:
const sourceJSON = {
"sports": [{
"id": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d",
"name": "Soccer",
"slug": "soccer"
}],
"competitions": [{
"id": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe",
"name": "English Premier League",
"sportId": "c60d0c48-151e-4fa2-bdf8-48cdfa77ad1d"
}],
"contests": [{
"id": "09cee598-7736-4941-b5f5-b26c9da113fc",
"name": "Super Domingo Ingles",
"status": "live",
"competitionId": "4c19ca7c-4d17-46ce-bb4e-e25a4ebe5dbe"
}]
}
function findSport(source, sportId) {
let sport = _.find(source['sports'], {id: sportId});
if(!sport) {
return {};
}
return {
id: sport.id,
name: sport.name,
slug: sport.slug,
}
}
function findCompetition(source, competitionId) {
let competition = _.find(source['competitions'], {id: competitionId});
if(!competition) {
return {};
}
return {
id: competition.id,
name: competition.name,
sport: findSport(source, competition.sportId),
}
}
function flattenContests(source) {
return _.map(source['contests'], (contest) => {
return {
id: contest.id,
name: contest.name,
status: contest.status,
competition: findCompetition(source, contest.competitionId),
}
});
}
console.log(flattenContests(sourceJSON));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Note that considering your original JSON, the flattened object should likely be an array of contests (since contests itself is an array) instead of a single contest object that you're expecting.

Parse array of objects recursively and filter object based on id

i have this array of objects : getCategory (variable)
[
{
"id": "20584",
"name": "Produits de coiffure",
"subCategory": [
{
"id": "20590",
"name": "Coloration cheveux",
"subCategory": [
{
"id": "20591",
"name": "Avec ammoniaque"
},
{
"id": "20595",
"name": "Sans ammoniaque"
},
{
"id": "20596",
"name": "Soin cheveux colorés"
},
{
"id": "20597",
"name": "Protection"
},
{
"id": "20598",
"name": "Nuancier de couleurs"
}
]
},
{
"id": "20593",
"name": "Soins cheveux",
"subCategory": [
{
"id": "20594",
"name": "Shampooing"
},
{
"id": "20599",
"name": "Après-shampooing"
},
{
"id": "20600",
"name": "Masques"
},
and i tried everything i could search in stackoverflow ..
lets say on this array i want to get recursively and object with the specified id .. like 20596 and it should return
{
"id": "20596",
"name": "Soin cheveux colorés"
}
The logic way i am doing is like this :
var getSubcategory = getCategory.filter(function f(obj){
if ('subCategory' in obj) {
return obj.id == '20596' || obj.subCategory.filter(f);
}
else {
return obj.id == '20596';
}
});
dont know what else to do .
Thanks
PS : I dont use it in browser so i cannot use any library . Just serverside with no other library . find dont work so i can only use filter
You need to return the found object.
function find(array, id) {
var result;
array.some(function (object) {
if (object.id === id) {
return result = object;
}
if (object.subCategory) {
return result = find(object.subCategory, id);
}
});
return result;
}
var data = [{ id: "20584", name: "Produits de coiffure", subCategory: [{ id: "20590", name: "Coloration cheveux", subCategory: [{ id: "20591", name: "Avec ammoniaque" }, { id: "20595", name: "Sans ammoniaque" }, { id: "20596", name: "Soin cheveux colorés" }, { id: "20597", name: "Protection" }, { id: "20598", name: "Nuancier de couleurs" }] }, { id: "20593", name: "Soins cheveux", subCategory: [{ id: "20594", name: "Shampooing" }, { id: "20599", name: "Après-shampooing" }, { id: "20600", name: "Masques" }] }] }];
console.log(find(data, '20596'));
console.log(find(data, ''));

AngularJS Array Comparison

I have got the following array of Usernames
Usernames = [
{
"id": 1,
"userName": "Jack",
"description": "jack is a nice guy",
"userRoleIds": [
1
]
},
{
"id": 2,
"userName": "Caroline",
"description": "Good girl",
"userRoleIds": [
2,3
]
},
{
"id": 3,
"userName": "Smith",
"description": "Smithyyyy",
"userRoleIds": [
1,2
]
}
]
And an array of userRoles.
userRoles = [
{
id: 1,
roleName: "Admin"
},
{
id: 2,
roleName: "Tester"
},
{
id: 3,
roleName: "Developer"
}
]
What i want to get done is first concat the arrays in in Usernames and userRoles to get the following result.
Usernames = [
{
"id": 1,
"userName": "Jack",
"description": "jack is a nice guy",
"userRoleIds": [
{
"id": 1,
"roleName" : "Admin"
}
]
},
{
"id": 2,
"userName": "Caroline",
"description": "Good girl",
"userRoleIds": [
{
"id": 2,
"roleName" : "Tester"
},
{
"id": 3,
"roleName" : "Developer"
}
]
},...
The second thing i want is to be able to filter for the roleName and userName seperated by pipe signs. As in type something in a text box that searches for userName and roleName for example.
if i type
Caroline, Tester
The result will be
result = [
{
"id": 2,
"userName": "Caroline",
"description": "Good girl",
"userRoleIds": [
2,3
]
},
{
"id": 3,
"userName": "Smith",
"description": "Smithyyyy",
"userRoleIds": [
1,2
]
}
]
What is the best practice for achieving this?
Thanks
Here is how I would do it. I prefer using services and take advantage of their functions to keep code clean.
app.service('UserService', function (PermisionsServices) {
var self = {
'list': [],
'load': function (Users) {//Pass your array of Users
angular.forEach(Users, function (user) {
angular.forEach(user.userRoleIds, function (role) {
self.user.userRolesIds.push(PermisionsServices.get(role));
});
self.list.push(user);
});
}, 'get': function (id) {
for (var i = 0; i < self.list.length; i++) {
var obj = self.list[i];
if (obj.id == id) {
return obj;
}
}
}
};
return self;
});
app.service('PermisionsServices', function () {
var self = {
'list': [],
'load': function (permisions) {//Pass your array of permisions
angular.forEach(permisions, function (permision) {
self.list.push(permision);
});
}, 'get': function (id) {
for (var i = 0; i < self.list.length; i++) {
var obj = self.list[i];
if (obj.id == id) {
return obj;
}
}
}
};
return self;
});
Afterwards, you can use it on your controller:
$scope.users=UserService;
And access each of the users as a separate object which can have multiple object permisions.
NOTE: Building the service (populating it) will of course depend on your app logic and controller, you could just easily remove the "load" function and just hardcode the list object by copy and pasting your arrays.
This is the approach I use to load data from API via resource.
Regards
Edit:
For use on the UI, you would just call:
<div ng-repeat='user in users.list'>
{{user.name}} has {{user.permissions}}
</div>
as the object information is already contained within it.
Edit 2:
If you want to search your data, then you can just add a filter like this:
<div ng-repeat='user in users.list | filter: filterList'>
{{user.name}} has {{user.permissions}}
</div>
And then on the controller:
$scope.filterList = function (user) {
if ($scope.filterTextBox) {
return user.name.indexOf($scope.filterTextBox) == 0;
}
return true;
}
Hope this works for you
I would do with pure JS like this. It won't take more than a single assignment line each.
var Usernames = [
{
"id": 1,
"userName": "Jack",
"description": "jack is a nice guy",
"userRoleIds": [
1
]
},
{
"id": 2,
"userName": "Caroline",
"description": "Good girl",
"userRoleIds": [
2,3
]
},
{
"id": 3,
"userName": "Smith",
"description": "Smithyyyy",
"userRoleIds": [
1,2
]
}
],
userRoles = [
{
id: 1,
roleName: "Admin"
},
{
id: 2,
roleName: "Tester"
},
{
id: 3,
roleName: "Developer"
}
],
modified = Usernames.reduce((p,c) => (c.userRoleIds = c.userRoleIds.map(e => e = userRoles.find(f => f.id == e)),p.concat(c)),[]),
query = ["Caroline","Tester"],
filtered = modified.filter(f => query.includes(f.userName) || f.userRoleIds.some(e => query.includes(e.roleName)));
console.log(JSON.stringify(modified,null,2));
console.log(JSON.stringify(filtered,null,2));
You can use lodash to achieve this.
var role = _.find(userRoles, function(role) {
return role.roleName == 'Tester';
});
_.find(Usernames, function(user) {
return user.userName == 'Caroline' || _.indexOf(user.userRoleIds, role.id)>=0;
});

Accessing second array in a JSON decode using Jquery

I need to access the second array from a JSON decoded string, but I am having no luck.
The entire JSON string is displayed in var RAW00, and then split into var RAW01 & var RAW02.
All 3 of these are for testing - RAW00 is identical to msg
When they are split - I can access either, depending on what variable I start of with, but when I use RAW00 I cannot access the tutor section.
I will provide more detail if required, but my question is:
How do I see and access the tutor array in the second $.each (nested) block??]
Thanks :-)
success: function(msg)
{
var test = "";
var raw00 = {
"allData": [
{
"class2": [
{
"tid": "1",
"name": "Monday 2"
},
{
"tid": "1",
"name": "Monday Test"
}
]
},
{
"tutor": [
{
"fname": "Jeffrey",
"lname": "Kranenburg"
},
{
"fname": "Jeffrey",
"lname": "Kranenburg"
}
]
}
]
};
var raw01 = {
"allData": [
{
"class2": [
{
"tid": "1",
"name": "Monday 2"
},
{
"tid": "1",
"name": "Monday Test"
}
]
}
]
};
var raw02 = {
"allData": [
{
"tutor": [
{
"fname": "Jeffrey",
"lname": "Kranenburg"
},
{
"fname": "Jeffrey",
"lname": "Kranenburg"
}
]
}
]
};
$.each(raw00.allData, function(index, entry)
{
$.each(entry.class2, function (index, data)
{
console.log(this.name);
test += '<tr><td>'+this.name+'</td>';
});
$.each(entry.tutor, function (index, data)
{
console.log(this.fname);
test += '<td>'+this.name+'</td></tr>';
});
$('#all-courses-table-content').html( test );
});
You need to check whether the current element of the array is an object with class2 property or tutor property.
$.each(raw00.allData, function(index, entry) {
if (entry.hasOwnProperty('class2')) {
$.each(entry.class2, function (index, data)
{
console.log(this.name);
test += '<tr><td>'+this.name+'</td>';
});
}
if (entry.hasOwnProperty('tutor')) {
$.each(entry.tutor, function (index, data)
{
console.log(this.fname);
test += '<td>'+this.fname+'</td></tr>';
});
}
$('#all-courses-table-content').html( test );
});
Things would probably be simpler if you redesigned the data structure. It generally doesn't make sense to have an array of objects when each object just has a single key and it's different for each. I suggest you replace the allData array with a single object, like this:
var raw00 = {
"allData": {
"class2": [
{
"tid": "1",
"name": "Monday 2"
},
{
"tid": "1",
"name": "Monday Test"
}
],
"tutor": [
{
"fname": "Jeffrey",
"lname": "Kranenburg"
},
{
"fname": "Jeffrey",
"lname": "Kranenburg"
}
]
}
};

Categories

Resources