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