Search code examples
javascriptobjecttransformmultipartform-data

How to transform formData into an iterable array?


Considering this simplified formData:

FormData {
  "id": "id1",
  "timeslots[0][start]": "2023-06-10",
  "timeslots[0][end]": "2023-06-09",
  "timeslots[1][start]": "2024-06-10",
  "timeslots[1][end]": "2024-06-09",
  ....
}

or parsed object (I have access to both):

{
  id: "id1",
  "timeslots[0][start]": "2023-06-10",
  "timeslots[0][end]": "2023-06-09",
  "timeslots[1][start]": "2024-06-10",
  "timeslots[1][end]": "2024-06-09",
  ...
}

What would be the simplest but readable way to transform timeslots into an array?
In fine, I'd like to get this object:

{
  id: "id1",
  timeslots:[
   { start: "2023-06-10", end: "2023-06-09" },
   { start: "2024-06-10", end: "2024-06-09" }
  ]
 }

I've begun with this (in JS). But I don't think it driving me somewhere...

  const timeslots = []
  for (const [key, value] of Object.entries(body)) {
    if (key.startsWith('timeslots')) {
      const new_key = key.substring(13, key.length - 1)
      const slot = key.substring(10, 11)
      const tmp = { [new_key]: value, number: slot }
      timeslots.push(tmp)
      ...
    }
  }

===== EDIT ======

Considering this augmented object:

{
  id: "id1",

  "timeslots[0][start]": "2023-06-10",
  "timeslots[0][end]": "2023-06-09",
  "timeslots[0]disability[3]": "D3",
  "timeslots[0]disability[4]": "D4"

  "timeslots[1][start]": "2024-06-10",
  "timeslots[1][end]": "2024-06-09",
  "timeslots[1]disability[1]": "D1",
  "timeslots[1]disability[5]": "D5"
  ...
}

How to update @newalvaro9 answer to get this object?

{
  id: "id1",
  timeslots:[
   { start: "2023-06-10", end: "2023-06-09", disability: ['D3', 'D4'] },
   { start: "2024-06-10", end: "2024-06-09", disability: ['D1', 'D5'] }
  ]
 }

Solution

  • After some tests I arrived to this conclusion:

    const inputObject = {
      id: "id1",
      "timeslots[0][start]": "2023-06-10",
      "timeslots[0][end]": "2023-06-09",
      "timeslots[1][start]": "2024-06-10",
      "timeslots[1][end]": "2024-06-09"
    };
    
    const transformedObject = {
      id: inputObject.id,
      timeslots: Object.entries(inputObject)
        .filter(([key]) => key.startsWith("timeslots"))
        .map(([key, value]) => {
          const [, index, property] = key.match(/timeslots\[(\d+)\]\[(start|end)\]/);
          return { [property]: value, index: parseInt(index) };
        })
        .reduce((acc, { index, ...rest }) => {
          acc[index] = acc[index] || {};
          Object.assign(acc[index], rest);
          return acc;
        }, [])
    };
    
    console.log(transformedObject);

    The above code creates a new Object based in the inputObject. For timeslots we retrieve the properties of the inputObject into an array of key-value pairs with Object.entries, then we only need only the keys that are timeslots so we .filter() the array. The remaining key-value pairs are mapped using .map() to extract the index and property name from the key using a regular expression. We then use .reduce() to merge the resulting objects into a single array of timeslot objects. The index property is used as the index in the array. If a timeslot object with the same index already exists, its properties are merged with the new object using Object.assign().

    ================= Edited question answer: ===================

    const inputObject = {
        id: "id1",
        "timeslots[0][start]": "2023-06-10",
        "timeslots[0][end]": "2023-06-09",
        "timeslots[0]disability[3]": "D3",
        "timeslots[0]disability[4]": "D4",
        "timeslots[1][start]": "2024-06-10",
        "timeslots[1][end]": "2024-06-09",
        "timeslots[1]disability[1]": "D1",
        "timeslots[1]disability[5]": "D5"
    };
    
    // Convert the input object into the desired format
    const timeslots = [];
    const keys = Object.keys(inputObject);
    
    keys.forEach(key => {
        const match = key.match(/timeslots\[(\d+)\]\[(start|end)\]/);
    
        if (match) {
            const index = parseInt(match[1]);
            const prop = match[2];
    
            if (!timeslots[index]) {
                timeslots[index] = {};
            }
    
            timeslots[index][prop] = inputObject[key];
        } else {
            const matchDisability = key.match(/timeslots\[\d+\]disability\[(\d+)\]/);
    
            if (matchDisability) {
                const index = parseInt(matchDisability[0].split('[')[1]);
                const disability = inputObject[key];
    
                if (!timeslots[index].disability) {
                    timeslots[index].disability = [];
                }
    
                timeslots[index].disability.push(disability);
            }
        }
    });
    
    const outputObject = { id: inputObject.id, timeslots };
    console.log(outputObject.timeslots);

    Im not going to explain this time, you should learn and try to understand the javascript functions and methods