0

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.

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Rodrigo Ibarra
  • 147
  • 1
  • 1
  • 8
  • have you tried push – cmgchess Feb 19 '22 at 09:42
  • _**... so I have this JSON object ...**_ - There is nothing like a JSON array or JSON object. JS data-structures can be provided and transferred/interchanged as [`JSON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) strings (see [`JSON.stringify`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)). Such strings can be converted back into objects by a parse process like `JSON.parse`. Thus `JSON` stands for both, a JavaScript namespace with methods and a syntax for serializing data-structures. – Peter Seliger Feb 19 '22 at 10:05
  • @RodrigoIbarra ... regarding all the approaches / solutions are there any questions left? – Peter Seliger Feb 21 '22 at 21:40
  • I can’t solve it yet. I posted a new question but same result, can’t make it work. – Rodrigo Ibarra Feb 21 '22 at 23:15
  • @RodrigoIbarra ... 1st of all, the OP could have given feedback on all until now provided answers/solutions whether each solution produces the expected result for the OP's example data. 2nd, why didn't the OP continue here, asking for help when still being stuck. 3rd, did the OP already try applying the code of each answer into the OP's environment? 4th, in order get notifications about new comments, the OP should use the annotation like `@Andy` or `@PeterSeliger`. I discovered the OP'S last/above comment just accidentally. – Peter Seliger Feb 24 '22 at 07:56
  • @RodrigoIbarra ... At SO it is considered to be a nice gesture from the one who got help, to provide some feedback (don't just disappear) and/or vote on answers and/or accept the answer which was the most helpful in solving the OP's problem. – Peter Seliger Feb 28 '22 at 17:18

2 Answers2

0

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);
Andy
  • 61,948
  • 13
  • 68
  • 95
0

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; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37