Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

196
Vistas
Conditionally expanding an Object recursively (nested children)

The goal of this is to have comments with recursive child comments.

As example data for this, there are posts and comments that got fetched.

let posts = [
    { id: '001a', topic: 'post topic', content: 'post content' }
]
let comments = [
    { id: '002a', postParent: '001a', directParent: '001a', content: 'comment on post' },
    { id: '003a', postParent: '001a', directParent: '002a', content: 'comment on comment' },
    { id: '004a', postParent: '001a', directParent: '003a', content: 'comment on comments comment' },
]

If I should formulate it into words, I would say: conditionally on a comment-objects parent-key, this object should become a child-comment-object of its parent-comment-object. To achieve this, I came to think that it needs a functionality to create another array. Like:

let postComments = [
    {
        id: '002a',
        postParent: '001a',
        directParent: '001a',
        content: 'comment on post',
        children: [
            { 
                id: '003a', 
                postParent: '001a', 
                directParent: '002a', 
                content: 'comment on comment',
                children: [ {id: '004a', post: '001a', parent: '003a', content: 'comment on comments comment' }} ]
            }
        ]
    },
]

The approach I tried until now, was solving this without creating such a new array that extends itself. I tried outputting the comments conditionally on it's parent in an each-block. Unfortunately this didn't leadt to a scalable solution (/ to do it recursively -I'm not sure about the right terminology here). That's how I got to the approach this question is now about and how to create a new array like shown in the example.

But as I'm still not sure if it's a good solution when having such data, any suggestion on a proven approach for such a problem is very welcome.

Unfortunately the extensive REPL I was thankfully able to create from the provided answers was overwritten when viewing and saving another REPL. I had to delete the now misleading link, but the little takeaway is to make a backup of svelte REPLS if some work went into it. Which I didn't. Anyway the answers below hold enough good examples.

about 4 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

let posts = [{ id: '001a', topic: 'post topic', content: 'post content' }]
let comments = [
  { id: '002a', post: '001a', parent: '001a', content: 'comment on post' },
  { id: '003a', post: '001a', parent: '002a', content: 'comment on comment' },
  { id: '004a', post: '001a', parent: '003a', content: 'comment on comments comment' },
]

function getNestedComments(parentId) {
  const subComments = comments.filter((c) => c.parent === parentId)
  if (subComments.length === 0) return subComments
  subComments.forEach(c => {
    c.children = getNestedComments(c.id)
  })
  return subComments
}

let postComments = getNestedComments('001a')
console.log(postComments)

TypeScript Playground

about 4 years ago · Juan Pablo Isaza Denunciar

0

Here is another solution with no recursive function. It uses map-lookup.

let posts = [
    { id: '001a', topic: 'post topic', content: 'post content' }
]
let comments = [
    { id: '002a', post: '001a', parent: '001a', content: 'comment on post' },
    { id: '003a', post: '001a', parent: '002a', content: 'comment on comment' },
    { id: '004a', post: '001a', parent: '003a', content: 'comment on comments comment' }
]

let postComments = toNestedComments(comments, posts[0].id);
console.log(postComments);

function toNestedComments(comments, postId) {
    const nestedComments = [];
    const map = {};

    for (let i = 0; i < comments.length; i++) {
        map[comments[i].id] = i;
    }

    for (let comment of comments) {
        if (comment.parent === postId) {
            nestedComments.push(comment);
        } else {
            if (!comments[map[comment.parent]].hasOwnProperty('children')) {
                comments[map[comment.parent]].children = [];
            }
            comments[map[comment.parent]].children.push(comment);
        }
    }

    return nestedComments;
}

about 4 years ago · Juan Pablo Isaza Denunciar

0

Retrieving the comments belonging to a specific parent only when you render that parent seems to me inefficient since each time you try to render the code will run through all your comments to find the ones belonging to that parent.

A better approach (in my opinion) is to add a property children to each posts/comment and populate it, as you have in your code. The difficulty here is to do this in way to minimize the number of times you have to 'loop' over all data.

One way is to build a lookup table for each post and comment like this:

const lookup = [...posts, ...comments].reduce((pre, cur) => {
  cur.children = []; // Prepares an array to hold the children
  pre[cur.id] = cur;
  return pre;
}, {});

And then loop over the comments again, adding themselves to the parent we can read from the lookup table.

comments.forEach(c => lookup[c.parent].children.push(c));

Because of how javascript works in regards to objects, this will result in the items of the original posts and comments now having a children property populated with the comments for that element (and these comments having their own children).

Now you can recursively render these with a Post component and svelte:self.

{#each children as child}
  <svelte:self {...child} />
{/each}

This solution only goes twice through the data to build this construction (once to make the lookup table, once to attach the comments) so is more efficient than searching the comments during render itself.

If your data is sorted in a way that a comment will always appear after it's parent, you could make this even better by pushing to the parent's children at the same time you build the map:

let map = [...posts, ...comments].reduce((pre, cur) => {
  cur.children = [];
  pre[cur.id] = cur;
  if (cur.parent) pre[cur.parent].children.push(cur);
  return pre;
}, {});

edit to fit with the data provided in the snippet

const lookup = [...posts].reduce((pre, cur) => {
  // Either a post or a comment
  const item = cur.post ?? cur.comment;
  // Prepares an array to hold the children
  item.children = []; 
  pre[cur.publicKey] = item;
  return pre;
}, {});
    
comments.forEach(({ comment }) => lookup[comment.post].children.push(comment));

Not perfect, but a start to get an idea. This will put all comments on the post so comments do not have their own children.

Demo Repl

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda