Sean
Sean

Reputation: 534

React.js: Combining properties from an Array of Objects

I have an Array of Objects where I'm trying to combine a couple of the properties and then return a new Array of Objects. Below is an example of the structure of the original Array of Objects:

[
      {
        "memID": "180",
        "memType": "Movie",
        "date": {
          "month": 5,
          "year": 1980
        },
        "favourite": null,
        "public": null,
        "music": [],
        "movie": [
          {
            "poster": "https://image.tmdb.org/t/p/original//7BuH8itoSrLExs2YZSsM01Qk2no.jpg"
          }
        ],
        "tvshow": [],
        "game": []
      },
      {
        "memID": "65",
        "memType": "Game",
        "date": {
          "month": 5,
          "year": 1980
        },
        "favourite": null,
        "public": null,
        "music": [],
        "movie": [],
        "tvshow": [],
        "game": [
          {
            "boxArt": "https://images.igdb.com/igdb/image/upload/t_1080p/co1hvj.jpg"
          }
        ]
      },
      {
        "memID": "178",
        "memType": "Movie",
        "date": {
          "month": 5,
          "year": 1980
        },
        "favourite": null,
        "public": null,
        "music": [],
        "movie": [
          {
            "poster": "https://image.tmdb.org/t/p/original//5xcXvTErivIgRchsaw9qaT3NflE.jpg"
          }
        ],
        "tvshow": [],
        "game": []
      },
]

What I would like to do is to return a new Array of Objects that groups the data by monthYear by combining both the month and year properties, for example:

[
    {
        "monthYear": {
            "5-1980": {
                {
                    "memID": "180",
                    "memType": "Movie",
                    "favourite": null,
                    "public": null,
                    "music": [],
                    "movie": [
                        {
                            "poster": "https://image.tmdb.org/t/p/original//7BuH8itoSrLExs2YZSsM01Qk2no.jpg"
                        }
                    ],
                    "tvshow": [],
                    "game": []
                },
                {
                    "memID": "65",
                    "memType": "Game",
                    "favourite": null,
                    "public": null,
                    "music": [],
                    "movie": [],
                    "tvshow": [],
                    "game": [
                        {
                            "boxArt": "https://images.igdb.com/igdb/image/upload/t_1080p/co1hvj.jpg"
                        }
                    ]
                },
                {
                    "memID": "178",
                    "memType": "Movie",
                    "favourite": null,
                    "public": null,
                    "music": [],
                    "movie": [
                        {
                            "poster": "https://image.tmdb.org/t/p/original//5xcXvTErivIgRchsaw9qaT3NflE.jpg"
                        }
                    ],
                    "tvshow": [],
                    "game": []
                },
            }
        }
    }
]

I've been trying to flatten the Array and then restructure it but I haven't been able to work out the best approach. I have tried .flat(), .flatMap() and a few other methods but haven't had any success.

Upvotes: 0

Views: 54

Answers (3)

Kunal Mukherjee
Kunal Mukherjee

Reputation: 5853

Use Array.prototype.reduce to group by your custom key, here's a sample

const data = [{
    "memID": "180",
    "memType": "Movie",
    "date": {
      "month": 5,
      "year": 1980
    },
    "favourite": null,
    "public": null,
    "music": [],
    "movie": [{
      "poster": "https://image.tmdb.org/t/p/original//7BuH8itoSrLExs2YZSsM01Qk2no.jpg"
    }],
    "tvshow": [],
    "game": []
  },
  {
    "memID": "65",
    "memType": "Game",
    "date": {
      "month": 5,
      "year": 1980
    },
    "favourite": null,
    "public": null,
    "music": [],
    "movie": [],
    "tvshow": [],
    "game": [{
      "boxArt": "https://images.igdb.com/igdb/image/upload/t_1080p/co1hvj.jpg"
    }]
  },
  {
    "memID": "178",
    "memType": "Movie",
    "date": {
      "month": 5,
      "year": 1980
    },
    "favourite": null,
    "public": null,
    "music": [],
    "movie": [{
      "poster": "https://image.tmdb.org/t/p/original//5xcXvTErivIgRchsaw9qaT3NflE.jpg"
    }],
    "tvshow": [],
    "game": []
  },
];

const groupedData = data.reduce((acc, curr) => {
  const { month, year } = curr.date;
  const k = `${month}-${year}`;
  acc[k] = (acc[k] || []).concat(curr);
  return acc;
}, Object.create(null));

const results = [{
  monthYear: groupedData
}];

console.log(results);

Upvotes: 0

JohMun
JohMun

Reputation: 446

I recommend to use lodash/groupBy for this.

const formatted = _.groupBy(data, item => `${item.date.month}-${item.date.year}`);

The function will create the following structure. It's a little bit different, but it groups the items according to month and year

{
  "5-1980": [
    {
      "memID": "180",
      "memType": "Movie",
      "date": {
        "month": 5,
        "year": 1980
      },
      "favourite": null,
      "public": null,
      "music": [],
      "movie": [
        {
          "poster": "https://image.tmdb.org/t/p/original//7BuH8itoSrLExs2YZSsM01Qk2no.jpg"
        }
      ],
      "tvshow": [],
      "game": []
    },
    {
      "memID": "65",
      "memType": "Game",
      "date": {
        "month": 5,
        "year": 1980
      },
      "favourite": null,
      "public": null,
      "music": [],
      "movie": [],
      "tvshow": [],
      "game": [
        {
          "boxArt": "https://images.igdb.com/igdb/image/upload/t_1080p/co1hvj.jpg"
        }
      ]
    },
    {
      "memID": "178",
      "memType": "Movie",
      "date": {
        "month": 5,
        "year": 1980
      },
      "favourite": null,
      "public": null,
      "music": [],
      "movie": [
        {
          "poster": "https://image.tmdb.org/t/p/original//5xcXvTErivIgRchsaw9qaT3NflE.jpg"
        }
      ],
      "tvshow": [],
      "game": []
    }
  ]
}

Upvotes: 2

Daniel Stoyanoff
Daniel Stoyanoff

Reputation: 1564

This should do the job:

inputData.reduce((acc, item) => {
  const key = `${item.date.month}-${item.date.year}`;
  const { date, ...realData } = item;

  acc[key] = [...acc[key] || [], realData];
  return acc;
}, {})

Explanation about the code.

const key = `${item.date.month}-${item.date.year}` - this part creates the key of the item. In your case it's a composition of month-year.

const { date, ...realData } = item - here we remove the date object from the whole, as you don't need it anymore (as per your desired output)

...acc[key] || [] - if this is the first object in the loop with that key, acc[key] would be null, so we initialize with an empty array. If that's not the first key, then acc[key] will already be an array. We then add the newly created object to that array.

Hope this is what you are after.

Upvotes: 0

Related Questions