Home > Blockchain >  How to append a data item to a deep nested array while keeping the original response data structure
How to append a data item to a deep nested array while keeping the original response data structure

Time:02-20

I'm creating data per day and I'm dealing with following response data ...

{
  tipster: {
    name: "Gallita FC",
    description: "TEST",
    picks: [{
      date: "Friday, February 18th 2022",
      data: [{
        title: "yesterday",
        description: "TEST",
        date: "Friday, February 18th 2022",
        category: "NHL",
        pickImageUrl: "https://res.cloudinary.com/creaciones-inteligentes-roy/image/upload/v1644455039/Captura_de_Pantalla_2022-02-09_a_la_s_18.59.43_voy1pj.png",
      }],
    }, {
      date: "Saturday, February 19th 2022",
      data: [{
        title: "today",
        description: "TEST",
        date: "Saturday, February 19th 2022",
        category: "NHL",
        pickImageUrl: "https://res.cloudinary.com/creaciones-inteligentes-roy/image/upload/v1644455039/Captura_de_Pantalla_2022-02-09_a_la_s_18.59.43_voy1pj.png",
      }],
    }],
    imageUrl: "https://res.cloudinary.com/sports-master/image/upload/v1644649610/27ADF778-454B-4DB7-88B7-DC98202E2736_utb7xw.png",
    bannerUrl: "https://scontent.fmex34-1.fna.fbcdn.net/v/t1.6435-9/167022015_1317341031983063_7337313589197318410_n.jpg?_nc_cat=111&ccb=1-5&_nc_sid=a26aad&_nc_ohc=5ctqP2nFf7IAX94PNSO&_nc_ht=scontent.fmex34-1.fna&oh=00_AT_TzRHhhV73ji7wzW2X1u27TOU8TNlObwtp0ILc0DzC1Q&oe=62207F2C",
    id: "62075e5a13a43ace611fe5bd",
  },
}

Within the tipster.picks array I need to append an additional data item to the last matching data item. A match could be where data.title equals "today".

The code I came up with so far does not lead to the correct result ...

const newPick = {
  title,
  description,
  date,
  category,
  pickImageUrl,
};    

const tipsterUpdate = {
  ...req.body,
  picks: [...tipster.picks, tipster.picks.slice(-(1)[0], newPick)],
};

I'm using spread operator because I need to maintain the old data and only add a new object on the data array.

I really appreciate a little help here. Thank you.

CodePudding user response:

Destructure out the picks array from everything else in the tipster object, then build a new tipster object containing an updated picks array.

const data={tipster:{name:"Gallita FC",description:"TEST",picks:[{date:"Friday, February 18th 2022",data:[{title:"yesterday",description:"TEST",date:"Friday, February 18th 2022",category:"NHL",pickImageUrl:"https://res.cloudinary.com/creaciones-inteligentes-roy/image/upload/v1644455039/Captura_de_Pantalla_2022-02-09_a_la_s_18.59.43_voy1pj.png"}]},{date:"Saturday, February 19th 2022",data:[{title:"today",description:"TEST",date:"Saturday, February 19th 2022",category:"NHL",pickImageUrl:"https://res.cloudinary.com/creaciones-inteligentes-roy/image/upload/v1644455039/Captura_de_Pantalla_2022-02-09_a_la_s_18.59.43_voy1pj.png"}]}],imageUrl:"https://res.cloudinary.com/sports-master/image/upload/v1644649610/27ADF778-454B-4DB7-88B7-DC98202E2736_utb7xw.png",bannerUrl:"https://scontent.fmex34-1.fna.fbcdn.net/v/t1.6435-9/167022015_1317341031983063_7337313589197318410_n.jpg?_nc_cat=111&ccb=1-5&_nc_sid=a26aad&_nc_ohc=5ctqP2nFf7IAX94PNSO&_nc_ht=scontent.fmex34-1.fna&oh=00_AT_TzRHhhV73ji7wzW2X1u27TOU8TNlObwtp0ILc0DzC1Q&oe=62207F2C",id:"62075e5a13a43ace611fe5bd"}};

const newPick = {
  title: 'Bob',
  description: 'Bob does it again',
  date: new Date(),
  category: 'Bob',
  pickImageUrl: 'bobImage',
};

// Accept data, the new pick, and a search
// (in this case "today")
function addNewPick(data, newPick, search) {

  // Grab the picks, and then everything else
  // from the tipster object
  const { tipster: { picks, ...rest } } = data;

  // `find` the index of the array containing the search text
  const index = picks.findIndex(pick => {
    return pick.data.some(obj => {
      return obj.title === search;
    });
  });

  // Add the new pick to the "today" array
  picks[index].data.push(newPick);

  // Return a new tipster object with
  // the updated picks
  return {
    tipster: { ...rest, picks }
  };

}

const out = addNewPick(data, newPick, 'today');

console.log(out);

CodePudding user response:

quoting the OP

I'm using spread operator because I need to mantaint the old data and only add a new object on the data array.

Since spread syntax creates a shallow copy only, thus any nested level of the copy is still a reference and therefore in danger of being mutated, I suggest a one time deep clone via structuredClone (there are polyfills for environments which do not yet support this Web-Api method).

And as for a generic approach, which inserts a new data item after (either) the last data with a matching condition (or even after every condition matching data item), one needs a function which gets provided

  • the tipster.picks reference of the deeply cloned response data object,
  • the to be inserted new data item,
  • a callback function which implements the condition of a matching data item.

Within a first step one would collect a list of all data items where the condition does match. The second step is the insert task which can be adapted to maybe changing requirements ...

function insertDataItemAfterLastMatchingCondition(picks, item, condition) {
  // collect a list of all data items where `condition` matches.
  const matchList = picks
    .reduce((matches, pickItem) => {

      const { data } = pickItem;
      const index = data.findIndex(condition);

      if (index >= 0) {
        matches.push({ array: data, index });
      }
      return matches;

    }, []);

  // insert new item excusivley after the last matching data item.
  const { array, index } = matchList.at(-1) ?? {};
  if (Array.isArray(array)) {

    array.splice((index   1), 0, item);
  }
  // // insert new item (copy) after every matching data item.
  //
  // matchList.forEach(({ array, index }) =>
  //   array.splice((index   1), 0, {...item})
  // );
}


const responseData = {tipster:{name:"Gallita FC",description:"TEST",picks:[{date:"Friday, February 18th 2022",data:[{title:"yesterday",description:"TEST",date:"Friday, February 18th 2022",category:"NHL",pickImageUrl:"https://res.cloudinary.com/creaciones-inteligentes-roy/image/upload/v1644455039/Captura_de_Pantalla_2022-02-09_a_la_s_18.59.43_voy1pj.png"}]},{date:"Saturday, February 19th 2022",data:[{title:"today",description:"TEST",date:"Saturday, February 19th 2022",category:"NHL",pickImageUrl:"https://res.cloudinary.com/creaciones-inteligentes-roy/image/upload/v1644455039/Captura_de_Pantalla_2022-02-09_a_la_s_18.59.43_voy1pj.png"}]}],imageUrl:"https://res.cloudinary.com/sports-master/image/upload/v1644649610/27ADF778-454B-4DB7-88B7-DC98202E2736_utb7xw.png",bannerUrl:"https://scontent.fmex34-1.fna.fbcdn.net/v/t1.6435-9/167022015_1317341031983063_7337313589197318410_n.jpg?_nc_cat=111&ccb=1-5&_nc_sid=a26aad&_nc_ohc=5ctqP2nFf7IAX94PNSO&_nc_ht=scontent.fmex34-1.fna&oh=00_AT_TzRHhhV73ji7wzW2X1u27TOU8TNlObwtp0ILc0DzC1Q&oe=62207F2C",id:"62075e5a13a43ace611fe5bd"}};

const responseClone = (typeof structuredClone === 'function')
  && structuredClone(responseData)
  || JSON.parse(JSON.stringify(responseData)); // fallback

const newData = {
  title: 'tomoorow',
  description: 'TEST',
  date: 'Sunday, February 20th 2022',
  category: 'NHL',
  pickImageUrl: 'https://res.cloudinary.com/creaciones-inteligentes-roy/image/upload/v1644455039/Captura_de_Pantalla_2022-02-09_a_la_s_18.59.43_voy1pj.png',
};


insertDataItemAfterLastMatchingCondition(
  responseClone.tipster.picks,
  newData,
  data => data.title === 'today',
); 
console.log({ responseData, responseClone });
.as-console-wrapper { min-height: 100%!important; top: 0; }

CodePudding user response:

If you want to do it with spread operator (inmutable way), something like this should be enough:

const oldData = {
  tipster: {
    name: "Gallita FC",
    description: "TEST",
    picks: [
      {
        date: "Friday, February 18th 2022",
        data: [
          {
            title: "yesterday",
            description: "TEST",
            date: "Friday, February 18th 2022",
            category: "NHL",
            pickImageUrl:
              "https://res.cloudinary.com/creaciones-inteligentes-roy/image/upload/v1644455039/Captura_de_Pantalla_2022-02-09_a_la_s_18.59.43_voy1pj.png",
          },
        ],
      },
      {
        date: "Saturday, February 19th 2022",
        data: [
          {
            title: "today",
            description: "TEST",
            date: "Saturday, February 19th 2022",
            category: "NHL",
            pickImageUrl:
              "https://res.cloudinary.com/creaciones-inteligentes-roy/image/upload/v1644455039/Captura_de_Pantalla_2022-02-09_a_la_s_18.59.43_voy1pj.png",
          },
        ],
      },
    ],
    imageUrl:
      "https://res.cloudinary.com/sports-master/image/upload/v1644649610/27ADF778-454B-4DB7-88B7-DC98202E2736_utb7xw.png",
    bannerUrl:
      "https://scontent.fmex34-1.fna.fbcdn.net/v/t1.6435-9/167022015_1317341031983063_7337313589197318410_n.jpg?_nc_cat=111&ccb=1-5&_nc_sid=a26aad&_nc_ohc=5ctqP2nFf7IAX94PNSO&_nc_ht=scontent.fmex34-1.fna&oh=00_AT_TzRHhhV73ji7wzW2X1u27TOU8TNlObwtp0ILc0DzC1Q&oe=62207F2C",
    id: "62075e5a13a43ace611fe5bd",
  },
};

const newPick = {
  title: "new title",
  description: "new description",
  date: "new date",
  category: "new category",
  pickImageUrl: "new image url",
};

const tipsterUpdate = {
  ...oldData,
  tipster: {
    picks: [...oldData.tipster.picks, newPick],
  },
};

console.log(tipsterUpdate);

If you don't mind inmutability, just use push:

oldData.tipster.picks.push(newPick);
  • Related