Array manipulation/mapping returning undefined - javascript

I'm trying to reorganise/restructure my data to send back to the api. I am mapping values into their respective new properties.
Incoming prop:
const data = [
{
otherProperty: "string",
otherPropertyTwo: "string",
personId: "1269",
peopleGroups: [
{ group: "SENIORS", groupStatus: "paid" },
{ group: "Infants", groupStatus: "not_paid" }
]
}
];
and need to restructure into this whilst not leaving in any other properties other than the ones below:
const statusArrayUpdate = [{
"personid": "1269",
"groups": [
{
"group": "seniors",
"status": "paid"
},
{
"group": "Infants",
"status": "not_paid"
}
]
}]
I tried this but getting undefined on the 2nd mapping, groups property...
const statusArrayUpdate = data.map(d => ({ ...d, personId: d.personId, groups: d.peopleGroups.map(s => [group: s.group, status: s.groupStatus]) }));

You can use map on your data array and just take the personId and rename the peopleGroups of each object, and rename groupStatus to status for each element in groups.
const data = [
{
otherProperty: "string",
otherPropertyTwo: "string",
personId: "1269",
peopleGroups: [
{ group: "SENIORS", groupStatus: "paid" },
{ group: "Infants", groupStatus: "not_paid" }
]
}
];
const statusArrayUpdate = data.map(({ personId, peopleGroups }) => ({
personId,
groups: peopleGroups.map(({ group, groupStatus }) => ({
group,
status: groupStatus
}))
}));
console.log(statusArrayUpdate)

Related

Converting an array to an object of nested objects for a tree diagram in Javascript

i'm attempting to create a Tree Diagram with react-d3-js. It needs to be in a specific format. So i need to convert the initial data that i have to the format.
This is a diagram for a shop to see the distribution chain and who is allowed to make a purchase from specific nodes.
Initial Data:
store.name = 'Absolut Chocolat' //Main Parent
store.shopconditions: [
{
"role": "agent",
"condition": ["owner", "stokist"]
},
{
"role": "stokist",
"condition": ["owner", "master stokist"]
},
{
"role": "master stokist",
"condition": ["owner"]
}
]
// If role is agent, then they are allowed to buy from 'owner' and 'stokist'
Here's the hardcoded ideal output:
orgChart = {
name: 'Absolut Chocolat',
children: [
{ name: 'Agent' },
{
name: 'Stokist',
children: [
{
name: 'Agent',
},
],
},
{
name: 'Master Stokist',
children: [
{
name: 'Stokist',
children: [
{
name: 'Agent',
},
],
},
],
},
],
};
With a few for each loops, i've gotten to the first 2 layers of the intended output but i cannot find a way to get more than that.
Here is what i got so far:
Agent node is not under Master Stokist
Current code:
let chartData = { name: store.name, children: [] };
store.shopconditions.forEach((i) => {
i.condition.forEach((c) => {
if (c === 'owner') {
chartData.children.push({ name: i.role });
}
});
});
const chartDataParser = (data) => {
data.children.map((i) => {
for (const [k, v] of Object.entries(i)) {
store.shopconditions.forEach((c) => {
c.condition.forEach((o) => {
if (o === v) {
if (!i.children) {
i.children = [{ name: c.role }];
} else {
i.children.push({ name: c.role });
}
}
});
});
}
});
};
chartDataParser(chartData);
Current output:
{
name: 'Absolut Chocolat',
children: [
{ name: 'Agent' },
{
name: 'Stokist',
children: [
{
name: 'Agent',
},
],
},
{
name: 'Master Stokist',
children: [
{
name: 'Stokist',
// Missing children: Agent Node
},
],
},
],
};
What the tree diagram should look like:
As you can see under Master Stokist node, Agent is under Stokist
The Agent node is not reached under the stokist node in the right most chain. I need a fix to my current code so it can go to that extra layer. Thanks in advance. Looking forward to learn from your answers.
You can build an object that lists children by role and then use that to recursively build the nodes of the object. Possibly something like the following:
const store = {
name: 'Absolut Chocolat',
shopconditions: [
{ "role": "agent", "condition": ["owner", "stokist"], name: 'Agent' },
{ "role": "stokist", "condition": ["owner", "master stokist"], name: 'Stockist' },
{ "role": "master stokist", "condition": ["owner"], name: 'Master Stockist' },
]
};
const build_role_map = (store) => {
let role_map = Object.fromEntries(
store.shopconditions.map((v) => [v.role, { ...v, children: [] }])
);
role_map.owner = { "role": "owner", "condition": [], children: [], name: store.name };
store.shopconditions.forEach(
({ role, condition }) => {
condition.forEach((parent) => { role_map[parent].children.push(role) })
}
);
return role_map;
};
const build_node = (role_map, { name, children }) => {
let node = { name };
if(children.length > 0)
node.children = children.map((child) => build_node(role_map, role_map[child]));
return node;
};
const build_tree = (store) => {
const role_map = build_role_map(store);
return build_node(role_map, role_map.owner);
};
console.log(build_tree(store));

Change the values in array based on some other value in React

For example the original array is
const [leads,setLeads] = useState([
{ name:"something", otherValue:"something",stage:["Converted","Rejected","Refunded"]},
{ name:"something2", otherValue:"something2", stage:["Converted w/o demo","Rejected","Refunded"] },
{ name:"something3", otherValue:"something3",stage:["Rejected","Refunded"]}
])
Here is what should happen
Now if the stage includes Converted or Converted w/o demo a field should be added named converted with a value if true or if it does not includes either of both converted should be set to false
Basically the desired result should be
[{ name:"something", otherValue:"something",stage:["Converted","Rejected","Refunded"],converted :true},
{ name:"something2", otherValue:"something2", stage:["Converted w/o demo","Rejected"],converted: true},
{ name:"something3", otherValue:"something3",stage:["Rejected","Refunded"], converted:false}]
The value should be set using set using setLeads function
You can pass a callback function to useState where you add the additional property after processing the initial array and return the resultant array to be set into state for the first time.
For processing the array, you can use Array.prototype.map and Array.prototype.includes
Post this any update to the state will need to take care of this property update too
const arr = [
{ name:"something", otherValue:"something",stage:["Converted","Rejected","Refunded"},
{ name:"something2", otherValue:"something2", stage:["Converted w/o demo","Rejected","Refunded" },
{ name:"something3", otherValue:"something3",stage:["Rejected","Refunded"],
]
const getInitialState = () => {
return arr.map(item => {
if(item.stage.includes('Converted w/o demo') || item.stage.includes('Converted')) {
return { ...item, converted: true}
} else {
return { ...item, converted: false}
}
})
}
const [leads, setLeads] = useState(getInitialState)
const array = [
{
name: 'something',
otherValue: 'something',
stage: ['Converted', 'Rejected', 'Refunded'],
},
{
name: 'something2',
otherValue: 'something2',
stage: ['Converted w/o demo', 'Rejected', 'Refunded'],
},
{
name: 'something3',
otherValue: 'something3',
stage: ['Rejected', 'Refunded'],
},
];
array.map((data, index) => {
if (data.stage.indexOf('Converted')) {
array[index].converted = true;
} else {
array[index].converted = false;
}
});
const [leads, setLeads] = useState(array);
// if Converted value exists in array then add converted=true otherwise converted=false . You can change the value accordingly above if statement if (data.stage.indexOf('Converted'))
// output
[
{
"name": "something",
"otherValue": "something",
"stage": [
"Converted",
"Rejected",
"Refunded"
],
"converted": false
},
{
"name": "something2",
"otherValue": "something2",
"stage": [
"Converted w/o demo",
"Rejected",
"Refunded"
],
"converted": true
},
{
"name": "something3",
"otherValue": "something3",
"stage": [
"Rejected",
"Refunded"
],
"converted": true
}
]

How to filter an object array based on the contents of child array?

I have this data
var data = [
{
title: "App development summary",
category: [],
},
{
title: "to experiment 2",
category: [],
},
{
title: "Some of these books I have read",
category: [
{
_id: "5f7c99faab20d14196f2062e",
name: "books",
},
{
_id: "5f7c99faab20d14196f2062f",
name: "to read",
},
],
},
{
title: "Quora users and snippets",
category: [
{
_id: "5f7c99feab20d14196f20631",
name: "quora",
},
],
},
{
title: "Politics to research",
category: [
{
_id: "5f7c9a02ab20d14196f20633",
name: "politics",
},
],
},
];
Say I want to get all the entries with the category of books. I tried doing this:
var bookCat = data.map(note => {
return note.category.map(cat => {
if(cat.name === "books" ) return note
})
})
But the result comes back with some empty and undefined arrays.
I was able to filter the empty arrays (at one point) but not the undefined
Edit
In plain English "if the object ha category.name "books", give me the title"
Filter by whether the array's category contains at least one name which is books:
var data=[{title:"App development summary",category:[]},{title:"to experiment 2",category:[]},{title:"Some of these books I have read",category:[{_id:"5f7c99faab20d14196f2062e",name:"books"},{_id:"5f7c99faab20d14196f2062f",name:"to read"}]},{title:"Quora users and snippets",category:[{_id:"5f7c99feab20d14196f20631",name:"quora"}]},{title:"Politics to research",category:[{_id:"5f7c9a02ab20d14196f20633",name:"politics"}]}];
const output = data
.filter(item => item.category.some(
({ name }) => name === 'books'
));
console.log(output);
If there's guaranteed to be only a single matching object, use .find instead:
var data=[{title:"App development summary",category:[]},{title:"to experiment 2",category:[]},{title:"Some of these books I have read",category:[{_id:"5f7c99faab20d14196f2062e",name:"books"},{_id:"5f7c99faab20d14196f2062f",name:"to read"}]},{title:"Quora users and snippets",category:[{_id:"5f7c99feab20d14196f20631",name:"quora"}]},{title:"Politics to research",category:[{_id:"5f7c9a02ab20d14196f20633",name:"politics"}]}];
const output = data
.find(item => item.category.some(
({ name }) => name === 'books'
));
console.log(output);

How To Push mutiple array elements into mongod by mongoose

There is a mongodb Schema which include these field, its type is array
......
orderlist: [
{
id: String,
price: Number,
photo: String,
name: String,
num: Number
}
]
......
The frontend post me the data such as this,this array has lots of array elements
goodslist:[
{
goodsid: '10001',
goodsprice: 20,
goodsphoto: '/goodsimg/upload_1843.jpg',
goodsname: 'goods1',
goodsnum: 2
},
{
goodsid: '10002',
goodsprice: 30,
goodsphoto: '/goodsimg/upload_1845.jpg',
goodsname: 'goods2',
goodsnum: 4
},
........(etc)
]
what can I do to push this 'goodslist' data into 'orderlist' field by mongoose without changing mongodb field, thanks
You must use mongoose virtuals to achieve this issue.
Your schema must like this:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const collectionName = 'orderlist';
const OrderSchema = new Schema({
id: String,
price: Number,
photo: String,
name: String,
num: Number
}, { minimize: false });
const OrderlistSchema = new Schema({
orderList: [OrderSchema]
}, { minimize: false, toJSON: { virtuals: true } });
OrderlistSchema.virtual('goodslist').
get(function () {
return this.orderList.map(order => ({
goodsid: order.id,
goodsprice: order.price,
goodsphoto: order.photo,
goodsname: order.name,
goodsnum: order.num
}))
}).
set(function (v) {
this.set({
orderList: v.map(good => ({
id: good.goodsid,
price: good.goodsprice,
photo: good.goodsphoto,
name: good.goodsname,
num: good.goodsnum
}))
});
});
module.exports = mongoose.model('Orderlist', OrderlistSchema, collectionName);
goodslist is virtual field here.
With this schema, you can set order field with your format without changing anything in mongodb.
Example posting document:
{
"goodslist": [
{
"goodsid": 2,
"goodsprice": 200,
"goodsphoto": "photo2",
"goodsname": "name2",
"goodsnum": 1234
}
]
}
you can also get order data in goodlist format
{
"_id": "5e9d8c0e27c7a813840c9ff0",
"orderList": [
{
"_id": "5e9d8c0e27c7a813840c9ff1",
"id": "2",
"price": 200,
"photo": "photo2",
"name": "name2",
"num": 1234
}
],
"__v": 0,
"goodslist": [
{
"goodsid": "2",
"goodsprice": 200,
"goodsphoto": "photo2",
"goodsname": "name2",
"goodsnum": 1234
}
],
"id": "5e9d8c0e27c7a813840c9ff0"
}
It going to be something like the following:
//Update order | create if does not exist
orderDB.updateOne({ _id: 'xxxx' }, {
//Push the list into order array
$push: {
orderlist: [{
id: goodlist[0][0],
price: goodlist[0][1],
photo: goodlist[0][2],
name: goodlist[0][3],
num: goodlist[0][4],
}]
}
//Upsert => update / create
}, { upsert: true })
However, you might need to loop through the goodslist.

Create a key map for all paths in a recursive/nested object array

I have an n levels deep nested array of tag objects with title and ID. What I'm trying to create is a an object with IDs as keys and values being an array describing the title-path to that ID.
I'm no master at recursion so my attempt below doesn't exactly provide the result I need.
Here's the original nested tag array:
const tags = [
{
title: 'Wood',
id: 'dkgkeixn',
tags: [
{
title: 'Material',
id: 'ewyherer'
},
{
title: 'Construction',
id: 'cchtfyjf'
}
]
},
{
title: 'Steel',
id: 'drftgycs',
tags: [
{
title: 'Surface',
id: 'sfkstewc',
tags: [
{
title: 'Polished',
id: 'vbraurff'
},
{
title: 'Coated',
id: 'sdusfgsf'
}
]
},
{
title: 'Quality',
id: 'zsasyewe'
}
]
}
]
The output I'm trying to get is this:
{
'dkgkeixn': ['Wood'],
'ewyherer': ['Wood', 'Material'],
'cchtfyjf': ['Wood', 'Construction'],
'drftgycs': ['Steel'],
'sfkstewc': ['Steel', 'Surface'],
'vbraurff': ['Steel', 'Surface', 'Polished'],
'sdusfgsf': ['Steel', 'Surface', 'Coated'],
'zsasyewe': ['Steel', 'Quality']
}
So I'm building this recursive function which is almost doing it's job, but I keep getting the wrong paths in my flat/key map:
function flatMap(tag, acc, pathBefore) {
if (!acc[tag.id]) acc[tag.id] = [...pathBefore];
acc[tag.id].push(tag.title);
if (tag.tags) {
pathBefore.push(tag.title)
tag.tags.forEach(el => flatMap(el, acc, pathBefore))
}
return acc
}
const keyMap = flatMap({ title: 'Root', id: 'root', tags}, {}, []);
console.log("keyMap", keyMap)
I'm trying to get the path until a tag with no tags and then set that path as value for the ID and then push the items 'own' title. But somehow the paths get messed up.
Check this, makePaths arguments are tags, result object and prefixed titles.
const makePaths = (tags, res = {}, prefix = []) => {
tags.forEach(tag => {
const values = [...prefix, tag.title];
Object.assign(res, { [tag.id]: values });
if (tag.tags) {
makePaths(tag.tags, res, values);
}
});
return res;
};
const tags = [
{
title: "Wood",
id: "dkgkeixn",
tags: [
{
title: "Material",
id: "ewyherer"
},
{
title: "Construction",
id: "cchtfyjf"
}
]
},
{
title: "Steel",
id: "drftgycs",
tags: [
{
title: "Surface",
id: "sfkstewc",
tags: [
{
title: "Polished",
id: "vbraurff"
},
{
title: "Coated",
id: "sdusfgsf"
}
]
},
{
title: "Quality",
id: "zsasyewe"
}
]
}
];
console.log(makePaths(tags));

Categories

Resources