How do I complete an array of information with async calls? - javascript

I have this code to fill an array with info about all books a person owns:
async getAllInfo(person_id)
{
let book_list = await this.getBooks(person_id);
for(let book in book_list)
{
book_list[book]["book_info"] = await this.getBookInfo(book_list[book]["book_id"])
}
return book_list;
}
When I run the getBooks I get:
[
{
"name": "BookA",
"book_id" : "123"
},
{
"Name": "BookB",
"book_id" : "456"
}
]
And then I complete the info about the book in the for loop:
[
{
"name": "BookA",
"book_id" : "123",
"book_info": {
"author": "authorA",
"publish_year": 1900
}
},
{
"name": "BookB",
"book_id" : "456",
"book_info": {
"author": "authorB",
"publish_year": 1900
}
}
]
The getBooks and getBookInfo are http calls and when a person have lots of books it may take some time to get all the information. Is is possible to get it simultaneously for all books in the array? I tried to remove the await and use the Promise.all(), but I always get:
[
{
"name": "BookA",
"book_id" : "123",
"book_info": {
"domain": {
"domain": null,
"_events": {},
"_eventsCount": 1,
"members": []
}
}
},
{
"name": "BookB",
"book_id" : "456",
"book_info": {
"domain": {
"domain": null,
"_events": {},
"_eventsCount": 1,
"members": []
}
}
}
]

What you're doing in this piece of code can be optimised:
for(let book in book_list) {
book_list[book]["book_info"] = await this.getBookInfo(book_list[book]["book_id"])
}
Because for each book your making a request and waiting for this request to complete before fetching the details of the next book. Here is how you can perform all the requests at once and wait for all the details of the books to be retrieved:
async getAllInfo(person_id) {
let book_list = await this.getBooks(person_id);
// Creating an array of Promises to fetch the details of all the books simultaneously
const fetchingBooksDetails = book_list.map(book => this.getBookInfo(book.book_id));
// Wainting for the requests to complete
const booksDetails = await Promise.all(fetchingBooksDetails);
// Saving the details of the book in the book_list variable
booksDetails.forEach((bookDetails, index) => {
book_list[index].book_info = bookDetails;
});
return book_list;
}

Try something like this (not tested)
async getAllInfo(person_id)
{
let book_list = await this.getBooks(person_id);
for(let book in book_list)
{
book_list[book]["book_info"] = this.getBookInfo(book_list[book]["book_id"])
}
await Promise
.all(book_list[book].map(b => b.book_info))
.then(infos => {
for (book in infos)
book_list[book]["book_info"] = infos[book];
});
return book_list;
}

function getAllInfo(person_id){
return getBooks(person_id).then(function(book_list){
var promiseArray = []
book_list.forEach(function(book,index){
promiseArray.push(getBookInfo(book_list[index]["book_id"]))
})
return Promise.all(promiseArray).then(function(values){
book_list.forEach(function(book,index){
book_list[index]["book_info"] = values[index]
})
return book_list
})
})
}
function getBooks(person_id){
return new Promise(function(resolve,reject){
resolve(
[
{
"name": "BookA",
"book_id" : "123"
},
{
"Name": "BookB",
"book_id" : "456"
}
]
)
})
}
function getBookInfo(book_id){
return new Promise(function(resolve,reject){
if(book_id=="123"){
resolve({
"author": "authorA",
"publish_year": 1900
})
}
else if(book_id=="456"){
resolve({
"author": "authorB",
"publish_year": 1900
})
}
else{
reject()
}
})
}
getAllInfo("rap_mosnter").then(function(data){
console.log(data)
})

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

Javascript for loop in shows undefined

MY JSON is:
[
{
"id": "5d7d855c-7301-4b2f-9676-3cb758316b4c",
"products": [
{
"id": 1,
"price": 699.0,
"quantity": 2,
"color": "silver",
"size": "128GB"
}
],
"contact": {
"name": "5423654",
"surname": "gdfsgsdf",
"address": "gfdsg",
"phone": "53454353",
"city": "5234532",
"country": "gfdsgfds"
},
"shippingPrice": 0.0,
"discount": null,
"totalPrice": 1398.0
}
]
I am trying to loop in it with for loop in
class Orders {
_orders;
constructor() {
this.init().then(() => this.renderOrders());
}
async init() {
this._orders = await this.getOrders();
}
GET(url) {
try {
return axios.get(url)
} catch (e) {
return e;
}
}
getOrders() {
return new Promise(resolve => {
this.GET('http://localhost:8080/orders/getOrders').then(response => {
resolve(response.data);
})
})
}
renderOrders() {
const template = document.getElementById("orders__template");
const container = document.getElementById("orders");
container.innerHTML = "";
console.log(typeof this._orders);
for (let key in this._orders) {
if (this._orders.hasOwnProperty(key)) {
for (let productKey in this._orders[key].products) {
if (this._orders[key].products.hasOwnProperty(productKey)) {
console.log(this._orders[key].products[productKey].id); //getting the id
}
}
for (let discountKey in this._orders[key].discount) {
if (this._orders[key].discount.hasOwnProperty(discountKey)) {
console.log(this._orders[key].discount[discountKey].id); //undefined(even when it's not null, why?
}
}
for (let contactKey in this._orders[key].contact) {
if (this._orders[key].contact.hasOwnProperty(contactKey)) {
console.log(this._orders[key].contact[contactKey].name); //undefined too
}
}
}
}
}
document.addEventListener("DOMContentLoaded", () => {
new Orders();
});
However, i am getting only at first for loop result, other discount, or contact are undefined.
i tried with other dummy data, i am getting the same results, so, what is the problem? However, i have other examples where it do work, the same structure, whats wrong?
in the orders object, property discount and contact are not arrays so you don't need to use for loop:
for (let key in order) {
if (order.hasOwnProperty(key)) {
for (let productKey in order[key].products) {
if (order[key].products.hasOwnProperty(productKey)) {
console.log(order[key].products[productKey].id); //getting the id
}
}
if (order[key].discount) {
console.log(order[key].discount.id);
}
if (order[key].contact) {
console.log(order[key].contact.name);
}
}
}

Skip JSON.map() for the subsequent elements

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

Filter the JSON - Angular 8

{"data": [
{
"client": {
"name": "TEST NAME",
"client_id": "id_client_boU6cpFX55vkLCXt52TSVB"
},
"Pay_list": [
{
"pay_id": "id_pay_aAW6mEvsCpBVT4aASDERTY"
},
{
"pay_id": "id_pay_aAW6mEvsCpBVT4aTDgVCSD"
}
],
"company": {
"name": "ABCD",
"ID": "1234"
}
},
{
"client": {
"name": "TEST NAME",
"client_id": "id_client_boU6cpFX55vkLCXt52TSVB"
},
"Pay_list": [
{
"pay_id": "id_pay_aAW6mEvsCpBVT4aASQQQW"
},
{
"pay_id": "id_pay_aAW6mEvsCpBVT4aTDDFGE"
},
{
"pay_id": "id_pay_aAW6mEvsCpBVT4aTDgVDFE"
}
],
"company": {
"name": "fBfD",
"ID": "5214"
}
},
]
}
JSON
I need to filter this JSON and get the company name.
this.Detail = result.data.filter(item => item.client.client_id== this.client_client_id && item.Pay_list.pay_id == this.PayId);
I have tried the above code and it trow the error because Pay_list is an array.
How can I filter the above JSON? Please assist me.
You can try this snippet instead. Have attached a Stackblitz Demo for your reference :
Possible variables needed for filter:
const clientId = "id_client_boU6cpFX55vkLCXt52TSVB";
const payId = "id_pay_aAW6mEvsCpBVT4aASDERTY";
Code
const result = response
.data
.filter(({ client: { client_id }, Pay_list }) => client_id === clientId && Pay_list.some(pay => pay.pay_id === payId))[0]
.company
.name;
Result:
ABCD
Here you go:
const client_id = 'id_client_boU6cpFX55vkLCXt52TSVB';
const pay_id = 'id_pay_aAW6mEvsCpBVT4aASQQQW';
const filtered = result.data.filter((item) => {
if (item.client.client_id !== client_id) return false;
if (item.Pay_list.map(({ pay_id }) => pay_id).includes(pay_id)) return false;
return true;
});
try this:
const client_id = 'id_client_boU6cpFX55vkLCXt52TSVB';
const pay_id = 'id_pay_aAW6mEvsCpBVT4aASQQQW';
const result = response
.data
.filter(({ client: { client_id }, Pay_list }) => client_id === clientId && Pay_list.some(pay => pay.pay_id === payId))[0]
.company
.name;

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

Categories

Resources