Mundarija (27)
- Bu darsda
- 1. Nega bu kerak?
- 2. Seed, migratsiya va fixture
- 3. Idempotent seed
- 3.1 Muammo
- 3.2 Usul 1: ON CONFLICT
- 3.3 Usul 2: o'zinikini o'chirib qayta yozish
- 4. Deterministik ma'lumot
- 4.1 Urug' bilan tasodif
- 4.2 Faker
- 4.3 SQL'da: setseed
- 5. Prodakshn himoyasi
- 6. prisma db seed
- 6.1 Sozlash
- 6.2 Kanon seed.ts
- 6.3 Kanon natijasi
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson)
- 2-mashq (o'rta)
- 3-mashq (qiyin)
- 9. Loyiha qadami
- 9.1 Holat 39
- 9.2 Tekshiruv
- 10. Real ishda
- Xulosa
- Manbalar
Seed: dev va test bazasini idempotent, deterministik ma'lumot bilan to'ldirish
Qisqacha: Seed (urug' ma'lumot) — bo'sh dev yoki test bazasini bir buyruqda ishlashga yaroqli ma'lumot bilan to'ldiradigan skript. Yaxshi seed uch shartga javob beradi: idempotent (ikki marta ishga tushsa ham dublikat va xato yo'q), deterministik (har safar aynan bir xil ma'lumot — urug' qiymati bilan) va prodakshnda ishlamaydi. Kanon
prisma db seed: 20 foydalanuvchi, 281 vazifa, 286 izoh — 775 ms; ikkinchi ishga tushirishda hash bir xil;NODE_ENV=productionda to'xtadi.
Bu darsda
- Seed, migratsiya va test fixture'ining farqini tushuntira olasiz.
- Seed'ni idempotent qilishning ikki usulini qo'llaysiz:
ON CONFLICTva "o'zinikini o'chirib qayta yozish". - Urug' (seed) qiymati bilan deterministik ma'lumot yaratasiz — JS'da va SQL'da.
- Prisma'da
prisma db seedni sozlab, kanonseed.tsni o'qiysiz. - Prodakshn himoyasi va katta sintetik to'plam yaratishni bilasiz.
Oldin bilishingiz kerak: Migratsiya tushunchasi, UPSERT va MERGE, Prisma Client CRUD, Asosiy murakkablik sinflari.
1. Nega bu kerak?
Malika jamoaga qo'shildi. Repo'ni klonladi, npm ci, npm run db:migrate — baza tayyor. Ilovani ochadi: ro'yxat bo'sh. Biror sahifani tekshirish uchun u qo'lda 5 foydalanuvchi, 30 vazifa, izohlar yaratadi. Yarim kun ketdi. Ertaga Sardor ham xuddi shuni qiladi — o'z ma'lumotlari bilan. Xato topilganda: "menda ishlayapti, senda ishlamayapti" — chunki ikkalasining bazasi har xil.
Seed bu muammoni hal qiladi: bitta buyruq — npm run db:seed — va har dasturchining bazasida aynan bir xil realistik ma'lumot. Skrinshotlar bir xil, xato qayta yaratiladi, yangi odam birinchi kuni ishlay boshlaydi.
O'xshatish: dehqonning urug'lik zaxirasi. Har bahor bir xil navli urug' ekiladi — hosil oldindan ma'lum. Har yili tasodifiy urug' sepsa, nima unib chiqishini hech kim bilmaydi.
Bu so'z kursda ikki ma'noda kelgan: 12-qismda urug' (seed) — tasodifiy sonlar generatorining boshlang'ich qiymati (Nozik xatolar: flaky test). Bu yerda ham ikkala ma'no birga ishlaydi: seed skripti ichida urug' qiymati turadi.
2. Seed, migratsiya va fixture
Uchta tushuncha tez-tez aralashtiriladi:
| Migratsiya | Seed | Test fixture | |
|---|---|---|---|
| Nima | Sxema (va ma'lumotnoma) | Demo/dev ma'lumot | Bitta test uchun ma'lumot |
| Qayerda ishlaydi | Hamma muhit, prodakshn ham | Lokal, dev, staging | Test ichida |
| Necha marta | Bir marta, holat jadvali bilan | Istalgancha | Har test oldidan |
| Misol | CREATE TABLE, ustuvorlik enum |
20 foydalanuvchi, 281 vazifa | "egasi 2 ta vazifali foydalanuvchi" |
Ma'lumotnoma (reference data) — ilova ishlashi uchun shart bo'lgan, hamma muhitda bir xil ma'lumot: valyutalar ro'yxati, viloyatlar, rollar, bizda — ustuvorlik qiymatlari (past, orta, yuqori, 004 migratsiyasida enum). U migratsiyada bo'ladi, chunki prodakshnga ham kerak. Demo foydalanuvchilar esa — seed'da: ular prodakshnga hech qachon tushmasligi kerak.
Test fixture'lar — 27-qismning oxirgi darslarida (Factory va fixture'lar): har test o'zining kichik ma'lumotini yaratadi va boshqa testlarga tayanmaydi.
3. Idempotent seed
3.1 Muammo
Sequelize darsida ko'rdik: oddiy seeder ikkinchi marta ishga tushganda yiqildi — Key (email)=(ali@example.com) already exists. Seed'ni bir necha marta ishga tushirish esa tabiiy: yangi kod tortdingiz, seed o'zgardi, qayta ishga tushirasiz. Seed idempotent bo'lishi kerak: necha marta bajarilsa ham, natija bir xil.
3.2 Usul 1: ON CONFLICT
Holat 39 bazasida (biz ishga tushirdik, PostgreSQL 17.6, Windows 11). Uch seed foydalanuvchini ikki marta qo'shamiz:
INSERT INTO foydalanuvchilar (email, toliq_ism) VALUES
('seed1@seed.example', 'Sadoqat Tohirova'),
('seed2@seed.example', 'Muhtor Nosirov'),
('seed3@seed.example', 'Nodira Rashidova')
ON CONFLICT ((lower(email))) DO NOTHING;
INSERT INTO foydalanuvchilar (email, toliq_ism) VALUES
('seed1@seed.example', 'Sadoqat Tohirova'),
('seed2@seed.example', 'Muhtor Nosirov'),
('seed3@seed.example', 'Nodira Rashidova')
ON CONFLICT ((lower(email))) DO NOTHING;
SELECT count(*) FROM foydalanuvchilar
WHERE email LIKE '%@seed.example';Natija:
INSERT 0 3
INSERT 0 0
count
-------
3
(1 row)Ikkinchi INSERT — 0 0: hech narsa qo'shilmadi, xato ham yo'q. ON CONFLICT ((lower(email))) — qo'shaloq qavslarga e'tibor bering: 26-qismda email noyobligi ustunga emas, ifodaga (lower(email)) qurilgan edi, shuning uchun to'qnashuv nishoni ham ifoda (UPSERT va MERGE).
DO NOTHING — "bor bo'lsa, tegma". Seed qiymati o'zgargan bo'lsa (foydalanuvchi ismini tuzatdingiz) — DO UPDATE SET toliq_ism = EXCLUDED.toliq_ism kerak. Ma'lumotnoma jadvallari uchun bu ayniqsa foydali: migratsiya har safar ro'yxatni yangilaydi.
3.3 Usul 2: o'zinikini o'chirib qayta yozish
Ko'p jadvalli seed'da (foydalanuvchi → vazifalar → izohlar) har jadvalga ON CONFLICT yozish og'ir. Kanon boshqa yo'lni tanlagan: seed faqat o'zi yaratgan yozuvlarni taniydi — email …@seed.example — ularni o'chiradi va qaytadan yaratadi. vazifalar va izohlar ON DELETE CASCADE bilan birga o'chadi:
BEGIN;
DELETE FROM foydalanuvchilar WHERE email LIKE '%@seed.example';
SELECT count(*) AS namuna FROM foydalanuvchilar;
ROLLBACK;Natija:
BEGIN
DELETE 3
namuna
--------
8
(1 row)
ROLLBACKSeed'ning 3 foydalanuvchisi ketdi, namuna ma'lumoti (8 ta) joyida qoldi. (Biz ROLLBACK qildik — seed foydalanuvchilari keyingi bo'limda kerak.) Bu usulning kuchi — chegara: seed hech qachon begona ma'lumotga tegmaydi. example domeni — zaxiralangan, hech kimga tegishli emas, shuning uchun haqiqiy foydalanuvchi bilan to'qnashmaydi.
Diqqat: "Hamma jadvalni
TRUNCATEqilib, keyin to'ldirish" — eng oddiy, lekin eng xavfli seed. U bir kun noto'g'riDATABASE_URLbilan ishga tushadi. IlmHamroh'ning o'z platformasida aynan shunday holat bo'lgan: eskiseed.tsjadvallarni tozalardi va uni prodakshnda ishga tushirish taqiqlangan; kanonseed.tsizohida ham shu voqeaga ishora bor.
Tekshirib ko'ring: Kanon seed'i
@seed.examplefoydalanuvchilarini o'chiradi. Dasturchi seed foydalanuvchisi nomidan ilovada qo'lda vazifa qo'shgan bo'lsa, keyingi seed'da nima bo'ladi?
Javob
U vazifa ham o'chadi — ON DELETE CASCADE foydalanuvchi bilan birga hamma vazifalarini oladi. Bu kutilgan xatti-harakat: seed foydalanuvchilari "seed'ga tegishli", ular ichidagi hamma narsa har safar qayta yaratiladi. Saqlanishi kerak bo'lgan sinov ma'lumotini o'z (seed bo'lmagan) foydalanuvchingizda yarating.
4. Deterministik ma'lumot
4.1 Urug' bilan tasodif
Seed realistik bo'lishi uchun tasodifiy ma'lumot kerak: har foydalanuvchida 0–30 vazifa, 40 % i bajarilgan. Lekin har safar boshqacha tasodif — har dasturchida boshqacha baza. Yechim — urug'li generator: bir xil urug' — bir xil "tasodifiy" ketma-ketlik. Asosiy murakkablik sinflari darsidagi makeRandom aynan shunday:
function makeRandom(seed) {
return () => (seed = (seed * 16807) % 2147483647);
}
const ISMLAR = ["Sadoqat", "Muhtor", "Nodira", "Jasur", "Malika"];
function foydalanuvchilarYasa(urug, soni) {
const random = makeRandom(urug);
return Array.from({ length: soni }, (_, i) => ({
email: `foydalanuvchi${i + 1}@seed.example`,
ism: ISMLAR[random() % ISMLAR.length],
vazifalar: random() % 31,
}));
}
console.log(foydalanuvchilarYasa(27, 3));
console.log(JSON.stringify(foydalanuvchilarYasa(27, 3)) ===
JSON.stringify(foydalanuvchilarYasa(27, 3)));Konsolda:
[
{
email: 'foydalanuvchi1@seed.example',
ism: 'Malika',
vazifalar: 21
},
{
email: 'foydalanuvchi2@seed.example',
ism: 'Muhtor',
vazifalar: 11
},
{
email: 'foydalanuvchi3@seed.example',
ism: 'Nodira',
vazifalar: 20
}
]
trueIkki chaqiruv — aynan bir xil natija (true). Urug'ni o'zgartirsangiz (28) — boshqa, lekin yana barqaror ketma-ketlik.
4.2 Faker
Haqiqiy loyihada ism, shahar, sana, telefon uchun faker kutubxonasi ishlatiladi. Kanon @faker-js/faker 10.6.0 ni oldi (faqat dev bog'liqlik) va o'zbekcha lotin lokalini:
import { fakerUZ_UZ_latin as faker } from "@faker-js/faker";
faker.seed(27);
faker.person.fullName(); // "Sadoqat Tohirova"
faker.number.int({ min: 0, max: 30 });
faker.datatype.boolean({ probability: 0.4 });
faker.helpers.arrayElement(["past", "orta", "yuqori"]);faker.seed(27) — urug'. Kanon seed'ining birinchi uch foydalanuvchisi (kanon o'lchovi, IlmHamroh, 2026-10):
Sadoqat Tohirova|foydalanuvchi1@seed.example
Muhtor Nosirov|foydalanuvchi2@seed.example
Nodira Rashidova V|foydalanuvchi3@seed.exampleKanon faker sifatida bir nechta kamchilikni qayd etgan — bilib qo'ying:
To\raqorgon—o'` o'rniga teskari apostrof (lokal ma'lumotidagi xato).- "Nodira Rashidova V" — familiyadan keyin ortiqcha harf (yuqorida ko'rinib turibdi).
loremmatnlari — lotincha, o'zbekcha emas. Shuning uchun kanon vazifa matnlarini o'z ro'yxatidan oladi ("Hisobot yozish", "Bozordan non olish" …).
faker.date.recent({ days: 30, refDate: "2026-10-25T00:00:00Z" }) — refDate bilan: aks holda "oxirgi 30 kun" bugungi sanaga bog'liq bo'ladi va determinizm buziladi.
4.3 SQL'da: setseed
Katta sintetik to'plam uchun JS'dan ko'ra SQL tezroq: ma'lumot tarmoqdan o'tmaydi. PostgreSQL'da urug' — setseed(). Seed foydalanuvchisiga 1 000 vazifa:
SELECT setseed(0.27) \gset
WITH t AS (
SELECT g, random() < 0.4 AS b FROM generate_series(1, 1000) g
)
INSERT INTO vazifalar (egasi_id, matn, bajarildi, bajarilgan_vaqt)
SELECT f.id, 'Vazifa ' || t.g, t.b,
CASE WHEN t.b THEN timestamptz '2026-10-25 09:00+05'
- make_interval(hours => t.g) END
FROM foydalanuvchilar f, t
WHERE f.email = 'seed1@seed.example';
SELECT count(*) AS jami,
count(*) FILTER (WHERE bajarildi) AS bajarilgan,
min(tartib) AS tartib_min, max(tartib) AS tartib_max
FROM vazifalar v JOIN foydalanuvchilar f ON f.id = v.egasi_id
WHERE f.email = 'seed1@seed.example';Natija:
INSERT 0 1000
jami | bajarilgan | tartib_min | tartib_max
------+------------+------------+------------
1000 | 400 | 1 | 1000
(1 row)Bir necha tafsilot:
\gset—setseedning bo'sh natija qatorini ekranga chiqarmaslik uchun (psql o'zgaruvchisiga yozadi).bajarilgan_vaqt—bajarildibilan birga: 26-qismdagiCHECK (bajarildi = (bajarilgan_vaqt IS NOT NULL))(ALTER TABLE darsidagi004migratsiyasi). Birinchi urinishimizda biz uni unutdik vavazifalar_bajarilgan_vaqt_checkxatosini oldik — seed ham bazaning hamma qoidalaridan o'tishi kerak.tartib1 dan 1000 gacha — biz bermadik, uni013trigger'i qo'ydi. Seed trigger'larni chetlab o'tmaydi — bu yaxshi: ma'lumot haqiqiy ilova yaratgandek.matnda raqam (Vazifa 1,Vazifa 2) —014faol vazifalar matnini egasi bo'yicha noyob qiladi; kanon seed'i ham shu sabab raqam qo'shadi.
Shu blokni (avval vazifalarni o'chirib) qayta ishga tushirdik — natija aynan o'sha: 400 bajarilgan. Urug' ishladi.
DELETE FROM vazifalar WHERE egasi_id =
(SELECT id FROM foydalanuvchilar
WHERE email = 'seed1@seed.example');
SELECT setseed(0.27) \gset
WITH t AS (
SELECT g, random() < 0.4 AS b FROM generate_series(1, 1000) g
)
INSERT INTO vazifalar (egasi_id, matn, bajarildi, bajarilgan_vaqt)
SELECT f.id, 'Vazifa ' || t.g, t.b,
CASE WHEN t.b THEN timestamptz '2026-10-25 09:00+05'
- make_interval(hours => t.g) END
FROM foydalanuvchilar f, t
WHERE f.email = 'seed1@seed.example';
SELECT count(*) FILTER (WHERE bajarildi) AS bajarilgan
FROM vazifalar v JOIN foydalanuvchilar f ON f.id = v.egasi_id
WHERE f.email = 'seed1@seed.example';Natija:
DELETE 1000
INSERT 0 1000
bajarilgan
------------
400
(1 row)Tekshirib ko'ring: Kanon katta to'plamni (500 000 vazifa) SQL bilan 71 soniyada qurgan, 1 000 foydalanuvchili Prisma seed'i esa 15 035 vazifani 29 soniyada. Nega SQL shunchalik tez?
Javob
Prisma seed'i har foydalanuvchi uchun alohida so'rovlar yuboradi (create, createManyAndReturn, createMany) — har biri Node ↔ baza aylanishi. INSERT … SELECT … generate_series esa butun ishni baza ichida, bitta buyruqda qiladi — tarmoq yo'q. Katta hajmda (COPY, batch va cursor) qoida: ma'lumotni bazaning o'zida yarating yoki COPY bilan oqim sifatida yuboring.
5. Prodakshn himoyasi
Seed'ning eng muhim qatori — birinchisi. Kanon seed.ts boshida:
if (process.env["NODE_ENV"] === "production") {
console.error(
"seed: NODE_ENV=production — to'xtatildi " +
"(seed faqat lokal/staging uchun)");
process.exit(1);
}Kanon sinovi:
$ NODE_ENV=production npm run db:seed
seed: NODE_ENV=production — to'xtatildi (seed faqat lokal/staging uchun)
[exit 1]Bu himoya yetarlimi? To'liq emas: NODE_ENV noto'g'ri qo'yilgan staging serveri prodakshn bazasiga ulangan bo'lishi mumkin. Qo'shimcha qatlamlar:
- Seed faqat o'zinikiga tegadi (
@seed.example) — xato bilan ishga tushsa ham, haqiqiy foydalanuvchilar o'chmaydi. - Ulanish satrini tekshirish:
DATABASE_URLdalocalhost/127.0.0.1bo'lmasa — aniq tasdiq talab qilish. - Prodakshn bazasiga ulanish huquqi dasturchining kompyuterida umuman bo'lmasligi.
Himoyani kod bilan sinash mumkin — u toza funksiya:
function seedRuxsat(env) {
if (env.NODE_ENV === "production") return "rad: production";
const url = env.DATABASE_URL ?? "";
if (url === "") return "rad: DATABASE_URL yo'q";
const host = new URL(url).hostname;
if (!["127.0.0.1", "localhost"].includes(host)) {
return env.SEED_TASDIQ === "ha" ? "ruxsat (tasdiq bilan)"
: `rad: ${host} lokal emas`;
}
return "ruxsat";
}
const lokal = "postgres://postgres@127.0.0.1:5498/vazifalar";
const uzoq = "postgres://app@db.example.com:5432/vazifalar";
console.log(seedRuxsat({ DATABASE_URL: lokal }));
console.log(seedRuxsat({
NODE_ENV: "production", DATABASE_URL: lokal }));
console.log(seedRuxsat({ DATABASE_URL: uzoq }));
console.log(seedRuxsat({ DATABASE_URL: uzoq, SEED_TASDIQ: "ha" }));Konsolda:
ruxsat
rad: production
rad: db.example.com lokal emas
ruxsat (tasdiq bilan)new URL() ulanish satridan xostni ajratadi (URL va URLSearchParams) — postgres:// ham URL sifatida o'qiladi.
6. prisma db seed
Kanon seed'i uchala qoidani ketma-ket bajaradi. Diagrammani yuqoridan o'qing — har qadam bitta qoida:
flowchart TD
A[npm run db:seed] --> B{NODE_ENV = production?}
B -->|ha| C[To'xtash, exit 1]
B -->|yo'q| D[faker.seed 27 — urug']
D --> E[O'zinikini o'chirish: @seed.example]
E --> F[Foydalanuvchi, vazifa, izoh yaratish]
F --> G[Natija qatori va disconnect]B — himoya, D — determinizm, E — idempotentlik. Shu uchtasi bo'lmasa, seed foydasidan zarari ko'p.
6.1 Sozlash
Prisma 7 da seed buyrug'i prisma.config.ts da (kanon holat 39):
export default defineConfig({
schema: "prisma/schema.prisma",
// seed: `npx prisma db seed` (holat 39)
migrations: {
path: "prisma/migrations",
seed: "node prisma/seed.ts",
},
...(url === undefined ? {} : { datasource: { url } }),
});seed: "node prisma/seed.ts" — Node 24 .ts ni type stripping bilan o'zi bajaradi. Ishga tushirish — ikki yo'l: npx prisma db seed yoki npm run db:seed (node --env-file-if-exists=.env prisma/seed.ts — Prisma 7 .env ni o'zi o'qimagani uchun).
6.2 Kanon seed.ts
Asosiy qismi (kanon prisma/seed.ts, izohlar qisqartirildi, uzun qatorlar bo'lindi):
const SONI = Number(process.env["SEED_FOYDALANUVCHI"] ?? "20");
const db = new PrismaClient({
adapter: new PrismaPg({ connectionString: url }) });
faker.seed(27);
const ochirildi = await db.foydalanuvchi.deleteMany({
where: { email: { endsWith: "@seed.example" } } });
for (let i = 1; i <= SONI; i++) {
const f = await db.foydalanuvchi.create({
data: {
email: `foydalanuvchi${String(i)}@seed.example`,
toliqIsm: faker.person.fullName(),
sozlamalar: { til: faker.helpers.arrayElement(
["uz-Latn", "uz-Cyrl", "ru", "en"]) },
},
select: { id: true },
});
const n = faker.number.int({ min: 0, max: 30 });
// createMany — bitta INSERT; tartib trigger'i har qatorga
const r = await db.vazifa.createManyAndReturn({
data: Array.from({ length: n }, (_, j) => {
const bajarildi =
faker.datatype.boolean({ probability: 0.4 });
return {
egasiId: f.id,
matn: `${faker.helpers.arrayElement(ISHLAR)} ` +
`${String(j + 1)} ${faker.helpers.arrayElement(TEGLAR)}`,
bajarildi,
bajarilganVaqt: bajarildi ? faker.date.recent({
days: 30, refDate: "2026-10-25T00:00:00Z" }) : null,
ustuvorlik: faker.helpers.arrayElement(
["past", "orta", "orta", "yuqori"] as const),
};
}),
select: { id: true },
});
// … izohlar: har vazifaga 0–2 ta, createMany bilan
}
await db.$disconnect();Yuqoridagi uch qoida — hammasi shu yerda: deleteMany faqat @seed.example (idempotent, chegarali), faker.seed(27) va refDate (deterministik), fayl boshidagi NODE_ENV tekshiruvi (himoya). SEED_FOYDALANUVCHI — hajmni o'zgartirish uchun. Vazifa matnida teg (#uy, #ish) — 006 trigger'i teglarni matndan o'zi ajratadi.
6.3 Kanon natijasi
Kanon o'lchovi (Prisma 7.10.1, faker 10.6.0, PostgreSQL 18.6). Ikki raqamga qarang — yaratilgan qatorlar soni va vaqt:
$ npx prisma db seed
Running seed command `node prisma/seed.ts` ...
seed: o'chirildi 0 eski seed foydalanuvchi; yaratildi 20 foydalanuvchi, 281 vazifa, 286 izoh — 775 ms
The seed command has been executed.Ikkinchi marta (npm run db:seed):
seed: o'chirildi 20 eski seed foydalanuvchi; yaratildi 20 foydalanuvchi, 281 vazifa, 286 izoh — 718 ms
determinizm (ikki ishga tushirish xeshi bir xilmi): HA (faed53457a548399f6a19a8695dd03d0)
ikkinchidan keyin: 20 seed foydalanuvchi (takrorlanmadi)Kanon ikki ishga tushirishdan keyingi seed ma'lumotining hashini hisoblagan — ma'lumotning qisqa "barmoq izi": bitta harf farq qilsa ham, hash butunlay boshqacha bo'lardi. Ikkalasi bir xil chiqdi (chiqishdagi "xeshi" — kanon skriptining yozuvi, ma'nosi hash). Namuna (8 foydalanuvchi) har safar joyida qoldi. Katta hajm: SEED_FOYDALANUVCHI=1000 — 15 035 vazifa, 14 989 izoh, 29 069 ms.
7. Ko'p uchraydigan xatolar
1. already exists / duplicate key ikkinchi ishga tushirishda. Seed idempotent emas. Tuzatish: ON CONFLICT yoki "o'zinikini o'chirib qayta yozish".
2. Har dasturchida boshqa ma'lumot. Urug'siz Math.random()/faker. Tuzatish: faker.seed(N), refDate, SQL'da setseed.
3. Seed bazaning qoidalarini buzadi. vazifalar_bajarilgan_vaqt_check, 014 noyoblik — biz ham uchradik. Tuzatish: seed'ni ham migratsiyadan keyin, bazaning hamma cheklovlari bilan sinash — u ilova kabi yozishi kerak.
4. Demo ma'lumot migratsiyada. Prodakshnga test foydalanuvchilari tushadi. Tuzatish: migratsiyada — faqat ma'lumotnoma; demo — seed'da.
5. TRUNCATE li seed. Bir kun noto'g'ri bazada ishlaydi. Tuzatish: chegarali o'chirish va prodakshn himoyasi.
6. Seed sekin. Har qator — alohida so'rov. Tuzatish: createMany, partiyalar, katta hajm — SQL generate_series yoki COPY.
8. Mashqlar
Yechimlar tekshirilgan (biz ishga tushirdik, PostgreSQL 17.6, Node 24.21.0).
1-mashq (oson)
Har ma'lumot qayerga yoziladi — migratsiya, seed yoki test fixture? (a) O'zbekiston viloyatlari ro'yxati (manzil formasi uchun); (b) 20 ta demo foydalanuvchi; (c) "o'chirilgan vazifa ro'yxatda chiqmaydi" testining ikkita vazifasi; (d) admin roli.
Yechim
(a) Migratsiya — ilova ishlashi uchun shart, hamma muhitda bir xil (ma'lumotnoma). (b) Seed — faqat dev/staging. (c) Test fixture — shu test o'zi yaratadi va o'zi ishlatadi. (d) Migratsiya — rol tizimning bir qismi; lekin admin foydalanuvchining o'zi (email, parol) — na migratsiya, na seed: u prodakshnda alohida, xavfsiz yo'l bilan yaratiladi (28-qism).
2-mashq (o'rta)
makeRandom va ISMLAR dan foydalanib vazifalarYasa(urug, soni) funksiyasini yozing: har vazifa { matn, bajarildi }, matn — ISHLAR ro'yxatidan + tartib raqami ("Kitob o'qish 1"), bajarildi — taxminan 40 % (random() % 10 < 4). Urug' 27, 5 ta vazifa yarating va ikki chaqiruv bir xil ekanini tekshiring. Ishora: Array.from({ length }, fn) (flat, flatMap va Array.from).
Yechim
function makeRandom(seed) {
return () => (seed = (seed * 16807) % 2147483647);
}
const ISHLAR = ["Hisobot yozish", "Bozordan non olish",
"Kitob o'qish", "Mashq qilish"];
function vazifalarYasa(urug, soni) {
const random = makeRandom(urug);
return Array.from({ length: soni }, (_, i) => ({
matn: `${ISHLAR[random() % ISHLAR.length]} ${i + 1}`,
bajarildi: random() % 10 < 4,
}));
}
const a = vazifalarYasa(27, 5);
for (const v of a) console.log(v.matn, v.bajarildi);
console.log(JSON.stringify(a) ===
JSON.stringify(vazifalarYasa(27, 5)));Konsolda:
Bozordan non olish 1 true
Mashq qilish 2 true
Hisobot yozish 3 false
Bozordan non olish 4 true
Mashq qilish 5 false
trueMatnga tartib raqami qo'shildi — xuddi kanon seed'idagidek, 014 noyoblik qoidasi uchun. 5 ta vazifadan 3 tasi bajarilgan (60 %) — kichik namunada 40 % aniq chiqmaydi, bu normal; urug' esa natijani har safar bir xil qiladi.
3-mashq (qiyin)
Ma'lumotnoma jadvali uchun idempotent migratsiya yozing: viloyatlar (kod text PRIMARY KEY, nom text NOT NULL). Uni ikki marta ishga tushiring: ikkinchi safar bitta viloyat nomi tuzatilgan bo'lsin ('Toshkent v.' → 'Toshkent viloyati') va bitta yangi viloyat qo'shilgan bo'lsin. Natijada dublikat yo'q, tuzatish qo'llangan bo'lsin. Oxirida jadvalni o'chiring. Ishora: ON CONFLICT (kod) DO UPDATE SET nom = EXCLUDED.nom (UPSERT va MERGE).
Yechim
CREATE TABLE IF NOT EXISTS viloyatlar (
kod text PRIMARY KEY, nom text NOT NULL);
INSERT INTO viloyatlar (kod, nom) VALUES
('TO', 'Toshkent v.'), ('SA', 'Samarqand viloyati')
ON CONFLICT (kod) DO UPDATE SET nom = EXCLUDED.nom;
CREATE TABLE IF NOT EXISTS viloyatlar (
kod text PRIMARY KEY, nom text NOT NULL);
INSERT INTO viloyatlar (kod, nom) VALUES
('TO', 'Toshkent viloyati'), ('SA', 'Samarqand viloyati'),
('BU', 'Buxoro viloyati')
ON CONFLICT (kod) DO UPDATE SET nom = EXCLUDED.nom;
SELECT kod, nom FROM viloyatlar ORDER BY kod;
DROP TABLE viloyatlar;Natija:
CREATE TABLE
INSERT 0 2
NOTICE: relation "viloyatlar" already exists, skipping
CREATE TABLE
INSERT 0 3
kod | nom
-----+--------------------
BU | Buxoro viloyati
SA | Samarqand viloyati
TO | Toshkent viloyati
(3 rows)
DROP TABLEIkkinchi INSERT — 0 3: bittasi qo'shildi, ikkitasi yangilandi (DO UPDATE ham sanaladi). Dublikat yo'q, TO ning nomi tuzatildi. Bu naqsh ma'lumotnoma uchun — prodakshnda ham xavfsiz, chunki faqat o'z kalitlariga tegadi. Haqiqiy loyihada bunday ro'yxat migratsiya faylida bo'ladi va har o'zgarish yangi migratsiya bilan keladi; DO UPDATE esa shu migratsiyani bir necha bazada qayta qo'llashni xavfsiz qiladi.
9. Loyiha qadami
9.1 Holat 39
Kanon commit'i:
npm i -D --save-exact @faker-js/faker@10.6.0
git add prisma/seed.ts prisma.config.ts package.json
git add package-lock.json tsconfig.json
M='feat(db): prisma/seed.ts — deterministik (faker uz_UZ_latin,'
M+=" seed 27), idempotent, production'da ishlamaydi"
git commit -m "$M"O'zgarishlar:
prisma/seed.ts— «Kanon seed.ts» bo'limidagi fayl to'liq (boshidaNODE_ENVvaDATABASE_URLtekshiruvlari,ISHLARvaTEGLARro'yxatlari, oxirida natija qatori).prisma.config.ts—migrations.seed: "node prisma/seed.ts".package.json—"db:seed": "node --env-file-if-exists=.env prisma/seed.ts", dev bog'liqlik@faker-js/faker10.6.0 (prodakshnga kirmaydi).tsconfig.json—includegaprisma/seed.ts(tsc strict uni ham tekshirsin).
9.2 Tekshiruv
npm run db:migrate
npm run db:seed
npm run db:seed
NODE_ENV=production npm run db:seed
npm run checkKutilgan: birinchi va ikkinchi seed — "yaratildi 20 foydalanuvchi, 281 vazifa, 286 izoh" (ikkinchisida "o'chirildi 20"), uchinchisi — "to'xtatildi", exit 1; tip/lint 0, testlar 99/99 (kanon tekshiruvi). Vaqt mashinangizga bog'liq.
10. Real ishda
- Har loyihada README'da "ishga tushirish:
npm ci,npm run db:migrate,npm run db:seed" — yangi dasturchining birinchi kuni shu uch buyruq. - Staging ko'pincha seed bilan emas, prodakshnning anonimlashtirilgan nusxasi bilan to'ldiriladi — haqiqiy hajm va taqsimot, lekin shaxsiy ma'lumotsiz (Ma'lumotni qisman ko'chirish).
- Demo va savdo — seed'li stend mijozga ko'rsatiladi; deterministik bo'lgani uchun har safar bir xil manzara.
- Intervyuda: "Seed va migratsiya farqi?", "Seed'ni qanday idempotent qilasiz?", "Prodakshnda seed ishga tushib ketmasligi uchun nima qilasiz?".
Xulosa
- Seed — dev/test ma'lumoti; ma'lumotnoma — migratsiyada; test ma'lumoti — fixture'da.
- Idempotent:
ON CONFLICT DO NOTHING/DO UPDATEyoki faqat o'zinikini (@seed.example) o'chirib qayta yozish. - Deterministik: urug' —
makeRandom,faker.seed(27)+refDate, SQL'dasetseed; kanon hash'i ikki ishga tushirishda bir xil. - Himoya:
NODE_ENV=productionda to'xtash (kanon: exit 1), lokal bo'lmagan xostda tasdiq, chegarali o'chirish. - Seed ham bazaning cheklov va trigger'laridan o'tadi; katta hajm — SQL'da (
generate_series) yokiCOPYbilan.
Keyingi dars: Migratsiyani deploy jarayonida qo'llash — migratsiyani kim va qachon qo'llaydi: alohida qadam, advisory lock, server ishga tushishidagi tekshiruv va BOM tuzog'i.
Manbalar
- Prisma hujjati — Seeding your database (
prisma db seed,prisma.config.ts): https://www.prisma.io/docs/orm/prisma-migrate/workflows/seeding - Faker hujjati — Reproducible results (
faker.seed,refDate), lokallar: https://fakerjs.dev/guide/usage - PostgreSQL 18 hujjati —
setseed,random,INSERT … ON CONFLICT: https://www.postgresql.org/docs/18/sql-insert.html - Kanon o'lchovi (IlmHamroh, 2026-10): holat 39,
prisma/seed.ts(Prisma 7.10.1, faker 10.6.0, PostgreSQL 18.6, 2026-10-25); darsdagi SQL va JS — biz ishga tushirdik (PostgreSQL 17.6, Node 24.21.0, Windows 11), 2026-10-27.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!