Tengo los siguientes modelos:
User
` Customer
`Comment
El usuario puede comentar sobre un Customer
, el usuario puede responder al comentario de otro usuario, recursivamente ilimitado.
He hecho esto, pero está limitado a una sola respuesta, y quiero obtener todas las respuestas NESTED:
public async getCommentsForCustomerId(customerId: string): Promise<CustomerComment[]> {
return this.find({where: {customer: {id: customerId}, parentComment: null}, relations: ['childComments']});
}
Sin embargo, la respuesta que obtengo solo está anidada en un nivel:
[
{
"id": "7b5b654a-efb0-4afa-82ee-c00c38725072",
"content": "test",
"created_at": "2019-12-03T15:14:48.000Z",
"updated_at": "2019-12-03T15:14:49.000Z",
"childComments": [
{
"id": "7b5b654a-efb0-4afa-82ee-c00c38725073",
"content": "test reply",
"created_at": "2019-12-03T15:14:48.000Z",
"updated_at": "2019-12-03T15:14:49.000Z",
"parentCommentId": "7b5b654a-efb0-4afa-82ee-c00c38725072"
}
]
}
]
¿Cómo puedo hacer una consulta para anidarlos a todos en typeorm?
Definición de entidad (nota cliente renombrado a Lead) :
@Entity('leads_comments')
export class LeadComment {
@PrimaryGeneratedColumn('uuid')
id: string;
@ManyToOne(type => LeadComment, comment => comment.childComments, {nullable: true})
parentComment: LeadComment;
@OneToMany(type => LeadComment, comment => comment.parentComment)
@JoinColumn({name: 'parentCommentId'})
childComments: LeadComment[];
@RelationId((comment: LeadComment) => comment.parentComment)
parentCommentId: string;
@ManyToOne(type => User, {cascade: true})
user: User | string;
@RelationId((comment: LeadComment) => comment.user, )
userId: string;
@ManyToOne(type => Lead, lead => lead.comments, {cascade: true})
lead: Lead | string;
@RelationId((comment: LeadComment) => comment.lead)
leadId: string;
@Column('varchar')
content: string;
@CreateDateColumn()
created_at: Date;
@UpdateDateColumn()
updated_at: Date;
}
Respuestas:
Básicamente estás usando un
Adjacency list Tree
.La lista de adyacencia es un modelo simple con autorreferencia. El beneficio de este enfoque es la simplicidad, PERO el inconveniente es que no puede manejar árboles profundos con eso.
Hay una forma recursiva de hacerlo con la lista de adyacencia, pero no funciona con MySQL.
La solución es usar otro tipo de árbol. Otros posibles árboles son:
Para cargar un árbol use:
Después de obtener un repositorio de árbol, puede usar las siguientes funciones:
findTrees(), findRoots(), findDescendants(), findDescendantsTree()
y otras. Ver documentación para más.Obtenga más información sobre los diferentes tipos de árboles: modelos para datos jerárquicos
fuente
Como dijo Gabriel, otros modelos de datos son mejores para hacer lo que desea en cuanto al rendimiento. Aún así, si no puede cambiar el diseño de la base de datos, puede usar alternativas (que son menos efectivas o bonitas, pero lo que funciona en la producción es todo lo que importa al final).
Al establecer el valor de Lead en su LeadComment, puedo sugerirle que establezca este valor también en las respuestas en el comentario raíz en la creación de respuestas (debería ser fácil en el código). De esta forma, puede obtener todos los comentarios de su cliente en una sola consulta (incluidas las respuestas).
Por supuesto, tendrá que ejecutar un lote de SQL para completar los valores de columna que faltan, pero es una cosa única, y una vez que su base de código también esté parchada, no tendrá que ejecutar nada después. Y no cambia la estructura de su base de datos (solo la forma en que se rellenan los datos).
Luego puede construir en nodejs todo el material (listas de respuestas). Para obtener el comentario "raíz", simplemente filtre por comentario que no sean respuestas (que no tengan padres). Si solo desea los comentarios raíz de la base de datos, incluso puede cambiar la consulta a solo estos (con parentComment nulo en la columna SQL).
Luego puede obtener respuestas en rootComments y construir la lista completa de forma recursiva en el nodo.
Probablemente hay formas más optimizadas para calcular estas listas, esta es para mí una de las más simples que se pueden hacer.
Dependiendo de la cantidad de comentarios, puede ser lento (puede limitar los resultados por marca de tiempo y número, por ejemplo, para que sea lo suficientemente bueno), así que tenga cuidado, no busque el universo de comentarios en un Lead "Justin Bieber" que obtenga muchos comentarios ...
fuente