Home > front end >  Group by nested array key
Group by nested array key

Time:11-21

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 over docs while updating a Map where the key is the detail-id and the value is the accumulated details with the docs array
  • In each iteration, iterate over the current details using Array#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 its docs array
    • Using Map#set, update the map with the new value
  • 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.

  1. Generate list of details
  2. 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));

  • Related