Mohammad Jawad Barati
Mohammad Jawad Barati
خواندن ۵ دقیقه·۴ سال پیش

ایجاد pagination در نود.جی‌اس توسط ejs و sequelize

پوستر ساختن یک وبلاگ پیشرفته در نود.جی‌اس
پوستر ساختن یک وبلاگ پیشرفته در نود.جی‌اس

برا ساختن یه pagination تو نود.جی‌اس باس چند تا مقدمه بهتون بگم:

  • مقدمه اول در مورد association ها تو sequelize هس
  • مقدمه دوم در مورد include کردن یا همون inner join زدنه

مقدمه اول

یادت باشه که توی Sequelize وقتی رابطه داری، برای Update کردن CASCADE میکنه. برای delete هم SET NULL میکنه، ولی اگه رابطه چند به چند باشه CASCADE میکنه. پس اگه چیز دیگه ای مد نظرت هست باید به صورت صریح به Sequelize بگی.

تو sequelize ما از روابط یک به یک، یک به چند و چند به چند پشتبانی می‌کنیم. حالا برا ساختن این association چهار تا متد داریم:

  1. متد HasOne
  2. متد BelongsTo
  3. متد HasMany
  4. متد BelongsToMany

این متدا تقریبا به یه شکل استفاده میشن و یه آرگومان دومی هم برا تنظیمات بیشتر دارن. حواست به نحوه‌ی تعریف association باشه. الان تو این مثال A مدل source هس و B مدل target هس. (مثالا رو از داک sequelize برداشتم)

A.hasOne(B, { /* options */ }); A.belongsTo(B, { /* options */ }); A.hasMany(B, { /* options */ }); A.belongsToMany(B, { through: 'C', /* options */ });

خط اول مثال بالا داره میگه یه رابطه یک به یک داریم و کلید اصلی مدل source به صورت خودکار به عنوان کلید خارجی تو مدل target تعریف میشه.

خط دوم داره میگه یه رابطه یک به یک داریم و کلید اصلی مدل target به صورت خودکار به عنوان کلید خارجی تو مدل source تعریف میشه (دقیقا برعکس خط یک).

خط سوم داره میگه یه رابطه یک به چند داریم که کلید اصلی مدل source به صورت خودکار به عنوان کلید خارجی تو مدل target تعریف میشه.

https://aparat.com/v/RKgA1

خط چهارم داره میگه یه رابطه چند به چند داریم. برا ایجاد این رابطه sequelize خودش یه جدول جدید می‌تعریفه (اگه بهش تو رشته مقدار بدید، دقیقا همین کاری که اینجی کردیم) و کلید اصلی مدل target و مدل source به عنوان کلید اصلی ترکیبی تو جدول C تعریف می‌کنه.

ست کردن option های مختلف

ست کردن through

به جدول C که واسطه بین دو تا جدول ما هست junction table میگن. ولی اگه شما میخواید junction table تون یه سری column های بیشتری داشته باشه باس خودتون یه مدل تعریف کنید و بعد اونو به جای 'C' بدید (مثل این: C)

پس در مجموع اگه بخوای یه رابطه یک به یک بسازی باس از hasOne و belongsTo به صورت همزمان استفاده بکنی. و اگه یه رابطه یک به چند میخوای از hasMany به همراه belongsTo استفاده میتونی، یادت باشه اگه از hasMany به همراه hasOne برا ایجاد association یک به چند استفاده بکنی به ارور Cyclic dependency یا Dependency chain میخوری:

استفاده از hasMany و hasOne برا ایجاد رابطه یک به چند یه Cycle Dependency درس میکنه که اشتبه.
استفاده از hasMany و hasOne برا ایجاد رابطه یک به چند یه Cycle Dependency درس میکنه که اشتبه.

برا ایجاد رابطه چند به چند هم باس از belongsToMany استفاده بکنی. فقط تو این یه مورد باید through رو تو option هاش بدی ولی بقیه option هاش مثل onDelete و ... اختیاری هس و اگه ست نکنی مقدار پیشفرضش که No Action هس رو میگیره.

// posts M:N tags PostModel.belongsToMany(TagModel, { through: 'post_tags', onDelete: 'CASCADE' }); TagModel.belongsToMany(PostModel, { through: 'post_tags', onDelete: 'CASCADE' });

ست کردن foreignKey

توی اینجا میتونی تنظیمات FK رو مشخص بکنی. مثلا اسم ستون، nullable بودن، مقدار پیشفرض رو مشخص بکنی

مقدمه دوم

برا اینکه include رو تو sequelize بفهمید باس اول دو تا مفهوم رو که پایه ای هستن یاد بگیرید: Eager Loading و Lazy Loading.

تو Lazy Loading میگیم اگه واقعا دیتا های مرتبط رو هم لازم داری بگو تا برات fetch اش بکنیم. ولی Eager Loading اون طرف دیگه قضیه هس که میگه من همه چیو با یه کوئری خفن ولی گنده (همه‌ی دیتا هایی که به نظرت لازمت میشه و بعدا لازمش داری) میام fetch میکنم. بزارید با مثال براتون نمایش بدمش:

// Lazy loading const post = await Post.findOne({ where: { slug: &quotJack-Sparrow&quot } }); // Do whatever you want with post // Now we want post's writer const user = await post.getUser();

خب فک کنم الان دارید میفهمید وقتی نوشتم که فقط زمانی که بهش نیاز داشتید میای دیتای مورد نیازتو fetch میکنی. تو این مثال اول خود پستو fetch کردیم و بعدا که به اطلاعات فردی که این پستو نوشته نیاز پیدا کردیم اومدیم اطلاعاتش رو هم fetch کردیم.

ما از Lazy loading تو مواردی استفاده می‌کنیم که تحت یه شرایط خاصی میخواییم دیتا های مرتبط رو هم fetch کنیم و تو بعضی شرایط به اون دیتا ها نیاز نداریم. Lazy loading تو save کردن زمان و مموری به ما کمک میکنه.

این متد getUser توسط خود sequelize به مدل post اضافه شده و شما میتونید توسط اون اطلاعات کاربرو fetch کنید.

const users = await User.findAll({ include: { model: UserRole, where: { accessLevel: 2 } } });

همون جوری که میبینید تو این مثال همه‌ی کاربرا رو بعلاوه اطلاعات role شون تو سیستم fetch کردیم. توجه کنید که اگه بخوای چند تا چیزو به صورت همزمان fetch کنی باس اینکار بکنی:

posts = await PostModel.findAll({ where: { isPublished: true }, include: [ { model: CategoryModel, attributes: ['title'], where: { title: categoryTitle } }, { model: CommentModel }, { model: UserModel, attributes: ['fullname', 'id'] } ] });

یعنی از [] برا اینکه چند تا چیزو با هم include کنی باس استفاده بکنی. حالا روش که forEach بزنی فیلدایی رو که برا مدلت تعریف کردی داری. خود sequelize میاد فیلدای اون مدلای دیگه رو به آبجکتی که برمی‌گردونه اضافه میکنه.

posts.forEach((post, i) => { // post.categories.forEach(category => { /* ... */ }); // post.title // post.user.fullname // post.comments.forEach(comment => { /* ... */ });

خب حالا بقیشو باس برید تو آپارات نگاه بکنید:)

https://www.aparat.com/v/Ryx3j

لینک: https://www.aparat.com/v/Ryx3j

node jssequelizeejseagerloadingexpressjs
برنانه نویس، مدرس، محقق. عاشق انیمه هستم و دنبال چالش ها جدید.
شاید از این پست‌ها خوشتان بیاید