-1

I have an array of objects:

const res = [
  {
    KIND_ID: 2229,
    NAME: "Group",
    SKU_ID: 311,
    ARTICLE_NAME: "Product one",
    WEEK: 202027,
    FORECAST: 81928.37,
    PROMO: 0,
    SALES: 92848,
    SAFETY_STOCK: 57704.79,
    STORES_COUNT: 132,
    ADD_FCST: null
  },
  {
    KIND_ID: 2229,
    NAME: "Group",
    SKU_ID: 311,
    ARTICLE_NAME: "Product one",
    WEEK: 202028,
    FORECAST: 84278.85,
    PROMO: 0,
    SALES: null,
    SAFETY_STOCK: 64000.39,
    STORES_COUNT: 144,
    ADD_FCST: null
  },
  {
    KIND_ID: 2229,
    NAME: "Group",
    SKU_ID: 316,
    ARTICLE_NAME: "Product two",
    WEEK: 202027,
    FORECAST: 89112.97,
    PROMO: 0,
    SALES: 98007,
    SAFETY_STOCK: 59509.31,
    STORES_COUNT: 142,
    ADD_FCST: null
  },
  {
    KIND_ID: 2229,
    NAME: "Group",
    SKU_ID: 316,
    ARTICLE_NAME: "Product two",
    WEEK: 202028,
    FORECAST: 85129.4,
    PROMO: 0,
    SALES: null,
    SAFETY_STOCK: 63409.61,
    STORES_COUNT: 144,
    ADD_FCST: null
  }
];

I want to group some fields in WEEKS, e.g:

const expected = [
  {
    KIND_ID: 2229,
    NAME: "Group",
    SKU_ID: 311,
    ARTICLE_NAME: "Product one",
    FORECAST: [{ 202026: 97555.64 }, { 202027: 98336.45 }],
    PROMO: [{ 202026: 0 }, { 202027: 0 }],
    SALES: [{ 202026: 95911.77 }, { 202027: null }],
    SAFETY_STOCK: [{ 202026: 63622.28 }, { 202027: 72852.62 }],
    STORES_COUNT: [{ 202026: 135 }, { 202027: 143 }],
    ADD_FCST: [{ 202026: null }, { 202027: null }]
  },
  {
    KIND_ID: 2229,
    NAME: "Group",
    SKU_ID: 316,
    ARTICLE_NAME: "Product two",
    FORECAST: [{ 202026: 104125.69 }, { 202027: 101147.07 }],
    PROMO: [{ 202026: 0 }, { 202027: 0 }],
    SALES: [{ 202026: 102281 }, { 202027: null }],
    SAFETY_STOCK: [{ 202026: 53709.55 }, { 202027: 60675.26 }],
    STORES_COUNT: [{ 202026: 143 }, { 202027: 144 }],
    ADD_FCST: [{ 202026: null }, { 202027: null }]
  }
];

If it helps i have array of weeks and values need to be grouped:

const weeks = [202027, 202028];
const keys = ['FORECAST','PROMO','SALES','SAFETY_STOCK','STORES_COUNT','ADD_FCST'];

I tried to solve with reduce and underscore method groupBy but this not helped. How to group this res array to expected?

Dummy text, because: It looks like your post is mostly code; please add some more details. But that's all what i want to tell

Denis
  • 300
  • 2
  • 10
  • Please elaborate on the methods you used to get the expected output. What will improve this question is simplicity. – Dane Brouwer Jul 09 '20 at 08:42
  • Does this answer your question? [using lodash .groupBy. how to add your own keys for grouped output?](https://stackoverflow.com/questions/23600897/using-lodash-groupby-how-to-add-your-own-keys-for-grouped-output) – Dane Brouwer Jul 09 '20 at 08:45

1 Answers1

1

I tried to solve with reduce

That's what I'd use, although there is a few steps involved as this isn't a classic grouping schematic.

Below is an example.

const res=[{KIND_ID:2229,NAME:"Group",SKU_ID:311,ARTICLE_NAME:"Product one",WEEK:202027,FORECAST:81928.37,PROMO:0,SALES:92848,SAFETY_STOCK:57704.79,STORES_COUNT:132,ADD_FCST:null},{KIND_ID:2229,NAME:"Group",SKU_ID:311,ARTICLE_NAME:"Product one",WEEK:202028,FORECAST:84278.85,PROMO:0,SALES:null,SAFETY_STOCK:64000.39,STORES_COUNT:144,ADD_FCST:null},{KIND_ID:2229,NAME:"Group",SKU_ID:316,ARTICLE_NAME:"Product two",WEEK:202027,FORECAST:89112.97,PROMO:0,SALES:98007,SAFETY_STOCK:59509.31,STORES_COUNT:142,ADD_FCST:null},{KIND_ID:2229,NAME:"Group",SKU_ID:316,ARTICLE_NAME:"Product two",WEEK:202028,FORECAST:85129.4,PROMO:0,SALES:null,SAFETY_STOCK:63409.61,STORES_COUNT:144,ADD_FCST:null}];


const grpFields = ['FORECAST', 'PROMO', 'SALES', 'SAFETY_STOCK',
   'STORES_COUNT', 'ADD_FCST'];

const o = res.reduce((a, v) => {
  const {KIND_ID, NAME, SKU_ID, ARTICLE_NAME} = v;
  let f = a.find(f => f.SKU_ID === v.SKU_ID);
  if (!f) {
    f = {KIND_ID, NAME, SKU_ID, ARTICLE_NAME};
    grpFields.forEach(k => f[k] = []);
    a.push(f);
  }
  grpFields.forEach(k => f[k].push({[v.WEEK]: v[k]}));
  return a;
},[]);

console.log(o);

To make this a generic function, you will need to pass a few parameters. Below is an example.

  • arr = The array your wanting to group
  • grpFields = The fields that you want the grouping applied to
  • grpValue = The field value your grouping
  • keyField = What field we are grouping on
  • stdFields = Other fields you want as part of the result

const res=[{KIND_ID:2229,NAME:"Group",SKU_ID:311,ARTICLE_NAME:"Product one",WEEK:202027,FORECAST:81928.37,PROMO:0,SALES:92848,SAFETY_STOCK:57704.79,STORES_COUNT:132,ADD_FCST:null},{KIND_ID:2229,NAME:"Group",SKU_ID:311,ARTICLE_NAME:"Product one",WEEK:202028,FORECAST:84278.85,PROMO:0,SALES:null,SAFETY_STOCK:64000.39,STORES_COUNT:144,ADD_FCST:null},{KIND_ID:2229,NAME:"Group",SKU_ID:316,ARTICLE_NAME:"Product two",WEEK:202027,FORECAST:89112.97,PROMO:0,SALES:98007,SAFETY_STOCK:59509.31,STORES_COUNT:142,ADD_FCST:null},{KIND_ID:2229,NAME:"Group",SKU_ID:316,ARTICLE_NAME:"Product two",WEEK:202028,FORECAST:85129.4,PROMO:0,SALES:null,SAFETY_STOCK:63409.61,STORES_COUNT:144,ADD_FCST:null}];


function groupData(arr, grpFields, grpValue, keyField, stdFields) {
  return arr.reduce((a, v) => {
    let f = a.find(f => f[keyField] === v[keyField]);
    if (!f) {
      f = Object.fromEntries(stdFields.map(k => [k, v[k]]));
      grpFields.forEach(k => f[k] = []);
      a.push(f);
    }
    grpFields.forEach(k => f[k].push({[v[grpValue]]: v[k]}));
    return a;
  },[]);
}

console.log(
  groupData(
    res,
    ['FORECAST', 'PROMO', 'SALES', 'SAFETY_STOCK','STORES_COUNT', 'ADD_FCST'],
    'WEEK',
    'SKU_ID',
    ['KIND_ID', 'NAME', 'SKU_ID', 'ARTICLE_NAME']
  )
);
Keith
  • 22,005
  • 2
  • 27
  • 44
  • How to make this 'o' function more flexible, without hardcode variables 'KIND_ID, NAME, SKU_ID, ARTICLE_NAME' ? As example i want to modify res array with other fields, but grouping by grpFields. – Denis Jul 21 '20 at 08:47
  • 1
    @Denis Updated to include a generic version. – Keith Jul 21 '20 at 09:37