0

I have an array of subscriptions group by the type (basic,medium ...) `

[
  [
    "Basic",
    [
      { "id": 2, "name": "Basic", "started_at": "2022-01-24", "count": 4 },
      { "id": 2, "name": "Basic", "started_at": "2022-03-16", "count": 2 },
      { "id": 2, "name": "Basic", "started_at": "2022-05-16", "count": 1 }
    ]
  ],
  [
    "Medium",
    [
      { "id": 3, "name": "Medium", "started_at": "2022-02-21", "count": 1 },
      { "id": 3, "name": "Medium", "started_at": "2022-05-28", "count": 1 }
    ]
  ],
  [
    "Premium",
    [{ "id": 4, "name": "Premium", "started_at": "2022-04-21", "count": 1 }]
  ],
  [
    "Master",
    [
      { "id": 7, "name": "Master", "started_at": "2022-07-28", "count": 1 },
      { "id": 7, "name": "Master", "started_at": "2022-08-02", "count": 1 }
    ]
  ],
  [
    "Jedi",
    [{ "id": 6, "name": "Jedi", "started_at": "2022-09-28", "count": 1 }]
  ]
]

`

What I want to do is return an array containing objects foreach sub with the following data(get the count value by month): `

[
  {
    label: "Basic",
    data: [4, 0, 2, 0, 1,0],
  },
  {
    label: "Medium",
    data: [0, 1, 0, 0, 1,0],
  },
  ...
]

`

The data field should contain the count field foreach subscription corresponding to the month. For example for with count 4 in January and count 2 in March it will return [4,0,1] with 0 for February.

How can I achieve that ?

I did this but it's returning only the existing month values so there is no way to know which month that value is for.

subscriptions.map((item) => {
            return {
                label: item[0],
                data: item[1].map((value, index) => {
                    return value.count;
                }),
            };
        })
4
  • Can there be multiple started_at dates on the same date/month for the same name? Can started_at also be 2022 and also be for 2023 in the one group? Commented Dec 28, 2022 at 10:40
  • 1
    Do you want for the whole year or only just the first six months? Master has data for July and August. Commented Dec 28, 2022 at 10:41
  • @NickParsons In one group yes we can have multiple objects with differents started_at Commented Dec 28, 2022 at 13:02
  • @adiga I want to print the data depending on the entries for the hole year so for master the data field should look like this [0,0,0,0,0,0,1,1,0,0,0,0] Commented Dec 28, 2022 at 13:05

1 Answer 1

2

You could reduce the array and create a mapper object which maps each plan with month specifc count. Something like this:

{
  "Basic": {
    "1": 4,
    "3": 2,
    "5": 1
  },
  "Medium": {
    "2": 1,
    "5": 1
  },
  ...
}

Then loop through the entries of the object and create objects with plan as label and an array of length: 12 and get the data for that specific month using the index

const input=[["Basic",[{id:2,name:"Basic",started_at:"2022-01-24",count:4},{id:2,name:"Basic",started_at:"2022-03-16",count:2},{id:2,name:"Basic",started_at:"2022-05-16",count:1}]],["Medium",[{id:3,name:"Medium",started_at:"2022-02-21",count:1},{id:3,name:"Medium",started_at:"2022-05-28",count:1}]],["Premium",[{id:4,name:"Premium",started_at:"2022-04-21",count:1}]],["Master",[{id:7,name:"Master",started_at:"2022-07-28",count:1},{id:7,name:"Master",started_at:"2022-08-02",count:1}]],["Jedi",[{id:6,name:"Jedi",started_at:"2022-09-28",count:1}]]];

const mapper = input.reduce((acc, [plan, subscriptions]) => {
   acc[plan] ??= {}

  for(const { started_at, count } of subscriptions)
    acc[plan][+started_at.slice(5,7)] = count
  
  return acc;
}, {})

const output = 
    Object.entries(mapper)
           .map( ([label, subData]) => ({ 
                label, 
                data: Array.from({ length: 12 }, (_, i) => subData[i+1] ?? 0) 
              }) )
              
console.log(output)

Note:

  • This assumes that the data is for a single year only. If it can be across years you'd have to create another level of nesting:

    {
      "Basic": {
        "2022": {
          "1": 3
        }
      }
    }
    
  • started_at.slice(5,7) is used to get the month number. If the dates are not in the ISO 8601 format, you can use new Date(started_at).getMonth() + 1 to get the month part.

Sign up to request clarification or add additional context in comments.

2 Comments

I have a doubt, I tried to answer by having a for each inside map(), it is not working and you have used reduce() any specific reason why reduce() and not a for loop ?
@SooryaJ you can use a for loop or a forEach with a const mapper = {} declared outside. reduce is just a functional way of doing it. map is not appropriate here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.