Skip JSON.map() for the subsequent elements - javascript
DEMO
(Please check the browser console for output)
I have a JSON customerItemResponse in a format
{
"totalResults": someNumber,
"results": [
{
"totalItem": 406,
"customerId": "10000"
},
{
"totalItem": 468,
"customerId": "10001"
},
{
"totalItem": 20,
"customerId": "10002"
},
...
Then I have another JSON customerInfo:
{
"totalResults": someNumber,
"results": [
{
"customerId": "10000",
"region": "4",
"area": "42",
},
{
"customerId": "10001",
"region": "4",
"area": "43",
},
{
"customerId": "10002",
"region": "5",
"area": "52",
},
Now I have to create a JSON in a format
[
{
region:'4'
regionDetails:[
{
area:'42'
customerDetails:[
{
customerId:'10000'
totalItem:406
},
{
customerId:'10005'
totalItem:301
},
]
},
{
area:'11'
customerDetails:[
{
customerId:'10010'
totalItem:11
},
{
customerId:'10021'
totalItem:105
},
]
},
]
},
{
region:'5'
regionDetails:[
{
area:'52'
customerDetails:[
{
customerId:'10002'
totalItem:52
},
{
customerId:'10027'
totalItem:310
},
]
},
{
area:'41'
customerDetails:[
{
customerId:'10017'
totalItem:109
},
{
customerId:'10041'
totalItem:450
},
]
},
]
}
]
This is the logic I have written:
customerData=<CustomerDataInterface[]>[]
mapJson() {
this.customerItemResponse.map((res, index) => {
this.customerInfo.find((obj) => {
if (obj.customerId == res.customerId) {
this.customerData.length
? this.customerData.map((data, index1) => {
if (data.region == obj.region) {
data.regionDetails.length
? data.regionDetails.map((regDetails, index2) => {
if (regDetails.area == obj.area) {
regDetails.dealerDetails.push({
customerId: obj.customerId,
totalItem: res.totalItem,
});
return;
}
if (index2 == data.regionDetails.length - 1) {
data.regionDetails.push({ area: obj.area, dealerDetails: [] });
}
})
: data.regionDetails.push({ area: obj.area, dealerDetails: [] });
return;
}
if (index1 == this.customerData.length - 1) {
this.customerData.push({ region: obj.region, regionDetails: [] });
}
})
: this.customerData.push({ region: obj.region, regionDetails: [] });
}
});
});
console.log(this.customerData);
}
Now the output of the console has several region repeated. And suppose if I have 6 unique region but the this.customerData.length is 31.
I think return; is not working as expected. And is not skipping the subsequent element.
here is an efficient way to resolving the issue using js Maps. We can build maps with info about corresponding region and then areas. and after the data is built into maps - convert it back to simple js structures, such as object and arrays
mapJson() {
const customerToTotalMap = new Map(this.customerItemResponse.map(({customerId, totalItem}) => [customerId, totalItem]));
const regionsMap = new Map();
for(let {customerId, region, area} of this.customerInfo) {
let regionAreas;
if(regionsMap.has(region)) {
regionAreas = regionsMap.get(region);
} else {
regionAreas = new Map();
regionsMap.set(region, regionAreas);
}
let areaInfo;
if(regionAreas.has(area)) {
areaInfo = regionAreas.get(area);
} else {
areaInfo = [];
regionAreas.set(area, areaInfo);
}
areaInfo.push({customerId, totalItem: customerToTotalMap.get(customerId)});
}
this.customerData = [...regionsMap.entries()].map(([region, areas]) => ({
region,
regionDetails: [...areas.entries()].map(([area, customerDetails]) => ({
area,
customerDetails
}))
}))
console.log(this.customerData);
}
This is similar to #Andrei's answer. It creates an object literal as mapper. Also, it uses mapping between the region and area when they are created. So, finally you can just get the values of the regionMapper object without going through the mapper objects again
const customerItemResponse=[{customerId:10000,totalItem:77},{customerId:10001,totalItem:37},{customerId:10002,totalItem:295},{customerId:10003,totalItem:458},{customerId:10004,totalItem:248},{customerId:10005,totalItem:35},{customerId:10006,totalItem:280},{customerId:10007,totalItem:147},{customerId:10008,totalItem:439},{customerId:10009,totalItem:401},{customerId:10010,totalItem:489},{customerId:10011,totalItem:414},{customerId:10012,totalItem:287},{customerId:10013,totalItem:391},{customerId:10014,totalItem:125},{customerId:10015,totalItem:207},{customerId:10016,totalItem:197},{customerId:10017,totalItem:151},{customerId:10018,totalItem:225},{customerId:10019,totalItem:333},{customerId:10020,totalItem:361},{customerId:10021,totalItem:225},{customerId:10022,totalItem:242},{customerId:10023,totalItem:150},{customerId:10024,totalItem:52},{customerId:10025,totalItem:475},{customerId:10026,totalItem:494},{customerId:10027,totalItem:30},{customerId:10028,totalItem:189},{customerId:10029,totalItem:112},{customerId:10030,totalItem:482},{customerId:10031,totalItem:283},{customerId:10032,totalItem:159},{customerId:10033,totalItem:440},{customerId:10034,totalItem:461},{customerId:10035,totalItem:76},{customerId:10036,totalItem:84},{customerId:10037,totalItem:392},{customerId:10038,totalItem:296},{customerId:10039,totalItem:293},{customerId:10040,totalItem:135},{customerId:10041,totalItem:348},{customerId:10042,totalItem:338},{customerId:10043,totalItem:444},{customerId:10044,totalItem:15},{customerId:10045,totalItem:32},{customerId:10046,totalItem:67},{customerId:10047,totalItem:277},{customerId:10048,totalItem:65},{customerId:10049,totalItem:95},{customerId:10050,totalItem:290}],
customerInfo=[{customerId:10000,region:"3",area:"32"},{customerId:10001,region:"2",area:"22"},{customerId:10002,region:"2",area:"25"},{customerId:10003,region:"3",area:"31"},{customerId:10004,region:"2",area:"25"},{customerId:10005,region:"1",area:"11"},{customerId:10006,region:"1",area:"14"},{customerId:10007,region:"5",area:"55"},{customerId:10008,region:"5",area:"51"},{customerId:10009,region:"4",area:"45"},{customerId:10010,region:"1",area:"14"},{customerId:10011,region:"1",area:"12"},{customerId:10012,region:"3",area:"33"},{customerId:10013,region:"2",area:"25"},{customerId:10014,region:"4",area:"41"},{customerId:10015,region:"3",area:"32"},{customerId:10016,region:"5",area:"55"},{customerId:10017,region:"2",area:"23"},{customerId:10018,region:"3",area:"33"},{customerId:10019,region:"5",area:"51"},{customerId:10020,region:"4",area:"42"},{customerId:10021,region:"1",area:"12"},{customerId:10022,region:"1",area:"14"},{customerId:10023,region:"1",area:"14"},{customerId:10024,region:"1",area:"13"},{customerId:10025,region:"4",area:"45"},{customerId:10026,region:"3",area:"34"},{customerId:10027,region:"2",area:"24"},{customerId:10028,region:"4",area:"45"},{customerId:10029,region:"2",area:"22"},{customerId:10030,region:"2",area:"22"},{customerId:10031,region:"2",area:"21"},{customerId:10032,region:"3",area:"33"},{customerId:10033,region:"1",area:"11"},{customerId:10034,region:"3",area:"33"},{customerId:10035,region:"3",area:"32"},{customerId:10036,region:"2",area:"22"},{customerId:10037,region:"4",area:"41"},{customerId:10038,region:"3",area:"31"},{customerId:10039,region:"5",area:"51"},{customerId:10040,region:"2",area:"23"},{customerId:10041,region:"4",area:"45"},{customerId:10042,region:"1",area:"14"},{customerId:10043,region:"5",area:"54"},{customerId:10044,region:"3",area:"34"},{customerId:10045,region:"5",area:"51"},{customerId:10046,region:"4",area:"42"},{customerId:10047,region:"5",area:"53"},{customerId:10048,region:"1",area:"11"},{customerId:10049,region:"3",area:"35"},{customerId:10050,region:"5",area:"51"}];
const customerItemMapper = {}
for (const c of customerItemResponse)
customerItemMapper[c.customerId] = c.totalItem
const regionMapper = {},
areaMapper = {};
for (const { customerId, region, area } of customerInfo) {
let regionKey = `Region_${region}`,
areaKey = `Area_${area}`,
totalItem = customerItemMapper[customerId];
if (!(regionKey in regionMapper))
regionMapper[regionKey] = { region, regionDetails: [] }
if (!(areaKey in areaMapper)) {
const o = { area, customerDetails: [] }
areaMapper[areaKey] = o;
regionMapper[regionKey].regionDetails.push(o) // area-region relation
}
areaMapper[areaKey].customerDetails.push({ customerId, totalItem })
}
console.log(Object.values(regionMapper))
Related
nested filter array javascript
I want to create a nested filter in js when I filter my array primary data is affected and changed but I need preliminary data to remove filters my js code : let result = companies; result.map((item, i) => {212 let rows = [...result[i].table.table_rows].filter((item3) => { return Object.keys(item3).some(i => item3[i][key] === value[key]); }); result[i].table.table_rows = [...rows]; return result[i]; }); arrayFilter(result); my data is: { "companies": [ { "company": { "name": "company 1" }, "table": { "table_rows": [ { "cells": { "product_name": "prod1", "pa_size": "12" } }, { "cells": { "product_name": "prod2", "pa_size": "15" } } ] } }, { "company": { "name": "company 2" }, "table": { "table_rows": [ { "cells": { "product_name": "prod2-1", "pa_size": "12" } }, { "cells": { "product_name": "prod2-2", "pa_size": "18" } } ] } } ] } I tried many ways to solve this problem, but I did not get the right answer
Your question is not clear, the point I have understand that you wanted to filter the array "table_rows" located inside each companies array object? map and filter returns new array, so the solution for this is: result = result.companies.map((item, i) => { const newItem = {...item}; let rows = newItem .table.table_rows.filter((item3) => { return Object.keys(item3).some(i => item3[i][key] === value[key]); }); newItem.table_rows = [...rows]; return newItem ; }); arrayFilter(result);
Converting one json object to another with jquery
i have an input json object , and i want the below output json from a jquery function . How can i achieve it with min lines of code . Input { "dashboardWidgetFacility": [{ "deskUsageInput": { "breakup": [{ "location_breakup_0": ["{\"id\":1,\"name\":\"campus\"},{\"id\":8,\"name\":\"building \"}"], "teams_breakup_0": ["3", "6"] }, { "location_breakup_1": ["{\"id\":1,\"name\":\"campus\"},{\"id\":8,\"name\":\"building \"},{\"id\":83,\"name\":\"floor \"}"], "teams_breakup_1": ["3", "2"] }] } }] } Output Object { "dashboardWidgetFacility": [{ "campus": { "id": 1 }, "building": { "id": 8 }, "widgetInput": { "deskUsageInput": { "teams": ["3", "6"] } } }, { "campus": { "id": 1 }, "building": { "id": 8 }, "floor": { "id": 83 }, "widgetInput": { "deskUsageInput": { "teams": ["3", "2"] } } }] } Here location breakup location_breakup_{index} , has the index.
I had to correct those location_breakup values because you have to parse out the json, but theyre not technically valid json on their own since theyre missing the square brackets on the sides. const input = { dashboardWidgetFacility: [ { deskUsageInput: { breakup: [ { location_breakup_0: [ '{"id":1,"name":"campus"},{"id":8,"name":"building "}', ], teams_breakup_0: ['3', '6'], }, { location_breakup_1: [ '{"id":1,"name":"campus"},{"id":8,"name":"building "},{"id":83,"name":"floor "}', ], teams_breakup_1: ['3', '2'], }, ], }, }, ], }; const output = Object.values( input.dashboardWidgetFacility[0].deskUsageInput.breakup ).reduce( (acc, item) => { const nestedItem = Object.keys(item).reduce((acc, key) => { let locationParsed; let teamsBreakup; if (key.startsWith('location_breakup')) { locationParsed = JSON.parse('[' + item[key] + ']'); } if (key.startsWith('teams_breakup')) { teamsBreakup = item[key]; } const obj = (locationParsed || []).reduce( (acc, item) => { const { name, id } = item; return { ...acc, [name.trim()]: { id, }, }; }, { widgetInput: { deskUsageInput: { teams: null, }, }, } ); obj.widgetInput.deskUsageInput.teams = teamsBreakup; return { ...acc, ...obj, }; }, {}); return { dashboardWidgetFacility: [...acc.dashboardWidgetFacility, nestedItem], }; }, { dashboardWidgetFacility: [], } ); console.log(output);
How in JS to merge in one object two json objects where the ID of on object correspond on the same ID of the second object
My question relates to the fact I'm querying 2 different objects from DB and the result is in JSON. I need to merge them into one. The 2 objects have in common this two key/value IRBId = ... and id = ... and they look as an example OBJ 1 { "data":{ "IRBs":{ "nodes":[ { "id":"8", "name":"Admin ", }, { "id":"9", "name":"Again", } ], } } } OBJ 2 { "data":{ "informedConsentForms":{ "count":3, "nodes":[ { "id":"93", ... "IRBId":"9", }, { "id":"92", ... "IRBId":"8", }, { "id":"91", ... "IRBId":"8", } ], } }, As you will see above OBJ 2 and OBJ 1 corresponding with the same at IRBid and id. What I need is to merge the two OBJ where IRBId OBJ 2 === id OBJ 1 The result I would expect after the merge is OBJ merged { [{ "id":"93", ... "IRBId":"9", "irb": { "name":"Again ", ... } }, { "id":"92", ... "IRBId":"8", "irb": { "name":"Admin ", ... } }, { "id":"91", ... "IRBId":"8", "irb": { "name":"Admin ", ... } ], }, I don't know how to make it looks like this.
Try using Array.reduce Logic Loop through second object data nodes Find the matching nodes from object 1 data nodes. Push to accumulator with required details. (I have added only the nodes that was mentioned in in Expected resut, you can add asmuch as you need.) const obj1 = { "data": { "IRBs": { "nodes": [ { "id": "8", "name": "Admin ", }, { "id": "9", "name": "Again", } ], } } } const obj2 = { "data": { "informedConsentForms": { "count": 3, "nodes": [ { "id": "93", "IRBId": "9", }, { "id": "92", "IRBId": "8", }, { "id": "91", "IRBId": "8", } ], } }, }; const obj1List = obj1.data.IRBs.nodes; const output = obj2.data.informedConsentForms.nodes.reduce((acc, curr) => { const matchingNode = obj1List.find((item) => item.id === curr.IRBId); if (matchingNode) { acc.push({ id: curr.id, IRBId: curr.IRBId, irb: { name: matchingNode.name } }) } return acc; }, []); console.log(output);
You need to use the map function on the nodes in the first object to construct a new object that contains the second and first object's attributes. const obj1 = { "data": { "IRBs": { "nodes": [{ "id": "8", "obj1": "one", "name": "Admin ", }, { "id": "9", "obj1": "two", "name": "Again", } ] } } }; const obj2 = { "data": { "informedConsentForms": { "count": 3, "nodes": [{ "id": "93", "obj2": "1", "IRBId": "9", }, { "id": "92", "obj2": "2", "IRBId": "8", }, { "id": "91", "obj2": "3", "IRBId": "8", } ], } } }; const obj1Data = obj1.data.IRBs.nodes; const obj2Data = obj2.data.informedConsentForms.nodes; const res = obj2Data.map(item => { const obj1Item = obj1Data.find(obj1Item => item.IRBId === obj1Item.id); return obj1Item ? { ...item, "irb": { ...obj1Item}} : { ...item}; }); console.log(res);
i am using nested loop, try this one const obj2 = { "data":{ "informedConsentForms":{ "count":3, "nodes":[ { "id":"93", "IRBId":"9", }, { "id":"92", "IRBId":"8", }, { "id":"91", "IRBId":"8", } ], } }, } const obj1 = { "data":{ "IRBs":{ "nodes":[ { "id":"8", "name":"Admin ", }, { "id":"9", "name":"Again", } ], } } } const result = []; const obj2Nodes = obj2.data.informedConsentForms.nodes; for(let i = 0; i < obj2Nodes.length; i++) { const obj1Nodes = obj1.data.IRBs.nodes for(let j = 0; j < obj1Nodes.length; j++) { if(obj2Nodes[i].IRBId === obj1Nodes[j].id) { const {id, ...reObj1Nodes} = obj1Nodes[j]; result.push({ ...obj2Nodes[i], 'irb': { ...reObj1Nodes } }) } } } console.log(result)
recursion with Promises
I have a collection in MongoDB like this [ { "classId": "1", "name": "Input", "definition": [ { "property": [ { "classId": "12", "name": "One" }, { "classId": "8", "name": "Comment" } ] } ] }, { "classId": "8", "name": "CommentDetail", "definition": [ { "property": [ { "classId": "10", "name": "user" }, { "classId": "10", "name": "message" } ] } ] }, { "classId": "10", "name": "String", "definition": [] }, { "classId": "12", "name": "Int", "definition": [] } ] Based on db above, I have a model to display data = { name:'', template: '' } With classId=1, the expectation result is { "Name": "Input", "temlate": "{['One': 'Int','Comment': ['user': 'String','message':'String']]}" } I try to using recursive promise to implement it. When property[] is empty, the result will be return. Here is my function: const getObjectTypeByClassId = (snapshotId, artifactId, objectType) => { return artifactDetailModel.find({ 'snapshotId': snapshotId, 'artifactId': artifactId }) .then(data => { let artifact = data[0]; let definition; let definitionData = {}; return Promise.resolve() .then(() => { definition = artifact.data.teamworks.twClass[0].definition[0]; if (!lodash.isUndefined(definition.property)) { const listOfProperty = definition.property; for (let property of listOfProperty) { classId = commonUtil.getArtifactId(property.classRef[0]); if (!lodash.isUndefined(classId)) { return getObjectTypeByClassId(snapshotId, classId, objectType); } } } else { definitionData.nameType = artifact.data.teamworks.twClass[0].elementAttribute.name; definitionData.classId = artifact.data.teamworks.twClass[0].elementAttribute.id; definitionData.template = bpmMapping.objectType[artifact.data.teamworks.twClass[0].elementAttribute.name]; return objectTypeModel.create(definitionData) .then(obj => { const response = { name: objectType.name, isArrayOf: objectType.isArrayOf, nameType: obj.nameType, template: obj.template, } return response; }) } }) }) } Run with my function, the response is data: { Name: Input temlate: user: String, } Please advice me.
I tried it to some extent, but wasn't able to get it right. Plus your expected output is not the valid JSON "temlate": {[]} doesn't make sense. It has nothing to do with Promise. You have to DFS you db array and created expected output. Here is what I have donup tillll now, you can think along those lines. But this is far from the solution. let mainArray = [ { "classId": "1", "name": "Input", "definition": [ { "property": [ { "classId": "12", "name": "One" }, { "classId": "8", "name": "Comment" } ] } ] }, { "classId": "8", "name": "CommentDetail", "definition": [ { "property": [ { "classId": "10", "name": "user" }, { "classId": "10", "name": "message" } ] } ] }, { "classId": "10", "name": "String", "definition": [] }, { "classId": "12", "name": "Int", "definition": [] } ] function dfs(root, createdRoot, fn, level) { fn(root,createdRoot, level); if(root.definition)/*if definition exists => keep traversing*/ root.definition[0].property.forEach(function (child) { createdRoot.template = createdRoot.template || []; let tempObj = {}; let lookupObj = lookupByClassId(child.classId); tempObj[child.name] = lookupObj.name; createdRoot.template.push(tempObj); dfs(child,tempObj, fn, level + 1); }); else /*if definition doesn't exist, look into the array*/ { createdRoot.template = lookupByClassId(root.classId); } } function lookupByClassId(classId){ for(let i=0;i<mainArray.length;++i){ let element =mainArray[i] if(element.classId == classId) return element; } } let root = lookupByClassId(1); createdRoot ={}; function func1(root, createdRoot, level) { createdRoot.name = root.name; console.log(root.classId); } dfs(root, createdRoot, func1, 0);
here is the solution from a guy on the internet. it works well. Thanks, #Cuong Quach var MongoClient = require('mongodb').MongoClient; var database = 'testdequy'; var collection = 'classes'; MongoClient.connect("mongodb://localhost:27017/" + database, function (err, db) { findDetails("1").then((r) => { console.log("r>>>", r); }) function findDetails(classId) { var results = { Name: "", Template: "" }; var template = {}; return new Promise((main_resolve, reject) => { process(template, "" , classId) var works = 0; function process(parent, childKey, objectId) { return new Promise((resolve, reject) => { db.collection(collection).find({ classId: objectId }) .toArray((err, docs) => { if (results.Name == "") { results.Name = docs[0].name; } let objectItem; if (childKey == "") objectItem = parent; else objectItem = parent[childKey]; console.log("\ndocs", docs[0], objectId, objectItem) if (docs[0].definition.length == 0 || docs[0].definition[0].property == undefined) { let name = docs[0].name; parent[childKey] = name; console.log("\nNo child", docs[0],parent, objectItem, docs[0].name) resolve(0); } else { docs[0].definition[0].property.forEach((item) => { works++; //console.log("item", item) let id = item.classId; let name = item.name; objectItem[name] = {}; process(objectItem, name, id).then((len)=>{ works--; if(len == 0 && works == 0) main_resolve(template); }) }) resolve(docs[0].definition[0].property.length) } }) }) } }) } });
How i can get data from another object?
Plunker I have two structures - ingredients and recipes [{ "id":"1", "name": "Cucumber" }, .. ] and [{ "id":"1", "name": "Salad1", "recipein":[1, 3, 5] }, { ... } ] and i want to show names of ingredients in each salad by press a button. I filtered object to get ID of object, then i try to get a array of ingredients getSalad(param:number) { this.saladId = this.recipe.filter(rec => { return rec.id.includes(param); }) this.getNameOfIngredients(this.saladId) } getNameOfIngredients(saladArray:any) { var ingredientsId = saladArray.map(function(num) { return num.recipein; }); i getting array [1,2,4] now i want to show all names of ingredients from this.ingredients with this array of id's. How can i do this? Plunker
I made updates in your plunker. I think thats what are you looking for: Plunker getSalad(param:number) { this.saladId = this.recipe.filter(rec => +rec.id === param )[0]; if(!this.saladId){ this.currentSalad = "Salad not found"; return; } this.currentSalad = this.getNameOfIngredients(this.saladId) } getNameOfIngredients(saladArray:any) { return this.ingredients.filter( ing => { return saladArray.recipein.indexOf(+ing.id) !== -1; });
let _ingredients = [] this.ingredients.foreach((ingr)=>{ if(this.ingreIDArry.indexof(ingr.id) > -1){ _ingredients.push(ingr.name) } }) return _ingredients is this what you want?
if you can flatten the array, it would be very straightforward for us to do lookups. Here is what you could do. const salads = [{ "id": "1", "name": "Salad1", "recipein": [1, 3, 5] }]; const ingredients = [{ "id": "1", "name": "Cucumber" }, { "id": "2", "name": "Cucumber2" }, { "id": "3", "name": "Cucumber3" }, { "id": "4", "name": "Cucumber4" }, { "id": "5", "name": "Cucumber5" } ]; const flattenIngredients = (() => { const output = {}; ingredients.forEach((ingredient) => { output[ingredient.id] = ingredient; }); return output; })(); const getSalad = (saladId) => { const filteredSalad = salads.filter((salad) => { return saladId == salad.id; }); if (filteredSalad.length > 0) { const salad = filteredSalad[0]; return salad.recipein.map((receip) => flattenIngredients[receip].name); } } console.log(getSalad(1));