تعد ترحيلات قواعد البيانات تعديلات يتم إجراؤها على قاعدة البيانات. قد تشمل هذه التعديلات تغيير مخطط جدول، تحديث البيانات في مجموعة من السجلات، إدخال بيانات أو حذف مجموعة من السجلات.

عادة ما يتم تشغيل ترحيلات قواعد البيانات قبل بدء التطبيق ولا يتم تشغيلها بنجاح أكثر من مرة واحدة لنفس قاعدة البيانات. تقوم أدوات ترحيل قواعد البيانات بحفظ سجل من الترحيلات التي تم تنفيذها في قاعدة بيانات بحيث يمكن تتبعها لأغراض مستقبلية.

في هذه المقالة، ستتعلم كيف تقوم بإعداد وتشغيل ترحيلات قواعد البيانات في تطبيق API بسيط باستخدام Node.js. سنستخدم ts-migrate-mongoose وسكربت npm لإنشاء ترحيل وإدخال بيانات في قاعدة بيانات MongoDB. يدعم ts-migrate-mongoose تشغيل سكربتات الترحيل من كود TypeScript بالإضافة إلى كود CommonJS.

يعد ts-migrate-mongoose إطار عمل لترحيل المشاريع في Node.js التي تستخدم mongoose كخريطة بيانات كائنية. يوفر قالبًا لكتابة سكربتات الترحيل. كما يوفر تكوينًا لتشغيل السكربتات برمجيًا ومن واجهة سطر الأوامر.

فهرس المحتويات

كيفية إعداد المشروع

لاستخدام ts-migrate-mongoose في ترحيل قاعدة البيانات، تحتاج إلى ما يلي:

  1. مشروع Node.js مع تثبيت mongoose كاعتماد.

  2. قاعدة بيانات MongoDB متصلة بالمشروع.

  3. بوصلة MongoDB (اختياري – لتمكيننا من عرض التغييرات في قاعدة البيانات).

تم إنشاء مستودع بداية يمكن نسخه من ts-migrate-mongoose-starter-repo للسهولة. انسخ المستودع، قم بملء المتغيرات البيئية وابدأ التطبيق عن طريق تشغيل الأمر npm start.

قم بزيارة http://localhost:8000 باستخدام متصفح أو عميل API مثل Postman وسيقوم الخادم بإرجاع نص “مرحبًا!” لإظهار أن تطبيق البداية يعمل كما هو متوقع.

كيفية تكوين ts-migrate-mongoose للمشروع

لتكوين ts-migrate-mongoose للمشروع، قم بتثبيت ts-migrate-mongoose باستخدام هذا الأمر:

npm install ts-migrate-mongoose

يتيح ts-migrate-mongoose التكوين باستخدام ملف JSON، ملف TypeScript، ملف .env أو عبر واجهة سطر الأوامر. من المستحسن استخدام ملف .env لأن محتوى التكوين قد يحتوي على كلمة مرور لقاعدة البيانات وليس من اللائق أن يتم عرضها للجمهور. يتم إخفاء ملفات .env عادةً من خلال ملفات .gitignore لذا فهي أكثر أمانًا للاستخدام. سيستخدم هذا المشروع ملف .env لتكوين ts-migrate-mongoose.

يجب أن يحتوي الملف على المفاتيح التالية وقيمها:

  • MIGRATE_MONGO_URI – عنوان URI لقاعدة بيانات Mongo. هو نفس عنوان URL لقاعدة البيانات.

  • MIGRATE_MONGO_COLLECTION – اسم المجموعة (أو الجدول) التي يجب حفظ الترحيلات فيها. القيمة الافتراضية هي migrations وهو ما يُستخدم في هذا المشروع. يقوم ts-migrate-mongoose بحفظ الترحيلات في MongoDB.

  • MIGRATE_MIGRATIONS_PATH – المسار إلى المجلد لتخزين وقراءة سكربتات الترحيل. القيمة الافتراضية هي ./migrations وهو ما يُستخدم في هذا المشروع.

كيفية زرع بيانات المستخدمين باستخدام ts-migrate-mongoose

لقد تمكنا من إنشاء مشروع وربطه بنجاح بقاعدة بيانات Mongo. في هذه المرحلة، نود زرع بيانات المستخدمين في قاعدة البيانات. نحتاج إلى:

  1. إنشاء مجموعة (أو جدول) للمستخدمين

  2. استخدام ts-migrate-mongoose لإنشاء سكربت ترحيل لزرع البيانات

  3. استخدام ts-migrate-mongoose لتشغيل الترحيل لزرع بيانات المستخدمين في قاعدة البيانات قبل بدء التطبيق

1. إنشاء مجموعة مستخدمين باستخدام Mongoose

يمكن استخدام مخطط Mongoose لإنشاء مجموعة مستخدمين (أو جدول). ستحتوي وثائق المستخدمين (أو السجلات) على الحقول (أو الأعمدة) التالية: email و favouriteEmoji و yearOfBirth.

لإنشاء مخطط Mongoose لمجموعة المستخدمين، أنشئ ملف user.model.js في جذر المشروع الذي يحتوي على مقطع الكود التالي:

const mongoose = require("mongoose");

const userSchema = new mongoose.Schema(
  {
    email: {
      type: String,
      lowercase: true,
      required: true,
    },
    favouriteEmoji: {
      type: String,
      required: true,
    },
    yearOfBirth: {
      type: Number,
      required: true,
    },
  },
  {
    timestamps: true,
  }
);

module.exports.UserModel = mongoose.model("User", userSchema);

2. إنشاء سكربت هجرة باستخدام ts-migrate-mongoose

يوفر ts-migrate-mongoose أوامر CLI يمكن استخدامها لإنشاء سكربتات هجرة.

تشغيل npx migrate create <name-of-script> في مجلد الجذر للمشروع سينشئ سكربت في مجلد MIGRATE_MIGRATIONS_PATH (./migrations في حالتنا). <name-of-script> هو الاسم الذي نريد أن يكون لملف سكربت الهجرة عند إنشائه.

لإنشاء سكربت هجرة لزرع بيانات المستخدمين، قم بتشغيل:

npx migrate create seed-users

سينشئ الأمر ملفًا في مجلد ./migrations باسم بتنسيق –<timestamp>-seed-users.ts. سيحتوي الملف على محتوى مقطع الكود التالي:

// استيراد نماذجك هنا

export async function up (): Promise<void> {
  // اكتب الهجرة هنا
}

export async function down (): Promise<void> {
  // اكتب الهجرة هنا
}

تُستخدم وظيفة up لتشغيل الترحيل. تُستخدم وظيفة down لعكس ما تنفذه وظيفة up، إذا لزم الأمر. في حالتنا، نحن نحاول زرع مستخدمين في قاعدة البيانات. ستحتوي وظيفة up على الكود الخاص بزرع المستخدمين في قاعدة البيانات وستحتوي وظيفة down على الكود الخاص بحذف المستخدمين الذين تم إنشاؤهم في وظيفة up.

إذا تم فحص قاعدة البيانات باستخدام MongoDB Compass، ستحتوي مجموعة الترحيل على وثيقة تبدو مثل هذا:

{
  "_id": ObjectId("6744740465519c3bd9c1a7d1"),
  "name": "seed-users",
  "state": "down",
  "createdAt": 2024-11-25T12:56:36.316+00:00,
  "updatedAt": 2024-11-25T12:56:36.316+00:00,
  "__v": 0
}

يتم تعيين حقل state في وثيقة الترحيل إلى down. بعد تشغيله بنجاح، يتغير إلى up.

يمكنك تحديث الكود في ./migrations/<timestamp>-seed-users.ts إلى الكود في المقتطف أدناه:

require("dotenv").config() // تحميل المتغيرات البيئية
const db = require("../db.js")
const { UserModel } = require("../user.model.js");

const seedUsers = [
  { email: "[email protected]", favouriteEmoji: "🏃", yearOfBirth: 1997 },
  { email: "[email protected]", favouriteEmoji: "🍏", yearOfBirth: 1998 },
];

export async function up (): Promise<void> {
  await db.connect(process.env.MONGO_URI)
  await UserModel.create(seedUsers);}

export async function down (): Promise<void> {
  await db.connect(process.env.MONGO_URI)
  await UserModel.delete({
    email: {
      $in: seedUsers.map((u) => u.email),
    },
  });
}

3. تشغيل الترحيل قبل بدء التطبيق

يوفر ts-migrate-mongoose لنا أوامر واجهة سطر الأوامر لتشغيل وظيفة up و down من نصوص الترحيل.

باستخدام npx migrate up <name-of-script> يمكننا تشغيل وظيفة up لنص معين. بـ npx migrate up يمكننا تشغيل وظيفة up لجميع النصوص في مجلد ./migrations بحالة down في قاعدة البيانات.

لتشغيل الهجرة قبل بدء التطبيق، نستخدم سكربت npm. سيتم تشغيل سكربتات npm التي تحتوي على بادئة pre قبل تشغيل سكربت بدون البادئة pre. على سبيل المثال، إذا كان هناك سكربت dev وسكربت predev، فعند تشغيل سكربت dev باستخدام npm run dev، سيتم تشغيل سكربت predev تلقائياً قبل تشغيل سكربت dev.

سنستخدم هذه الميزة في سكربتات npm لوضع أمر ts-migrate-mongoose في سكربت prestart حتى تعمل الهجرة قبل تشغيل السكربت start.

قم بتحديث ملف package.json ليحتوي على سكربت prestart الذي يقوم بتشغيل أمر ts-migrate-mongoose لتشغيل وظيفة up من سكربتات الهجرة في المشروع.

  "scripts": {
    "prestart": "npx migrate up",
    "start": "node index.js"
  },

بهذا الإعداد، عند تنفيذ npm run start لبدء التطبيق، سيتم تشغيل سكربت prestart لتنفيذ الهجرة باستخدام ts-migrate-mongoose وزرع قاعدة البيانات قبل بدء التطبيق.

يجب أن تكون لديك شيئًا مماثل للقصاصة أدناه بعد تشغيل npm run start:

Synchronizing database with file system migrations...
MongoDB connection successful
up: 1732543529744-seed-users.ts 
All migrations finished successfully

> [email protected] start
> node index.js

MongoDB connection successful                      
Server listening on port 8000

تحقق من فرع seed-users في مستودع الشفرة لرؤية الحالة الحالية لقاعدة الشفرة في هذه النقطة في المقال.

كيفية بناء نقطة نهاية API لاسترجاع البيانات المزروعة

يمكننا بناء نقطة نهاية API لاسترجاع بيانات المستخدمين المزروعة في قاعدة البيانات لدينا. في ملف server.js، قم بتحديث الشفرة إلى الشفرة الموجودة في القصاصة أدناه:

const { UserModel } = require("./user.model.js")

module.exports = async function (req, res) {
  const users = await UserModel.find({}) // احصل على جميع المستخدمين في قاعدة البيانات

  res.writeHead(200, { "Content-Type": "application/json" });
  return res.end(JSON.stringify({ // ارجع تمثيل JSON لبيانات المستخدمين التي تم جلبها
    users: users.map((u) => ({
      email: u.email,
      favouriteEmoji: u.favouriteEmoji,
      yearOfBirth: u.yearOfBirth,
      createdAt: u.createdAt
    }))
  }, null, 2));
};

إذا بدأنا التطبيق وزرنا http://localhost:8000 باستخدام Postman أو متصفح ويب، سنحصل على استجابة JSON مشابهة للتالي:

{
  "users": [
    {
      "email": "[email protected]",
      "favouriteEmoji": "🏃",
      "yearOfBirth": 1997,
      "createdAt": "2024-11-25T14:18:55.416Z"
    },
    {
      "email": "[email protected]",
      "favouriteEmoji": "🍏",
      "yearOfBirth": 1998,
      "createdAt": "2024-11-25T14:18:55.416Z"
    }
  ]
}

لاحظ أنه إذا تم تشغيل التطبيق مرة أخرى، فإن نص الهجرة لن يتم تشغيله مرة أخرى لأن الحالة للهجرة ستكون الآن مفعلة بعد تشغيلها بنجاح.

تحقق من فرع fetch-users في مستودع الشفرة لرؤية الحالة الحالية لقاعدة الشفرة في هذه المرحلة من المقالة.

الاستنتاج

الهجرات هي مفيدة عند بناء التطبيقات وهناك حاجة لزرع بيانات أولية للاختبار، زرع مستخدمين إداريين، تحديث مخطط قاعدة البيانات عن طريق إضافة أو إزالة أعمدة وتحديث قيم الأعمدة في السجلات بشكل جماعي.

يمكن لـ ts-migrate-mongoose أن يساعد في توفير إطار عمل لتشغيل الهجرات لتطبيقات Node.js الخاصة بك إذا كنت تستخدم Mongoose مع MongoDB.