Search code examples
javascriptarraysreactjsjavascript-objectsnested-loops

Pushing object into an array which is a property of an object


I'm trying to push objects to an array("replies") present inside an object(newProjObj.comments).

And while logging the entire object(newProjObj.comments), I get an empty array as the value of the property(newProjObj.comments.replies: [])

But while logging that specific property(console.log(newProjObj.comments.replies)), I get the desired output([{...},{...}])

export function structureCommentsWithReplies(projectDetails) {
    console.log(projectDetails)
    let newProjObj = {...projectDetails};
    console.log(newProjObj)
    // Filtering the actual comments
    let commsOnPost = newProjObj.comments.filter((comment) => comment.onPost);
    // Filtering replies to the comments above
    let commsOnComm = newProjObj.comments.filter((comment) => !comment.onPost);
    // Looping to the actual comments
    for(let [index, comment] of commsOnPost.entries()) {
        // Created a property "replies" for every comment initialised to []
        commsOnPost[index]["replies"] = []
        // Looping through filtered replies
        for(let reply of commsOnComm) {
            if((!reply.onPost) && (reply.commentOnID === comment.id)) {
                // Push the reply into "replies" property of appropriate actual comment
                commsOnPost[index]["replies"].push(reply) 
                console.log(commsOnPost[index]['replies']) // Logs the pushed reply as expected => [{ id:17, onPost:false, ... }]
                console.log(commsOnPost[index]) // Logs the comment object with replies property as EMPTY ARRAY => { id: 1, onPost: true, replies: [], ... }
            }
        }
    }
    newProjObj.comments = commsOnPost;
    console.log(newProjObj.comments[0]) // Logs the comment object with replies property as EMPTY ARRAY => { id: 1, onPost: true, replies: [], ... }
    console.log(newProjObj.comments[0].replies) // Logs the pushed reply as expected => [{ id:17, onPost:false, ... }]
    return newProjObj;
}

And the object being returned at the end also has an empty array as the value of the "replies" property.

I've written comments explaining each line as well if that helps.

Thank you!


Solution

  • If I understand correctly, then you have an object (something) like this:

    const projectDetails = {
      comments: [
        {
          id: 1,
          onPost: true,
        },
        {
          id: 2,
          onPost: false,
          commentOnID: 1,
        },
        {
          id: 3,
          onPost: false,
          commentOnID: 1,
        },
        {
          id: 4,
          onPost: true,
        },
        {
          id: 5,
          onPost: false,
          commentOnID: 4,
        },
      ]
    }
    

    and you would like to get something like this:

    const newProjObj = {
      comments: [
        {
          id: 1,
          onPost: true,
          replies: [
            {
              id: 2,
              onPost: false,
              commentOnID: 1,
            },
            {
              id: 3,
              onPost: false,
              commentOnID: 1,
            },
          ],
        },
        {
          id: 4,
          onPost: true,
          replies: [
            {
              id: 5,
              onPost: false,
              commentOnID: 4,
            },
          ],
        },
      ]
    }
    

    If this is correct, then the following snippet would work:

    const projectDetails = {
      comments: [{
          id: 1,
          onPost: true,
        },
        {
          id: 2,
          onPost: false,
          commentOnID: 1,
        },
        {
          id: 3,
          onPost: false,
          commentOnID: 1,
        },
        {
          id: 4,
          onPost: true,
        },
        {
          id: 5,
          onPost: false,
          commentOnID: 4,
        },
      ]
    }
    
    // only taking out the value that we'll be working with
    const structureCommentsWithReplies = ({ comments, ...details }) => {
    
      // classifying items - in one pass &
      // retrieving the two objects we need
      const { commsOnPost, commsOnComm } = comments.reduce(
        (a, { onPost, ...rest }) => {
          if (onPost) {
            a.commsOnPost[rest.id] = {
              onPost,
              replies: [],
              ...rest
            }
          } else {
            a.commsOnComm = [...a.commsOnComm, {
              onPost,
              ...rest
            }]
          }
          return a
        }, {
          commsOnPost: {},
          commsOnComm: []
        })
    
      // adding items to their parent comments'
      // replies array
      commsOnComm.forEach(({ commentOnID, ...rest }) => {
        commsOnPost[commentOnID].replies = [
          ...commsOnPost[commentOnID].replies,
          { commentOnID, ...rest }
        ]
      })
    
      // returning the object with updated
      // comments section
      return {
        ...details,
        comments: Object.values(commsOnPost)
      }
    }
    
    const structured = structureCommentsWithReplies(projectDetails)
    console.log('structured', structured)