NestJS nodejs, ilişkileri olan bir sorguda iç içe yorumlar yüklüyor mu?


10

Aşağıdaki modellerim var:

User, Customer,Comment

Kullanıcı bir yorum yapabilir Customer, kullanıcı tekrar tekrar sınırsız başka bir kullanıcının yorumuna cevap verebilir.

Bunu yaptım ama sadece bir cevapla sınırlı ve tüm cevapları NESTED almak istiyorum:

public async getCommentsForCustomerId(customerId: string): Promise<CustomerComment[]> {
    return this.find({where: {customer: {id: customerId}, parentComment: null}, relations: ['childComments']});
}

Ancak aldığım yanıt sadece bir düzeyde yuvalanmış:

[
    {
        "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"
            }
        ]
    }
]

Hepsini typeorm içine yerleştirmek için nasıl sorgu yapabilirim?

Varlık tanımı (müşterinin Aday Müşteri olarak yeniden adlandırıldığını unutmayın) :

@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;
}

1
Varlık tanımlarınızı ekleyebilir misiniz?
19'da zenbeni

@zenbeni Eklendi teşekkürler
Ben Beri

Yanıtlar:


7

Temelde bir Adjacency list Tree.

Bitişiklik listesi, kendini referans alan basit bir modeldir. Bu yaklaşımın yararı sadeliktir, ama dezavantajı, derin ağaçları bununla ele alamamanızdır.

Bitişiklik listesi ile yapmanın yinelemeli bir yolu var, ancak MySQL ile çalışmıyor.

Çözüm başka bir ağaç türü kullanmaktır. Diğer olası ağaçlar:

  • İç içe set : Okumalar için çok verimli, ancak yazma için kötü. İç içe kümede birden fazla kök olamaz.
  • Maddi Yol : (Yol Numaralandırma olarak da bilinir) basit ve etkilidir.
  • Kapatma tablosu : ebeveyn ve çocuk arasındaki ilişkileri ayrı bir tabloda saklar. Hem okuma hem de yazma işlemlerinde etkilidir (Bir bileşenin üst öğesinin güncellenmesi veya kaldırılması henüz uygulanmamıştır)
@Entity()
@Tree("nested-set") // or @Tree("materialized-path") or @Tree("closure-table")
export class Category {

    @PrimaryGeneratedColumn()
    id: number;

    @TreeChildren()
    children: Category[];

    @TreeParent()
    parent: Category;
}

Bir ağaç yüklemek için:

const manager = getManager();
const trees = await manager.getTreeRepository(Category).findTrees();

Bir ağaç havuzu aldıktan sonra, sonraki işlevleri kullanabilirsiniz: findTrees(), findRoots(), findDescendants(), findDescendantsTree()ve diğerleri. Daha fazla bilgi için belgelere bakın .

Farklı ağaç türleri hakkında daha fazla bilgi edinin: Hiyerarşik veri modelleri


1

Gabriel'in dediği gibi, diğer veri modelleri performans istediğinizi yapmak için daha iyidir. Yine de veritabanı tasarımını değiştiremiyorsanız, alternatifleri kullanabilirsiniz (daha az performans veya güzel, ancak üretimde işe yarayan sonuçta önemlidir).

LeadComment öğenizde Lead değerini ayarladıkça, bu değeri yanıt oluşturma ile ilgili kök yorumdaki yanıtlarda da ayarlamanızı önerebilirim (kodda kolay olmalı). Bu şekilde, müşterinizdeki tüm yorumları tek bir sorguda (yanıtlar dahil) alabilirsiniz.

const lead = await leadRepository.findOne(id);
const comments = await commentRepository.find({lead});

Tabii ki, eksik sütun değerlerini doldurmak için bir SQL toplu işlemi çalıştırmak zorunda kalacaksınız, ancak bu bir defalık bir şey ve kod tabanınız da yandıktan sonra daha sonra hiçbir şey çalıştırmanız gerekmeyecek. Veritabanınızın yapısını değiştirmez (sadece verilerin doldurulma şekli).

Daha sonra nodejs'de tüm şeyleri oluşturabilirsiniz (yanıt listeleri). "Kök" yorumu almak için yanıt olmayan (ebeveynleri olmayan) yoruma göre filtreleyin. Sadece veritabanından kök açıklamaları istiyorsanız, sorguyu yalnızca bu komutlarla değiştirebilirsiniz (SQL sütununda parentComment null ile).

function sortComment(c1: LeadComment , c2: LeadComment ): number {
    if (c1.created_at.getTime() > c2.created_at.getTime()) {
    return 1;
    }
    if (c1.created_at.getTime() < c2.created_at.getTime()) {
        return -1;
    }
    return 0;
}
const rootComments = comments
    .filter(c => !c.parentComment)
    .sort(sortComment);

Daha sonra rootComments üzerinde yanıt alabilir ve tüm listeyi düğümde özyineli olarak oluşturabilirsiniz.

function buildCommentList(currentList: LeadComment[], allComments: LeadComment[]): LeadComment[] {
    const lastComment = currentList[currentList.length - 1];
    const childComments = allComments
        .filter(c => c.parentComment?.id === lastComment.id)
        .sort(sortComment);
    if (childComments.length === 0) {
        return currentList;
    }
    const childLists = childComments.flatMap(c => buildCommentList([c], allComments));
    return [...currentList, ...childLists];
}

const listsOfComments = rootComments.map(r => buildCommentList([r], comments));

Bu listeleri hesaplamak için muhtemelen daha optimize edilmiş yollar var, bu benim için yapılabilecek en basitlerden biri.

Yorumların sayısına bağlı olarak yavaşlayabilir (sonuçları zaman damgası ve sayı ile sınırlayabilirsiniz, böylece yeterince iyi olması gerekir mi?) birçok yorum ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.