Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. 1:N — eng ko'p uchraydigani
- 2.1 Ikki tomon
- 2.2 Ixtiyoriy relation
- 3. 1:1
- 4. N:M — ikki yo'l
- 4.1 Yashirin (implicit)
- 4.2 Aniq (explicit) — kanon tanlovi
- 5. Self-relation va tarkibiy kalit
- 5.1 Kichik vazifalar
- 5.2 Kanon tajribasi: 3 daraja
- 6. include: Prisma relation'larni qanday yuklaydi
- 6.1 Alohida so'rovlar
- 6.2 relationLoadStrategy — flagsiz ishlamaydi
- 7. onDelete va onUpdate
- 7.1 Sukutlar va bazaga ta'siri
- 7.2 Kanondagi onUpdate: NoAction
- 8. relationMode: tashqi kalitsiz relation
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): qaysi tur
- 2-mashq (o'rta): include qo'lda
- 3-mashq (qiyin): kichik vazifalar daraxti
- 11. Loyiha qadami: holat 20 — relation'lar
- 12. Real ishda
- Xulosa
- Manbalar
Prisma relations: 1:1, 1:N, N:M, self-relation va onDelete
Qisqacha: Prisma'da bog'lanish ikki tomonda yoziladi: tashqi kalit turgan modelda
egasi Foydalanuvchi @relation(fields: [egasiId], references: [id]), qarshi tomonda esa ro'yxatvazifalar Vazifa[]. 1:1 — tashqi kalit@unique; N:M — yo yashirin (Prisma o'zi_AToBjadvalini yaratadi), yo aniq ko'prik model (kanondagiVazifaTegi).onDeletebazadagi referential action'ga aylanadi (Cascade,Restrict,SetNull).includerelation'larni JOIN bilan emas, alohidaIN (…)so'rovlar bilan yuklaydi.
Bu darsda
@relation(fields, references)ning ikki tomonini o'qib, qaysi model tashqi kalitni ushlashini aniqlaysiz.- 1:1, 1:N va N:M ni Prisma sxemasida yozasiz va Prisma ularni qanday SQL'ga aylantirishini ko'rasiz.
- Yashirin va aniq N:M farqini bilib, kanonda nega aniq varianti tanlanganini tushuntirasiz.
- Self-relation (kichik vazifalar) va tarkibiy tashqi kalitni o'qiy olasiz.
onDeletevarelationModeqanday ishlashini bilasiz.
Oldin bilishingiz kerak: Prisma: modellar va atributlar, Bog'lanishlar: 1:1, 1:N, N:M, Foreign key va referential actions, N+1 muammosi.
1. Nega bu kerak?
Bog'lanishlar darsida bazada bog'lanish nima ekanini o'rgandik: tashqi kalit (foreign key) ustuni va REFERENCES. Bazaga bu yetadi. Lekin Prisma'dan "Azizni vazifalari va ularning izohlari bilan ber" deb so'rash uchun, Prisma bog'lanishlarni bilishi kerak: qaysi ustun qaysi jadvalga ishora qiladi, bog'lanish birga-bir mi yoki birga-ko'p.
Shuning uchun Prisma sxemasida bog'lanish alohida yoziladi — relation maydonlari bilan. Ular bazada ustun emas: foydalanuvchi.vazifalar degan ustun yo'q. Bu Prisma'ning o'zi uchun xarita.
O'xshatish: «Bahor» oshxonasining buyurtma daftari. Har buyurtmada mijozning raqami yozilgan (tashqi kalit). Lekin ofitsiant "Jasur akaning hamma buyurtmalari" ni topishi uchun mijoz kartasiga "buyurtmalari — daftarning shu sahifalarida" degan eslatma ham kerak. Relation maydoni — o'sha eslatma.
Diqqat: Kanon — holat 20 sxemasi va uning Prisma tajribasi, Prisma 7.10.1, PostgreSQL 18.6. Kanonda yo'q 1:1 va yashirin N:M ni biz alohida namuna sxemada sinadik («Bahor» oshxonasi: mijoz, profil, buyurtma, taom) — Prisma 7.10.1, PostgreSQL 17.6, "biz ishga tushirdik".
2. 1:N — eng ko'p uchraydigani
2.1 Ikki tomon
Bir foydalanuvchida ko'p vazifa. Kanondan (qisqartirilgan):
model Foydalanuvchi {
id BigInt @id @default(autoincrement())
vazifalar Vazifa[]
@@map("foydalanuvchilar")
}
model Vazifa {
id BigInt @id @default(autoincrement())
egasiId BigInt @map("egasi_id")
egasi Foydalanuvchi @relation(fields: [egasiId],
references: [id], onDelete: Cascade)
@@map("vazifalar")
}(Uzun atribut o'qish uchun ikki qatorga bo'lindi.) O'qiymiz:
Vazifa.egasiId— oddiy skalyar maydon, bazadagiegasi_idustuni.Vazifa.egasi— relation maydoni.@relation(fields: [egasiId], references: [id])— "shu modeldagiegasiIdFoydalanuvchi.idga ishora qiladi".fieldsturgan tomon — tashqi kalitni ushlaydigan tomon.Foydalanuvchi.vazifalar Vazifa[]— qarshi tomon: ro'yxat, unda@relationargumentlari yo'q.
Ikkala tomon ham majburiy: bittasini yozsangiz, prisma validate qarshi tomonni so'raydi (prisma format uni o'zi qo'shib beradi).
flowchart LR
F["Foydalanuvchi.vazifalar: Vazifa[]"] -.->|"qarshi tomon"| V
V["Vazifa.egasi: @relation"] -->|"egasi_id REFERENCES id"| F2[(foydalanuvchilar)]Diagrammada: tashqi kalit faqat vazifalar jadvalida (egasi_id), Foydalanuvchi tomonidagi ro'yxat esa faqat Prisma xaritasi — bazada hech qanday ustun qo'shmaydi.
2.2 Ixtiyoriy relation
Izohning muallifi o'chirilgan bo'lishi mumkin (26-qismda ON DELETE SET NULL). Kanonda:
muallifId BigInt? @map("muallif_id")
muallif Foydalanuvchi? @relation(fields: [muallifId],
references: [id], onUpdate: NoAction)Ikkalasi ham ? bilan: tashqi kalit NULL bo'lishi mumkin, demak relation ham. onDelete yozilmagan — Prisma'ning sukuti ixtiyoriy relation uchun SetNull, bazadagi bilan bir xil.
Tekshirib ko'ring:
VazifadaegasiId BigInt(majburiy), lekinegasi Foydalanuvchi?(ixtiyoriy) deb yozsangiz nima bo'ladi?
Javob
prisma validate xato beradi: relation maydonining ixtiyoriyligi fields dagi skalyar maydonlarga mos bo'lishi kerak. Skalyar majburiy bo'lsa, relation ham majburiy; skalyar ? bo'lsa — relation ham ?.
3. 1:1
1:1 — 1:N ning bitta farqli holati: tashqi kalit noyob. «Bahor» namunasida har mijozning bittagina profili bor:
model Mijoz {
id Int @id @default(autoincrement())
ism String
profil Profil?
}
model Profil {
id Int @id @default(autoincrement())
telefon String
mijozId Int @unique
mijoz Mijoz @relation(fields: [mijozId], references: [id],
onDelete: Cascade)
}mijozId @unique — shu bitta atribut 1:N ni 1:1 ga aylantiradi. Qarshi tomonda ro'yxat emas, Profil? — "profil bor yoki yo'q". Prisma yasagan SQL'dan (biz ishga tushirdik, migrate diff):
CREATE UNIQUE INDEX "Profil_mijozId_key" ON "Profil"("mijozId");
ALTER TABLE "Profil" ADD CONSTRAINT "Profil_mijozId_fkey"
FOREIGN KEY ("mijozId") REFERENCES "Mijoz"("id")
ON DELETE CASCADE ON UPDATE CASCADE;Noyob indeks + tashqi kalit — Bog'lanishlar darsidagi 1:1 ning aynan o'zi. E'tibor bering: @@map yozmaganimiz uchun jadval nomlari model nomi bilan — "Mijoz", "Profil" (katta harf, qo'shtirnoqda).
4. N:M — ikki yo'l
4.1 Yashirin (implicit)
Buyurtmada ko'p taom, taom ko'p buyurtmada. Prisma'da eng qisqa yozuv — ikkala tomonda ro'yxat:
model Buyurtma {
id Int @id @default(autoincrement())
taomlar Taom[]
}
model Taom {
id Int @id @default(autoincrement())
nom String
buyurtmalar Buyurtma[]
}Ko'prik jadvalni Prisma o'zi yaratadi (biz ishga tushirdik):
CREATE TABLE "_BuyurtmaToTaom" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL,
CONSTRAINT "_BuyurtmaToTaom_AB_pkey" PRIMARY KEY ("A","B")
);
CREATE INDEX "_BuyurtmaToTaom_B_index" ON "_BuyurtmaToTaom"("B");Ustunlar A va B — model nomlarining alifbo tartibida (Buyurtma → A, Taom → B). Ikkala tashqi kalit ON DELETE CASCADE.
4.2 Aniq (explicit) — kanon tanlovi
Kanonda vazifa ↔ teg bog'lanishi — aniq ko'prik model:
model VazifaTegi {
vazifaId BigInt @map("vazifa_id")
tegId BigInt @map("teg_id")
teg Teg @relation(fields: [tegId], references: [id],
onDelete: Cascade, onUpdate: NoAction)
vazifa Vazifa @relation(fields: [vazifaId], references: [id],
onDelete: Cascade, onUpdate: NoAction)
@@id([vazifaId, tegId])
@@index([tegId], map: "vazifa_teglari_teg_id_idx")
@@map("vazifa_teglari")
}Vazifa va Teg modellarida esa vazifaTeglari VazifaTegi[].
| Yashirin | Aniq | |
|---|---|---|
| Ko'prik jadval nomi | _AToB (Prisma tanlaydi) |
o'zingizniki (vazifa_teglari) |
| Qo'shimcha ustun (vaqt, kim qo'shgan) | mumkin emas | mumkin |
| Mavjud bazaga moslash | qiyin (nom va A/B qat'iy) |
oson (@map) |
| So'rov yozish | qisqaroq (taomlar: { connect }) |
bir qadam uzunroq (vazifaTeglari: { some: { teg } }) |
Kanon uchun tanlov aniq edi: ko'prik jadval 26-qismdan bor, nomi vazifa_teglari, uni trigger to'ldiradi — yashirin N:M bunga mos kelmaydi. Kanon PrismaOmbori dagi teg filtri shunday ko'rinadi: vazifaTeglari: { some: { teg: { nom } } } — SQL'da EXISTS.
Tekshirib ko'ring: Ertaga "tegni qachon qo'shilgan" vaqti kerak bo'lib qoldi. Yashirin N:M da buni qanday qilasiz?
Javob
Yashirin N:M ga ustun qo'shib bo'lmaydi — Prisma _AToB jadvalini to'liq o'zi boshqaradi. Aniq ko'prik modelga o'tish kerak: BuyurtmaTaomi modeli, unda ikki tashqi kalit va qoshilganVaqt. Bu migratsiya talab qiladi — shuning uchun qo'shimcha ma'lumot bo'lishi mumkin bo'lgan joyda boshidanoq aniq modelni tanlash ma'qul.
5. Self-relation va tarkibiy kalit
5.1 Kichik vazifalar
Vazifaning kichik vazifalari bor — bog'lanish o'sha modelning o'ziga. Kanondan:
otaId BigInt? @map("ota_id")
ota Vazifa? @relation("KichikVazifalar",
fields: [otaId, egasiId], references: [id, egasiId],
onDelete: Cascade, onUpdate: NoAction,
map: "vazifalar_ota_id_fkey")
kichikVazifalar Vazifa[] @relation("KichikVazifalar")Uch yangi narsa:
- Relation nomi (
"KichikVazifalar") — bitta modelda bir xil turdagi ikki relation maydoni bor (otavakichikVazifalar), Prisma qaysi biri qaysiga juft ekanini nom orqali biladi. Ikkala tomonda ham bir xil nom. - Tarkibiy tashqi kalit —
fields: [otaId, egasiId], references: [id, egasiId]. 26-qismdagi qaror: ota vazifa o'sha egasiniki bo'lishi kerak; buni baza tekshiradi (FOREIGN KEY (ota_id, egasi_id) REFERENCES vazifalar (id, egasi_id)). Prisma'da bungareferencestomonda noyob juftlik kerak —Vazifadagi@@unique([id, egasiId])aynan shu uchun. map:— tashqi kalit cheklovining bazadagi nomi.
5.2 Kanon tajribasi: 3 daraja
Kanon "kichik vazifasi bor vazifalar, ularning kichiklari va yana bir daraja" ni so'radi. Natija (qisqartirilgan):
[{"matn":"Portfolio saytiga blog yozish #portfolio","kichikVazifalar":[{"matn":"Qoralama yozish","kichikVazifalar":[]},{"matn":"Blog uchun mavzu tanlash","kichikVazifalar":[]},{"matn":"Rasmlarni siqish","kichikVazifalar":[]}]},{"matn":"Kurs ishi: ma'lumotlar bazasi bo'limi #o'qish","kichikVazifalar":[{"matn":"Jadvallarni loyihalash","kichikVazifalar":[{"matn":"ER diagramma chizish"},{"matn":"Normalizatsiyani tekshirish"}]},{"matn":"Adabiyotlar ro'yxati","kichikVazifalar":[]}]}, …]Har daraja — alohida SQL so'rov (kanon logida 3 ta SELECT, ikkinchi va uchinchisi WHERE egasi_id IN ($1,$2,$3) …). Prisma rekursiyani qila olmaydi: chuqurlikni include ichiga include qo'yib o'zingiz belgilaysiz. Cheksiz chuqur daraxt kerak bo'lsa — Rekursiv CTE va raw SQL.
6. include: Prisma relation'larni qanday yuklaydi
6.1 Alohida so'rovlar
Kanon "Aziz, uning ikki vazifasi va izohlari" ni so'radi:
Aziz Karimov [
"JavaScript kursining 26-qismini boshlash #o'qish (3 izoh)",
"Postgres'ni Docker'da ko'tarish #o'qish #docker (1 izoh)"
]Bu tajriba holat 20 sxemasida ishlagan: foydalanuvchi ismi hali ism maydonida (SQL'da "foydalanuvchilar"."ism" ustuni). Zero-downtime: expand-contract darsida bu maydon toliqIsm ga aylanadi — o'shanda select dagi nom ham o'zgaradi.
Prisma yuborgan SQL'da nimaga qarash kerak: nechta SELECT bor va oxirgisida IN (qisqartirilgan):
SQL: SELECT "public"."foydalanuvchilar"."id", … FROM "public"."foydalanuvchilar" …
SQL: SELECT "public"."vazifalar"."id", "public"."vazifalar"."egasi_id", … FROM "public"."vazifalar" …
SQL: SELECT "public"."izohlar"."id", "public"."izohlar"."matn", "public"."izohlar"."vazifa_id" FROM "public"."izohlar" WHERE "public"."izohlar"."vazifa_id" IN ($1,$2) OFFSET $3Uch daraja — uch so'rov, JOIN yo'q. Muhimi — har daraja bitta so'rov: ikkala vazifaning izohlari IN ($1,$2) bilan birga olinadi. Bu N+1 emas, "1+1+1": vazifa 2 ta bo'ladimi, 200 ta — izohlar uchun baribir bitta so'rov. Natijani Prisma JS'da yig'adi.
Biz ham namunada sanadik: mijoz + profil + buyurtmalar + taomlar (N:M) — include 4 ta so'rov yubordi (biz ishga tushirdik):
Jasur aka | +998 90 000 00 00
[{"nom":"Osh"},{"nom":"Ko'k choy"}]
include so'rovlari: 46.2 relationLoadStrategy — flagsiz ishlamaydi
Prisma 7 hujjatida relationLoadStrategy: "join" (bitta SQL'da LATERAL JOIN bilan yuklash) bor, lekin "Preview" deb belgilangan. Kanon uni flagsiz sinadi:
Unknown argument `relationLoadStrategy`. Available options are marked with ?."Noma'lum argument". Prisma 7.10.1 da bu imkoniyat generator'dagi previewFeatures = ["relationJoins"] bilan yoqiladi. Preview imkoniyat — hali sinovdagi, keyingi versiyada o'zgarishi mumkin bo'lgan qism. Kanon flagni yoqmadi: loyiha barqaror API bilan qoladi. Xulosa: hujjatdagi har imkoniyat sizning versiyangizda va sozlamangizda borligini tekshiring.
Diqqat: 2026-10 holatida prisma.io/docs sukut bo'yicha Prisma 8 (release candidate) hujjatini ochadi — u yerda
includeboshqacha ishlaydi. Prisma 7 hujjati/docs/orm/v7bo'limida. Hujjatni o'qishdan oldin versiyani tekshiring.
Maslahat:
includehamma ustunlarni oladi. Faqat kerakli maydonlar uchunselectichida relation yozing:select: { ism: true, vazifalar: { select: { matn: true } } }. Bu Prisma Client CRUD darsida.
7. onDelete va onUpdate
7.1 Sukutlar va bazaga ta'siri
onDelete — Prisma bazaga yozadigan referential action (Foreign key va referential actions):
| Prisma | SQL | Ota o'chirilsa |
|---|---|---|
Cascade |
ON DELETE CASCADE |
bolalar ham o'chadi |
Restrict |
ON DELETE RESTRICT |
o'chirish rad etiladi |
NoAction |
ON DELETE NO ACTION |
rad etiladi (tekshiruv tranzaksiya oxirida ham bo'lishi mumkin) |
SetNull |
ON DELETE SET NULL |
bolada kalit NULL |
SetDefault |
ON DELETE SET DEFAULT |
bolada kalit sukut qiymatiga |
Prisma sukutlari (onDelete yozilmasa): majburiy relation — Restrict, ixtiyoriy — SetNull; onUpdate — Cascade. Biz namunada tekshirdik: Buyurtma.mijoz da onDelete yozmagan edik, Prisma yasagan SQL'da — ON DELETE RESTRICT ON UPDATE CASCADE.
Buyurtmasi bor mijozni o'chirib ko'rdik (biz ishga tushirdik):
P2003 ForeignKeyConstraintViolationP2003 — tashqi kalit cheklovi buzildi (Postgres'da 23503). Ilovada bu "avval buyurtmalarni hal qiling" degan javobga aylanadi, 500 ga emas.
7.2 Kanondagi onUpdate: NoAction
db pull kanon sxemasida hamma joyga onUpdate: NoAction yozdi — chunki 26-qism SQL'ida ON UPDATE berilmagan, Postgres sukuti esa NO ACTION. Prisma'ning o'z sukuti (Cascade) bilan bazadagi holat farq qilgani uchun introspection aniq yozib qo'ydi. Bu to'g'ri: sxema bazani tasvirlaydi. Bizda birlamchi kalitlar identity va o'zgarmaydi, shuning uchun onUpdate amalda ishlamaydi.
8. relationMode: tashqi kalitsiz relation
Ba'zi bazalar (masalan, tashqi kalitlarni qo'llamaydigan PlanetScale/Vitess) uchun Prisma'da relationMode = "prisma" bor: relation'lar faqat Prisma Client'da "emulyatsiya" qilinadi, bazada tashqi kalit yaratilmaydi. Biz namuna sxemaga uni qo'shdik:
Prisma schema warning:
- With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. … We recommend adding an index manually.migrate diff dagi FOREIGN KEY lar soni — 0 (sukut rejimda 4 ta edi). Ogohlantirish matnidagi "baza o'zi yaratadigan indeks" Postgres uchun aniq emas — Postgres tashqi kalit ustuniga indeksni o'zi yaratmaydi (Qaysi ustunga va qanday tartibda indeks); lekin xulosa to'g'ri: indeksni qo'lda qo'ying.
Postgres'da relationMode = "prisma" ishlatishga sabab yo'q: tashqi kalit — bazaning eng arzon va ishonchli himoyasi. Prisma'dan tashqari yozuvlar (raw SQL, boshqa servis) uni chetlab o'ta olmaydi. Kanon sukut rejimda (foreignKeys).
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
validate: qarshi tomon relation yo'q |
faqat bir tomon yozilgan | prisma format yoki qo'lda Vazifa[] |
Ambiguous relation |
bir modelda bir xil turdagi ikki relation | ikkala tomonda relation nomi |
| tarkibiy FK uchun xato | references noyob emas |
@@unique([id, egasiId]) |
P2003 o'chirishda |
Restrict (sukut) |
onDelete ni ongli tanlash yoki bolalarni avval hal qilish |
Unknown argument relationLoadStrategy |
preview flagi yo'q | previewFeatures = ["relationJoins"] yoki undan voz kechish |
| mavjud ko'prik jadval ishlatilmayapti | yashirin N:M _AToB yaratmoqchi |
aniq ko'prik model + @@map |
10. Mashqlar
Mashqlar kurs/mashqlar/27/22-prisma-relations/ da. 2- va 3-mashq Node 24 da tekshirilgan (biz ishga tushirdik).
1-mashq (oson): qaysi tur
- Tashqi kalitda
@uniquebor — - Ikkala tomonda ro'yxat, ko'prik model yo'q — yashirin
- Bir modelda
otavakichikVazifalar— -relation - Majburiy relation'da
onDeleteyozilmasa — - Bazada tashqi kalit yaratmaydigan rejim —
relationMode = ""
Yechim
- 1:1 —
mijozId Int @unique, qarshi tomondaProfil?. - N:M — Prisma
_BuyurtmaToTaomni o'zi yaratadi. - self — relation nomi (
"KichikVazifalar") bilan. - Restrict — ixtiyoriy relation'da
SetNull. - prisma — Postgres'da kerak emas.
2-mashq (o'rta): include qo'lda
Prisma include ni "har daraja — bitta IN so'rov + JS'da yig'ish" bilan bajaradi. Shuni o'zingiz qiling: vazifalar va izohlar massivlari berilgan; izohlarBilan(vazifalar, izohlar) har vazifaga izohlar maydonini qo'shsin. Izohlarni avval Map ga guruhlang (har vazifa uchun izohlarni bir martada topish — filter ni sikl ichida emas).
Ishora: Map — get/set (Map); ?? bilan bo'sh massiv.
Yechim
function izohlarBilan(vazifalar, izohlar) {
const guruh = new Map();
for (const i of izohlar) {
const r = guruh.get(i.vazifaId) ?? [];
r.push(i.matn);
guruh.set(i.vazifaId, r);
}
return vazifalar.map((v) => ({
...v, izohlar: guruh.get(v.id) ?? [],
}));
}
const vazifalar = [
{ id: 1, matn: "JavaScript kursining 26-qismini boshlash" },
{ id: 2, matn: "Postgres'ni Docker'da ko'tarish" },
{ id: 9, matn: "Onamga dori olib borish" },
];
const izohlar = [
{ vazifaId: 1, matn: "Boshladim" },
{ vazifaId: 2, matn: "Volume'ni unutmang" },
{ vazifaId: 1, matn: "JOIN'lar qiyin ekan" },
];
for (const v of izohlarBilan(vazifalar, izohlar)) {
console.log(v.id, v.izohlar.length, v.izohlar.join(" | "));
}Konsolda:
1 2 Boshladim | JOIN'lar qiyin ekan
2 1 Volume'ni unutmang
9 0Izohlar bir marta aylanib chiqildi — vazifalar soni oshsa ham ish chiziqli o'sadi. Sikl ichida izohlar.filter(…) yozilsa, bu JS'dagi "N+1" bo'lardi: har vazifa uchun butun ro'yxat qayta aylanadi.
3-mashq (qiyin): kichik vazifalar daraxti
Kanondagi kabi otaId li tekis ro'yxatdan daraxt chizing. daraxtniChiqar(vazifalar) ildiz vazifalarni (otaId === null) va ularning kichiklarini ikki bo'shliq chekinish bilan chiqarsin, istalgan chuqurlikda.
Ishora: avval otaId bo'yicha Map (2-mashqdagidek), keyin rekursiv funksiya (Rekursiya asoslari).
Yechim
function daraxtniChiqar(vazifalar) {
const bolalar = new Map();
for (const v of vazifalar) {
const r = bolalar.get(v.otaId) ?? [];
r.push(v);
bolalar.set(v.otaId, r);
}
function chiz(otaId, chuqurlik) {
for (const v of bolalar.get(otaId) ?? []) {
console.log(" ".repeat(chuqurlik) + v.matn);
chiz(v.id, chuqurlik + 1);
}
}
chiz(null, 0);
}
daraxtniChiqar([
{ id: 20, otaId: null, matn: "Kurs ishi: bazalar bo'limi" },
{ id: 21, otaId: 20, matn: "Jadvallarni loyihalash" },
{ id: 22, otaId: 21, matn: "ER diagramma chizish" },
{ id: 23, otaId: 21, matn: "Normalizatsiyani tekshirish" },
{ id: 24, otaId: 20, matn: "Adabiyotlar ro'yxati" },
{ id: 17, otaId: null, matn: "Portfolio saytiga blog yozish" },
{ id: 44, otaId: 17, matn: "Qoralama yozish" },
]);Konsolda:
Kurs ishi: bazalar bo'limi
Jadvallarni loyihalash
ER diagramma chizish
Normalizatsiyani tekshirish
Adabiyotlar ro'yxati
Portfolio saytiga blog yozish
Qoralama yozishPrisma'da shu daraxt uchun chuqurlikni oldindan bilish kerak edi (include ichida include). Bu yerda ma'lumot bitta so'rov bilan olinib (masalan findMany({ where: { egasiId } })), daraxt JS'da quriladi — chuqurlik cheklanmagan. Juda katta daraxtda esa rekursiv CTE bazaning o'zida qiladi. id lar misol uchun tanlangan.
11. Loyiha qadami: holat 20 — relation'lar
Holat 20 ning uchinchi qadami. Hali commit qilmang — commit PrismaOmbori tayyor bo'lgach.
Oldingi darsda tartiblangan modellarga relation maydonlarini kanondagidek qo'shing (ko'pini db pull allaqachon yozgan — nomlarini o'zgartirasiz):
| Model | Relation maydonlari |
|---|---|
Foydalanuvchi |
vazifalar Vazifa[], teglar Teg[], izohlar Izoh[] |
Vazifa |
egasi, ota / kichikVazifalar ("KichikVazifalar"), izohlar Izoh[], vazifaTeglari VazifaTegi[] |
Teg |
egasi, vazifaTeglari VazifaTegi[] |
VazifaTegi |
teg, vazifa; @@id([vazifaId, tegId]) |
Izoh |
muallif Foydalanuvchi?, vazifa |
VazifaTarixi |
relation yo'q — jadvalda tashqi kalit yo'q (26-qism qarori: tarix vazifa o'chsa ham qoladi) |
Tekshiring:
Vazifada@@unique([id, egasiId], map: "vazifalar_id_egasi_id_key")— tarkibiy FK uchun.otarelation'idamap: "vazifalar_ota_id_fkey"vaonDelete: Cascade.- Hamma relation'larda
onUpdate: NoAction(bazadagidek).
Tekshiruv: npx prisma validate, npm run db:generate, npm run tip — exit 0. Kichik skript bilan (oldingi darslardagidek) db.foydalanuvchi.findUnique({ where: { id: 1n }, include: { vazifalar: { include: { izohlar: true } } } }) ni ishga tushirib, SQL logida uchta so'rov va IN (…) ni ko'ring.
12. Real ishda
- Relation'larni to'g'ri e'lon qilish — Prisma loyihasining asosi:
include, nested write (Prisma: nested write va tranzaksiyalar) va filtrlar (some,every,none) shunga tayanadi. - Mavjud bazalarda ko'prik jadvallar deyarli doim aniq model bo'ladi — yashirin N:M yangi, kichik loyihalar uchun qulay.
- Intervyuda: "Prisma'da N:M qanday yoziladi, yashirin va aniq farqi?", "
includeN+1 ga olib keladimi?", "Prisma'daonDeletesukuti qanday?"
Xulosa
- Relation maydoni bazada ustun emas — Prisma xaritasi;
@relation(fields, references)tashqi kalitni ushlagan tomonda. - 1:1 = tashqi kalit
@unique; N:M — yashirin (_AToB,A/B) yoki aniq ko'prik model (qo'shimcha ustun, mavjud jadval). - Self-relation — relation nomi bilan; tarkibiy FK uchun
referencestomonda@@unique. include— har daraja bittaIN (…)so'rov ("1+1+1"), JOIN emas; chuqurlikni o'zingiz belgilaysiz.- Sukut: majburiy —
Restrict(P2003), ixtiyoriy —SetNull; Postgres'darelationMode = "prisma"kerak emas.
Keyingi dars: Prisma Client CRUD — findUnique, findMany, create, update, upsert, delete, select va include, va trigger qiymatlari bilan ishlash.
Manbalar
- Prisma — Relations (1:1, 1:N, N:M, self-relations): https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations
- Many-to-many (implicit, explicit): https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/many-to-many-relations
- Referential actions (sukutlar): https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/referential-actions
- Relation mode: https://www.prisma.io/docs/orm/v7/prisma-schema/data-model/relations/relation-mode
- Relation queries (
include,relationLoadStrategy): https://www.prisma.io/docs/orm/v7/prisma-client/queries/relation-queries - O'qilgan sana — 2026-10-27. Kanon o'lchovi (IlmHamroh, 2026-10): holat 20
schema.prisma(relation'lar, tarkibiy FK),includeSQL'i,relationLoadStrategyxatosi, self-relation 3 daraja. Biz ishga tushirdik (Prisma 7.10.1, PostgreSQL 17.6, Node 24.21.0): «Bahor» namuna sxemasi — 1:1 va yashirin N:M DDL,includeso'rovlari soni,P2003,relationMode = "prisma"; 2–3-mashqlar.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!