db: seeder
This commit is contained in:
+178
-531
@@ -1,564 +1,211 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
import { Types } from "mongoose";
|
||||
|
||||
faker.locale = "fa";
|
||||
import { cleanMongoData, extractDumpData, getCollectionData } from "./utils/extractDumpData";
|
||||
import { Logger } from "../../core/logging/logger";
|
||||
import { AttributeValueModel } from "../../modules/category/models/attributeValue.model";
|
||||
import { CategoryModel } from "../../modules/category/models/category.model";
|
||||
import { CategoryAttributeModel } from "../../modules/category/models/CategoryAttribute.model";
|
||||
import { ThemeModel } from "../../modules/category/models/theme.model";
|
||||
import { ThemeValueModel } from "../../modules/category/models/themeValue.model";
|
||||
|
||||
interface ICategorySeed {
|
||||
title_fa: string;
|
||||
title_en: string;
|
||||
icon: string;
|
||||
imageUrl: string;
|
||||
description: string;
|
||||
leaf: boolean;
|
||||
themeType?: "color" | "size" | "meterage" | null;
|
||||
parent?: Types.ObjectId;
|
||||
}
|
||||
/**
|
||||
* Maps theme string from dump to Persian theme title
|
||||
*/
|
||||
const mapThemeStringToTitle = (themeString: string | null | undefined): string | null => {
|
||||
if (!themeString || themeString === "noColor_noSize") return null;
|
||||
|
||||
interface ICategoryAttributeSeed {
|
||||
title: string;
|
||||
hint?: string;
|
||||
type: string;
|
||||
multiple: boolean;
|
||||
required: boolean;
|
||||
}
|
||||
const themeMap: { [key: string]: string } = {
|
||||
Color: "رنگ",
|
||||
Size: "سایز",
|
||||
Meterage: "متراژ",
|
||||
};
|
||||
|
||||
const rootCategories: ICategorySeed[] = [
|
||||
{
|
||||
title_fa: "موبایل و تبلت",
|
||||
icon: "mobile",
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
description: "لوازم جانبی",
|
||||
title_en: "mobile",
|
||||
leaf: false,
|
||||
},
|
||||
{
|
||||
title_fa: "لوازم تحریر و اداری",
|
||||
icon: "stationery",
|
||||
description: "انواع لوازم تحریر و اداری",
|
||||
title_en: "stationery-office",
|
||||
leaf: false,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "برق و الکتریکی",
|
||||
icon: "electric",
|
||||
description: "لوازم برق و الکتریکی",
|
||||
title_en: "electric-electrical",
|
||||
leaf: false,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "لوازم و ابزارآلات",
|
||||
icon: "tools",
|
||||
description: "انواع لوازم و ابزارآلات",
|
||||
title_en: "tools-equipment",
|
||||
leaf: false,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "صوت و تصویر",
|
||||
icon: "audio-visual",
|
||||
description: "انواع لوازم صوتی و تصویری",
|
||||
title_en: "audio-visual",
|
||||
leaf: false,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "کامپیوتر",
|
||||
icon: "computer",
|
||||
description: "انواع کامپیوتر و لوازم جانبی",
|
||||
title_en: "computer",
|
||||
leaf: false,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "کنسول بازی",
|
||||
icon: "console",
|
||||
description: "انواع کنسول بازی و لوازم جانبی",
|
||||
title_en: "game-console",
|
||||
leaf: false,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "ورزش و سفر",
|
||||
icon: "sports",
|
||||
description: "لوازم ورزشی و سفر",
|
||||
title_en: "sports-travel",
|
||||
leaf: false,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{ title_fa: "پوشاک و مد", icon: "fashion", description: "لباس و مد", title_en: "fashion", leaf: false, imageUrl: faker.image.imageUrl() },
|
||||
{
|
||||
title_fa: "لوازم خانگی",
|
||||
icon: "home-appliances",
|
||||
description: "لوازم خانه",
|
||||
title_en: "home-appliances",
|
||||
leaf: false,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "متفرقه",
|
||||
icon: "malicious",
|
||||
description: "متفرقه",
|
||||
title_en: "malicious",
|
||||
leaf: true,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
];
|
||||
|
||||
const subcategories: { [key: string]: ICategorySeed[] } = {
|
||||
"موبایل و تبلت": [
|
||||
{
|
||||
title_fa: "گوشی موبایل",
|
||||
icon: "phone",
|
||||
description: "انواع گوشی های موبایل",
|
||||
title_en: "mobile-phones",
|
||||
leaf: true,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
themeType: "color",
|
||||
},
|
||||
{
|
||||
title_fa: "تبلت",
|
||||
icon: "tablet",
|
||||
description: "انواع تبلت ها",
|
||||
title_en: "tablets",
|
||||
leaf: true,
|
||||
themeType: "color",
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "ساعت هوشمند",
|
||||
icon: "watch",
|
||||
description: "انواع ساعت هوشمند",
|
||||
title_en: "smart-watch",
|
||||
leaf: true,
|
||||
themeType: "color",
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "پاور بانک",
|
||||
icon: "watch",
|
||||
description: "انواع پاور بانک",
|
||||
title_en: "power-banks",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
"لوازم تحریر و اداری": [
|
||||
{
|
||||
title_fa: "خودکار و خودنویس",
|
||||
icon: "pen",
|
||||
description: "انواع خودکار و خودنویس",
|
||||
title_en: "pens",
|
||||
leaf: true,
|
||||
themeType: "color",
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "دفتر و کاغذ",
|
||||
icon: "paper",
|
||||
description: "انواع دفتر و کاغذ",
|
||||
title_en: "paper-notebooks",
|
||||
leaf: true,
|
||||
themeType: "color",
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
"برق و الکتریکی": [
|
||||
{
|
||||
title_fa: "لامپ",
|
||||
icon: "bulb",
|
||||
description: "انواع لامپ ها",
|
||||
title_en: "bulbs",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "کابل و سیم",
|
||||
icon: "cable",
|
||||
description: "انواع کابل و سیم",
|
||||
title_en: "cables-wires",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
"لوازم و ابزارآلات": [
|
||||
{
|
||||
title_fa: "آچار و پیچ گوشتی",
|
||||
icon: "wrench",
|
||||
description: "انواع آچار و پیچ گوشتی",
|
||||
title_en: "wrenches-screwdrivers",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "دریل",
|
||||
icon: "drill",
|
||||
description: "انواع دریل ها",
|
||||
title_en: "drills",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
"صوت و تصویر": [
|
||||
{
|
||||
title_fa: "تلویزیون",
|
||||
icon: "tv",
|
||||
description: "انواع تلویزیون",
|
||||
title_en: "televisions",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "اسپیکر",
|
||||
icon: "speaker",
|
||||
description: "انواع اسپیکر",
|
||||
title_en: "speakers",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "هدفون",
|
||||
icon: "headphone",
|
||||
description: "انواع هدفون",
|
||||
title_en: "headphones",
|
||||
leaf: true,
|
||||
themeType: "color",
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "دوربین عکاسی",
|
||||
icon: "camera",
|
||||
description: "انواع دوربین عکاسی",
|
||||
title_en: "cameras",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
کامپیوتر: [
|
||||
{
|
||||
title_fa: "لپ تاپ",
|
||||
icon: "laptop",
|
||||
description: "انواع لپ تاپ",
|
||||
title_en: "laptops",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "موس و کیبورد",
|
||||
icon: "mouse-keyboard",
|
||||
description: "انواع موس و کیبورد",
|
||||
title_en: "mouse-keyboards",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
"کنسول بازی": [
|
||||
{
|
||||
title_fa: "پلی استیشن",
|
||||
icon: "playstation",
|
||||
description: "انواع پلی استیشن",
|
||||
title_en: "playstations",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "ایکس باکس",
|
||||
icon: "xbox",
|
||||
description: "انواع ایکس باکس",
|
||||
title_en: "xbox",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
"ورزش و سفر": [
|
||||
{
|
||||
title_fa: "تجهیزات ورزشی",
|
||||
icon: "sports-equipment",
|
||||
description: "انواع تجهیزات ورزشی",
|
||||
title_en: "sports-equipment",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "لوازم سفر",
|
||||
icon: "travel",
|
||||
description: "انواع لوازم سفر",
|
||||
title_en: "travel-equipment",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
"پوشاک و مد": [
|
||||
{
|
||||
title_fa: "لباس زنانه",
|
||||
icon: "women-clothing",
|
||||
description: "انواع لباس زنانه",
|
||||
title_en: "women-clothing",
|
||||
leaf: true,
|
||||
themeType: "size",
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "لباس مردانه",
|
||||
icon: "men-clothing",
|
||||
description: "انواع لباس مردانه",
|
||||
title_en: "men-clothing",
|
||||
leaf: true,
|
||||
themeType: "size",
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
"لوازم خانگی": [
|
||||
{
|
||||
title_fa: "لوازم آشپزخانه",
|
||||
icon: "kitchen-appliances",
|
||||
description: "انواع لوازم آشپزخانه",
|
||||
title_en: "kitchen-appliances",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
{
|
||||
title_fa: "لوازم نظافت",
|
||||
icon: "cleaning-appliances",
|
||||
description: "انواع لوازم نظافت",
|
||||
title_en: "cleaning-appliances",
|
||||
leaf: true,
|
||||
themeType: null,
|
||||
imageUrl: faker.image.imageUrl(),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const categoryAttributesMap: { [key: string]: ICategoryAttributeSeed[] } = {
|
||||
"گوشی موبایل": [
|
||||
{ title: "باتری", hint: "ظرفیت باتری", type: "select", multiple: false, required: true },
|
||||
{ title: "دوربین", hint: "کیفیت دوربین", type: "select", multiple: false, required: true },
|
||||
{ title: "سیستم عامل", hint: "نوع سیستم عامل", type: "select", multiple: false, required: true },
|
||||
{ title: "حافظه داخلی موبایل", hint: "ظرفیت حافظه", type: "select", multiple: false, required: true },
|
||||
{ title: "پشتیبانی از 5G", hint: "آیا پشتیبانی میکند؟", type: "checkbox", multiple: false, required: false },
|
||||
],
|
||||
تبلت: [
|
||||
{ title: "اندازه صفحه تبلت", hint: "اینچ", type: "select", multiple: false, required: true },
|
||||
{ title: "پردازنده تبلت", hint: "نوع پردازنده", type: "select", multiple: false, required: true },
|
||||
{ title: "دوربین جلو", hint: "کیفیت دوربین جلو", type: "select", multiple: false, required: false },
|
||||
{ title: "ظرفیت باتری", hint: "میلیآمپر ساعت", type: "select", multiple: false, required: true },
|
||||
{ title: "اتصال به شبکه", hint: "نوع شبکه", type: "select", multiple: false, required: false },
|
||||
],
|
||||
"خودکار و خودنویس": [
|
||||
{ title: "نوع جوهر", hint: "جوهر مورد استفاده", type: "select", multiple: false, required: true },
|
||||
{ title: "ضخامت نوشتاری", hint: "ضخامت نوک", type: "select", multiple: false, required: true },
|
||||
{ title: "قابلیت شارژ مجدد", hint: "آیا قابل شارژ است؟", type: "checkbox", multiple: false, required: false },
|
||||
{ title: "جنس بدنه خودکار", hint: "جنس بدنه خودکار", type: "select", multiple: false, required: true },
|
||||
{ title: "رنگ جوهر", hint: "رنگ جوهر خودکار", type: "select", multiple: false, required: true },
|
||||
],
|
||||
لامپ: [
|
||||
{ title: "نوع لامپ", hint: "نوع لامپ (LED، هالوژن و غیره)", type: "select", multiple: false, required: true },
|
||||
{ title: "توان مصرفی لامپ", hint: "وات", type: "select", multiple: false, required: true },
|
||||
{ title: "رنگ نور", hint: "رنگ نور", type: "select", multiple: false, required: true },
|
||||
{ title: "طول عمر", hint: "ساعت", type: "select", multiple: false, required: true },
|
||||
{ title: "قابلیت تنظیم شدت نور", hint: "آیا قابل تنظیم است؟", type: "checkbox", multiple: false, required: false },
|
||||
],
|
||||
تلویزیون: [
|
||||
{ title: "اندازه صفحه تلویزیون", hint: "اینچ", type: "select", multiple: false, required: true },
|
||||
{ title: "رزولوشن", hint: "کیفیت تصویر", type: "select", multiple: false, required: true },
|
||||
{ title: "نوع صفحه", hint: "LED, OLED, QLED", type: "select", multiple: false, required: true },
|
||||
{ title: "هوشمند", hint: "آیا هوشمند است؟", type: "checkbox", multiple: false, required: false },
|
||||
{ title: "درگاههای ارتباطی", hint: "نوع و تعداد درگاهها", type: "select", multiple: true, required: true },
|
||||
],
|
||||
"لپ تاپ": [
|
||||
{ title: "پردازنده لپ تاپ", hint: "نوع پردازنده", type: "select", multiple: false, required: true },
|
||||
{ title: "حافظه رم", hint: "ظرفیت حافظه رم", type: "select", multiple: false, required: true },
|
||||
{ title: "حافظه داخلی", hint: "ظرفیت حافظه", type: "select", multiple: false, required: true },
|
||||
{ title: "اندازه صفحه", hint: "اینچ", type: "select", multiple: false, required: true },
|
||||
{ title: "کارت گرافیک", hint: "نوع کارت گرافیک", type: "select", multiple: false, required: true },
|
||||
],
|
||||
"لباس زنانه": [
|
||||
{ title: "جنس پارچه", hint: "نوع پارچه", type: "select", multiple: false, required: true },
|
||||
{ title: "نوع یقه", hint: "یقه لباس", type: "select", multiple: false, required: true },
|
||||
{ title: "نوع آستین", hint: "آستین لباس", type: "select", multiple: false, required: true },
|
||||
{ title: "مدل لباس", hint: "نوع و مدل لباس", type: "select", multiple: false, required: true },
|
||||
{ title: "نوع شستشو", hint: "نحوه شستشو", type: "select", multiple: false, required: false },
|
||||
],
|
||||
"لوازم آشپزخانه": [
|
||||
{ title: "توان مصرفی", hint: "توان لوازم برقی", type: "select", multiple: false, required: true },
|
||||
{ title: "جنس بدنه", hint: "جنس بدنه دستگاه", type: "select", multiple: false, required: true },
|
||||
{ title: "ظرفیت", hint: "ظرفیت دستگاه", type: "select", multiple: false, required: true },
|
||||
{ title: "قابلیت تنظیم", hint: "آیا قابلیت تنظیم دارد؟", type: "checkbox", multiple: false, required: false },
|
||||
{ title: "نوع کاربری", hint: "کاربری دستگاه", type: "select", multiple: false, required: true },
|
||||
],
|
||||
// Add more categories as needed
|
||||
};
|
||||
|
||||
const attributeValuesMap: { [key: string]: string[] } = {
|
||||
باتری: ["3000mAh", "4000mAh", "5000mAh", "6000mAh", "7000mAh"],
|
||||
دوربین: ["12MP", "16MP", "20MP", "48MP", "108MP"],
|
||||
"سیستم عامل": ["اندروید", "iOS", "ویندوز", "لینوکس", "سایر"],
|
||||
"حافظه داخلی موبایل": ["32GB", "64GB", "128GB", "256GB", "512GB"],
|
||||
"پشتیبانی از 5G": ["بله", "خیر"],
|
||||
"اندازه صفحه تبلت": ["7 اینچ", "10 اینچ", "13 اینچ", "15 اینچ", "17 اینچ"],
|
||||
"پردازنده تبلت": ["Intel", "AMD", "Apple M1", "Qualcomm", "MediaTek"],
|
||||
"دوربین جلو": ["5MP", "8MP", "12MP", "16MP", "20MP"],
|
||||
"ظرفیت باتری": ["2000mAh", "3000mAh", "4000mAh", "5000mAh", "6000mAh"],
|
||||
"اتصال به شبکه": ["WiFi", "4G", "5G", "Ethernet", "بلوتوث"],
|
||||
"نوع جوهر": ["ژل", "روغنی", "آبی", "خودکار", "پلاستیکی"],
|
||||
"ضخامت نوشتاری": ["0.5mm", "0.7mm", "1.0mm", "1.2mm", "1.5mm"],
|
||||
"قابلیت شارژ مجدد": ["بله", "خیر"],
|
||||
"جنس بدنه خودکار": ["فلز", "پلاستیک", "چوب", "سرامیک", "کربن"],
|
||||
"رنگ جوهر": ["مشکی", "آبی", "قرمز", "سبز", "بنفش"],
|
||||
"نوع لامپ": ["LED", "هالوژن", "فلورسنت", "رشتهای", "پلاسما"],
|
||||
"توان مصرفی لامپ": ["5W", "10W", "15W", "20W", "25W"],
|
||||
"رنگ نور": ["سفید", "زرد", "آبی", "سبز", "قرمز"],
|
||||
"طول عمر": ["1000 ساعت", "5000 ساعت", "10000 ساعت", "20000 ساعت", "50000 ساعت"],
|
||||
"قابلیت تنظیم شدت نور": ["بله", "خیر"],
|
||||
"اندازه صفحه تلویزیون": ["20 اینچ", "32 اینچ", "40 اینچ", "60 اینچ", "70 اینچ"],
|
||||
رزولوشن: ["720p", "1080p", "4K", "8K", "HDR"],
|
||||
"نوع صفحه": ["LED", "OLED", "QLED", "Plasma", "LCD"],
|
||||
هوشمند: ["بله", "خیر"],
|
||||
"درگاههای ارتباطی": ["HDMI", "USB", "Bluetooth", "WiFi", "Ethernet"],
|
||||
"پردازنده لپ تاپ": ["Intel", "AMD", "Apple M1", "Qualcomm", "Apple M2"],
|
||||
"حافظه رم": ["4GB", "8GB", "16GB", "32GB", "64GB"],
|
||||
"حافظه داخلی": ["128GB", "256GB", "512GB", "1TB"],
|
||||
"اندازه صفحه": ["14 اینچ", "12 اینچ", "16 اینچ"],
|
||||
"کارت گرافیک": ["NVIDIA", "AMD", "Intel", "Apple M1", "ARM Mali"],
|
||||
"جنس پارچه": ["پنبه", "پلیاستر", "نایلون", "ریون", "کتان"],
|
||||
"نوع یقه": ["گرد", "هفت", "ایستاده", "دکمهای", "یقه اسکی"],
|
||||
"نوع آستین": ["کوتاه", "بلند", "سهربع", "بیآستین", "کشباف"],
|
||||
"مدل لباس": ["تیشرت", "پیراهن", "ژاکت", "هودی", "پلیور"],
|
||||
"نوع شستشو": ["ماشینی", "دستی", "خشکشویی", "آب سرد", "آب گرم"],
|
||||
"توان مصرفی": ["150W", "200W", "400W"],
|
||||
"جنس بدنه": ["فلز", "پلاستیک", "چوب", "سرامیک", "کربن"],
|
||||
ظرفیت: ["1 لیتر", "2 لیتر", "3 لیتر", "4 لیتر", "5 لیتر"],
|
||||
"قابلیت تنظیم": ["بله", "خیر"],
|
||||
"نوع کاربری": ["آبمیوهگیری", "مخلوطکن", "آسیاب", "کبابپز", "زودپز"],
|
||||
// Add more attributes and their values as needed
|
||||
return themeMap[themeString] || null;
|
||||
};
|
||||
|
||||
export const seedCategories = async (logger: Logger) => {
|
||||
try {
|
||||
logger.info("Categories seeding started");
|
||||
logger.info("Categories seeding started");
|
||||
|
||||
const colorTheme = await ThemeModel.findOne({ title: "رنگ" });
|
||||
const sizeTheme = await ThemeModel.findOne({ title: "سایز" });
|
||||
const meterageTheme = await ThemeModel.findOne({ title: "متراژ" });
|
||||
// Extract data from dump
|
||||
const dumpData = extractDumpData();
|
||||
const categoriesData = getCollectionData(dumpData, "categories");
|
||||
|
||||
const colors = colorTheme ? (await ThemeValueModel.find({ theme: colorTheme._id })).map((color) => color._id) : [];
|
||||
const sizes = sizeTheme ? (await ThemeValueModel.find({ theme: sizeTheme._id })).map((size) => size._id) : [];
|
||||
const meterages = meterageTheme ? (await ThemeValueModel.find({ theme: meterageTheme._id })).map((meterage) => meterage._id) : [];
|
||||
|
||||
const createdCategories: { [key: string]: Types.ObjectId } = {};
|
||||
const createdSubCategories: { [key: string]: Types.ObjectId } = {};
|
||||
|
||||
// Create root categories
|
||||
for (const category of rootCategories) {
|
||||
const { title_fa, icon, description, title_en, leaf, imageUrl } = category;
|
||||
|
||||
const rootCategory = new CategoryModel({ title_fa, icon, title_en, description, leaf, imageUrl });
|
||||
await rootCategory.save();
|
||||
|
||||
createdCategories[title_fa] = rootCategory._id;
|
||||
if (categoriesData.length === 0) {
|
||||
logger.warn("No category data found in dump, skipping category seeding");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create subcategories
|
||||
for (const [rootName, subs] of Object.entries(subcategories)) {
|
||||
const parentId = createdCategories[rootName];
|
||||
if (parentId) {
|
||||
for (const subcategory of subs) {
|
||||
const { title_fa, icon, description, title_en, leaf, themeType, imageUrl } = subcategory;
|
||||
// Get all themes and create a map
|
||||
const themes = await ThemeModel.find();
|
||||
const themeMap = new Map<string, Types.ObjectId>();
|
||||
themes.forEach((theme) => {
|
||||
themeMap.set(theme.title, theme._id);
|
||||
});
|
||||
|
||||
// Map themeType to theme ID and variants
|
||||
let themeId: Types.ObjectId | undefined;
|
||||
let catVariants: Types.ObjectId[] = [];
|
||||
// Get all theme values and create maps by theme
|
||||
const themeValues = await ThemeValueModel.find();
|
||||
const themeValueMap = new Map<Types.ObjectId, Types.ObjectId[]>();
|
||||
themes.forEach((theme) => {
|
||||
const values = themeValues.filter((tv) => tv.theme.toString() === theme._id.toString()).map((tv) => tv._id);
|
||||
themeValueMap.set(theme._id, values);
|
||||
});
|
||||
|
||||
if (themeType === "color" && colorTheme) {
|
||||
themeId = colorTheme._id;
|
||||
catVariants = [...colors];
|
||||
} else if (themeType === "size" && sizeTheme) {
|
||||
themeId = sizeTheme._id;
|
||||
catVariants = [...sizes];
|
||||
} else if (themeType === "meterage" && meterageTheme) {
|
||||
themeId = meterageTheme._id;
|
||||
catVariants = [...meterages];
|
||||
// Clean and prepare category data
|
||||
const cleanedCategories = categoriesData.map((cat) => cleanMongoData(cat));
|
||||
|
||||
// Filter out deleted categories
|
||||
const activeCategories = cleanedCategories.filter((cat) => !cat.deleted);
|
||||
|
||||
// Create a map to store created categories by their old _id
|
||||
const categoryIdMap = new Map<string, Types.ObjectId>();
|
||||
|
||||
// First pass: Create all categories without parent relationships
|
||||
interface CategoryToCreate {
|
||||
oldId: string;
|
||||
data: {
|
||||
title_fa: string;
|
||||
title_en: string;
|
||||
icon: string;
|
||||
imageUrl: string;
|
||||
description: string;
|
||||
leaf: boolean;
|
||||
theme?: Types.ObjectId;
|
||||
variants: Types.ObjectId[];
|
||||
deleted: boolean;
|
||||
};
|
||||
parentOldId?: string;
|
||||
}
|
||||
const categoriesToCreate: CategoryToCreate[] = [];
|
||||
|
||||
for (const cat of activeCategories) {
|
||||
const oldId = cat._id?.toString() || "";
|
||||
const parentOldId = cat.parent?.toString();
|
||||
|
||||
// Map theme string to theme ObjectId
|
||||
let themeId: Types.ObjectId | undefined;
|
||||
let variants: Types.ObjectId[] = [];
|
||||
|
||||
const themeTitle = mapThemeStringToTitle(cat.theme);
|
||||
if (themeTitle) {
|
||||
themeId = themeMap.get(themeTitle);
|
||||
if (themeId) {
|
||||
// Get all theme values for this theme
|
||||
variants = themeValueMap.get(themeId) || [];
|
||||
}
|
||||
}
|
||||
|
||||
// Map variants from dump if they exist (they might be old IDs, so we'll use all theme values)
|
||||
// If the category has specific variants in the dump, we could map them here
|
||||
// For now, we'll use all theme values for the theme
|
||||
|
||||
const categoryData = {
|
||||
title_fa: cat.title_fa,
|
||||
title_en: cat.title_en,
|
||||
icon: cat.icon || "/images/icons/default.png",
|
||||
imageUrl: cat.imageUrl || "",
|
||||
description: cat.description || "",
|
||||
leaf: cat.leaf !== undefined ? cat.leaf : true,
|
||||
theme: themeId,
|
||||
variants: variants,
|
||||
deleted: false,
|
||||
};
|
||||
|
||||
categoriesToCreate.push({
|
||||
oldId,
|
||||
data: categoryData,
|
||||
parentOldId,
|
||||
});
|
||||
}
|
||||
|
||||
// Sort categories: root categories first (no parent), then children
|
||||
const rootCategories = categoriesToCreate.filter((cat) => !cat.parentOldId);
|
||||
const childCategories = categoriesToCreate.filter((cat) => cat.parentOldId);
|
||||
|
||||
// Create root categories first
|
||||
for (const { oldId, data } of rootCategories) {
|
||||
try {
|
||||
const category = new CategoryModel(data);
|
||||
await category.save();
|
||||
categoryIdMap.set(oldId, category._id);
|
||||
logger.info(`Created root category: ${data.title_fa}`);
|
||||
} catch (error: unknown) {
|
||||
// Handle duplicate key error (title_en must be unique)
|
||||
if (error && typeof error === "object" && "code" in error && error.code === 11000) {
|
||||
const existing = await CategoryModel.findOne({ title_en: data.title_en });
|
||||
if (existing) {
|
||||
categoryIdMap.set(oldId, existing._id);
|
||||
logger.warn(`Category with title_en '${data.title_en}' already exists, using existing`);
|
||||
}
|
||||
} else {
|
||||
logger.error(`Error creating category ${data.title_fa}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create child categories with parent relationships
|
||||
// We need to process them in levels (children of roots, then grandchildren, etc.)
|
||||
let remainingCategories = [...childCategories];
|
||||
const maxIterations = 10; // Prevent infinite loops
|
||||
let iteration = 0;
|
||||
|
||||
while (remainingCategories.length > 0 && iteration < maxIterations) {
|
||||
iteration++;
|
||||
const categoriesToProcess = remainingCategories.filter((cat) => {
|
||||
// Check if parent exists in our map
|
||||
return cat.parentOldId && categoryIdMap.has(cat.parentOldId);
|
||||
});
|
||||
|
||||
if (categoriesToProcess.length === 0) {
|
||||
// No more categories can be processed (orphaned categories)
|
||||
logger.warn(`Stopped processing: ${remainingCategories.length} categories have missing parents`);
|
||||
break;
|
||||
}
|
||||
|
||||
for (const { oldId, data, parentOldId } of categoriesToProcess) {
|
||||
try {
|
||||
const parentId = parentOldId ? categoryIdMap.get(parentOldId) : undefined;
|
||||
|
||||
if (!parentId) {
|
||||
logger.warn(`Parent not found for category ${data.title_fa}, skipping`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const subCategoryDoc = new CategoryModel({
|
||||
title_fa,
|
||||
icon,
|
||||
imageUrl,
|
||||
title_en,
|
||||
description,
|
||||
leaf,
|
||||
theme: themeId,
|
||||
variants: catVariants,
|
||||
// Build hierarchy from parent
|
||||
const parentCategory = await CategoryModel.findById(parentId);
|
||||
const hierarchy = parentCategory?.hierarchy ? [...parentCategory.hierarchy, parentId] : [parentId];
|
||||
|
||||
const category = new CategoryModel({
|
||||
...data,
|
||||
parent: parentId,
|
||||
hierarchy: hierarchy,
|
||||
});
|
||||
await subCategoryDoc.save();
|
||||
|
||||
// Save the subcategory ID for later use
|
||||
createdSubCategories[title_fa] = subCategoryDoc._id;
|
||||
await category.save();
|
||||
categoryIdMap.set(oldId, category._id);
|
||||
logger.info(`Created category: ${data.title_fa} (parent: ${parentCategory?.title_fa})`);
|
||||
} catch (error: unknown) {
|
||||
// Handle duplicate key error
|
||||
if (error && typeof error === "object" && "code" in error && error.code === 11000) {
|
||||
const existing = await CategoryModel.findOne({ title_en: data.title_en });
|
||||
if (existing) {
|
||||
categoryIdMap.set(oldId, existing._id);
|
||||
logger.warn(`Category with title_en '${data.title_en}' already exists, using existing`);
|
||||
}
|
||||
} else {
|
||||
logger.error(`Error creating category ${data.title_fa}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove processed categories
|
||||
remainingCategories = remainingCategories.filter((cat) => !categoriesToProcess.includes(cat));
|
||||
}
|
||||
|
||||
const createdAttributes: { [key: string]: number } = {};
|
||||
|
||||
// Generate attributes for each subcategory
|
||||
for (const [subcategoryTitle, attributes] of Object.entries(categoryAttributesMap)) {
|
||||
const subcategoryId = createdSubCategories[subcategoryTitle];
|
||||
if (subcategoryId) {
|
||||
for (const attr of attributes) {
|
||||
const attributeDoc = new CategoryAttributeModel({
|
||||
category: subcategoryId,
|
||||
title: attr.title,
|
||||
hint: attr.hint,
|
||||
type: attr.type,
|
||||
multiple: attr.multiple,
|
||||
required: attr.required,
|
||||
});
|
||||
await attributeDoc.save();
|
||||
createdAttributes[attr.title] = attributeDoc._id;
|
||||
}
|
||||
} else {
|
||||
logger.warn(`Subcategory '${subcategoryTitle}' not found.`);
|
||||
}
|
||||
}
|
||||
// Generate values for each attribute
|
||||
for (const [attributeTitle, attributeId] of Object.entries(createdAttributes)) {
|
||||
const values = attributeValuesMap[attributeTitle] || [];
|
||||
|
||||
for (const valueText of values) {
|
||||
await AttributeValueModel.create({
|
||||
attribute: attributeId,
|
||||
text: valueText,
|
||||
});
|
||||
|
||||
// await valueDoc.save();
|
||||
}
|
||||
if (remainingCategories.length > 0) {
|
||||
logger.warn(`${remainingCategories.length} categories could not be created due to missing parents`);
|
||||
}
|
||||
|
||||
logger.info("Categories, subcategories, attributes, and values seeded successfully");
|
||||
logger.info(`Categories seeded successfully! Created ${categoryIdMap.size} categories`);
|
||||
} catch (error) {
|
||||
logger.error("Error seeding categories:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user