I have some example data that shows some data related to docs (docs.id
) and the people which it refers to (details.id
) :
const docs = [
{
id: "89",
state: "accepted",
details: [
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
first_name: "First Name",
last_name: "Last Name",
type_label: "claimant"
}
]
},
{
id: "45",
state: "accepted",
details: [
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
first_name: "First Name",
last_name: "Last Name",
type_label: "claimant"
},
{
id: 20657,
type: "Fellow",
name: "Fellow First Name Fellow Last Name",
first_name: "Fellow First Name",
last_name: "Fellow Last Name",
type_label: "fellow"
}
]
},
{
id: "47",
state: "rejected",
details: [
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
first_name: "First Name",
last_name: "Last Name",
type_label: "claimant"
}
]
}
]
const groups = docs.reduce((groups, item) => {
const group = groups[item.details] || [];
group.push(item);
groups[item.details] = group;
return groups;
}, {});
console.log("groups: ", groups);
I'm trying to manipulate this array so that I could group per person (details.id
) all her related docs (docs.id
) so that I can later on use the results in react app but it's not working like that.
EDIT (adding expected result):
const new = [
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
docs: [89,45,47]
},
{
id: 20656,
type: "Fellow",
name: "Fellow First Name Fellow Last Name",
docs: [47]
}
]
CodePudding user response:
Using reduce()
is a right choice,but we need to iterate the details
array
let result = docs.reduce((a,v)=>{
let docId = v.id
v.details.forEach(d => {
let pId = d.id
let obj = a.find(i => i.personId === pId)
if(obj){
obj.docId.push(docId)
}else{
a.push({'personId':pId,'docId':[docId]})
}
})
return a
},[])
const docs = [
{
id: "89",
state: "accepted",
details: [
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
first_name: "First Name",
last_name: "Last Name",
type_label: "claimant"
}
]
},
{
id: "45",
state: "accepted",
details: [
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
first_name: "First Name",
last_name: "Last Name",
type_label: "claimant"
},
{
id: 20657,
type: "Fellow",
name: "Fellow First Name Fellow Last Name",
first_name: "Fellow First Name",
last_name: "Fellow Last Name",
type_label: "fellow"
}
]
},
{
id: "47",
state: "rejected",
details: [
{
id: 20656,
type: "Claimant",
name: "First Name Last Name",
first_name: "First Name",
last_name: "Last Name",
type_label: "claimant"
}
]
}
]
let result = docs.reduce((a,v)=>{
let docId = v.id
v.details.forEach(d => {
let pId = d.id
let obj = a.find(i => i.personId === pId)
if(obj){
obj.docId.push(docId)
}else{
a.push({'personId':pId,'docId':[docId]})
}
})
return a
},[])
console.log(result)
CodePudding user response:
- Using
Array#reduce
, iterate overdocs
while updating aMap
where the key is the detail-id and the value is the accumulated details with thedocs
array - In each iteration, iterate over the current
details
usingArray#forEach
:- Using
Map#get
, get the accumulated object for the current detail-id, otherwise use an initial one - Using
Array#push
, add the doc-id to itsdocs
array - Using
Map#set
, update the map with the new value
- Using
- Using
Map#values
, return the list of grouped items
const docs = [
{
id: "89",
state: "accepted",
details: [
{ id: 20656, type: "Claimant", name: "First Name Last Name", first_name: "First Name", last_name: "Last Name", type_label: "claimant" }
]
},
{
id: "45",
state: "accepted",
details: [
{ id: 20656, type: "Claimant", name: "First Name Last Name", first_name: "First Name", last_name: "Last Name", type_label: "claimant" },
{ id: 20657, type: "Fellow", name: "Fellow First Name Fellow Last Name", first_name: "Fellow First Name", last_name: "Fellow Last Name", type_label: "fellow" }
]
},
{
id: "47",
state: "rejected",
details: [
{ id: 20656, type: "Claimant", name: "First Name Last Name", first_name: "First Name", last_name: "Last Name", type_label: "claimant" }
]
}
];
const groups = [...
docs.reduce((detailMap, { id: docId, state, details = [] }) => {
details.forEach(({ id, type, name }) => {
const detail = detailMap.get(id) ?? { id, type, name, docs: [] };
detail.docs.push(docId);
detailMap.set(id, detail);
});
return detailMap;
}, new Map)
.values()
];
console.log("groups: ", groups);
CodePudding user response:
Logic.
- Generate list of details
- Group it against the id.
Array.reduce
implementation
const docs = [
{
id: "89",
state: "accepted",
details: [
{ id: 20656, type: "Claimant", name: "First Name Last Name", first_name: "First Name", last_name: "Last Name", type_label: "claimant" },
],
},
{
id: "45",
state: "accepted",
details: [
{ id: 20656, type: "Claimant", name: "First Name Last Name", first_name: "First Name", last_name: "Last Name", type_label: "claimant" },
{ id: 20657, type: "Fellow", name: "Fellow First Name Fellow Last Name", first_name: "Fellow First Name", last_name: "Fellow Last Name", type_label: "fellow" },
],
},
{
id: "47",
state: "rejected",
details: [
{ id: 20656, type: "Claimant", name: "First Name Last Name", first_name: "First Name", last_name: "Last Name", type_label: "claimant" },
],
},
];
const groups = docs
.map((node) => node.details.map((item) => ({
id: item.id,
type: item.type,
name: item.name,
parentId: node.id,
})))
.flat()
.reduce((acc, curr) => {
acc[curr.id] = acc[curr.id] ?? curr;
if (acc[curr.id].docs) {
acc[curr.id].docs.push(curr.parentId)
} else {
acc[curr.id].docs = [curr.parentId]
}
return acc;
}, {})
console.log(Object.values(groups));