طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 122 · برمجة قواعد البيانات
الدرس 28 · الوحدة 12: تنفيذ أمثلة عملية لتحسين استعلامات البيانات

قواعد البيانات السحابية و NoSQL

أين تعيش قواعد البيانات اليوم، ومتى تحتاج نموذجًا غير الجداول. ⏱ نحو 45 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تشرح فكرة قواعد البيانات المُدارة في السحابة وما يبقى مسؤوليتك.
  • تميز أنواع NoSQL ومتى يناسب كل منها.
  • تخزن JSONB وتستعلم عنه بـ -> و ->> و @> وتفهرسه بـ GIN.
  • تقابل مفاهيم PostgreSQL بمفاهيم Firestore.

١قاعدة البيانات في السحابة

في أغلب المشاريع الحديثة لا تثبّت PostgreSQL على خادمك، بل تستأجر خدمة مُدارة: المزوّد يتولى التثبيت والتحديثات والنسخ الاحتياطي والتوسّع، وأنت تتصل وتكتب SQL كما تعلمت تمامًا.

ما يتولاه المزوّدما يبقى عليك
تثبيت الخادم وتحديثهتصميم الجداول والفهارس
النسخ الاحتياطي التلقائيكتابة استعلامات وإجراءات جيدة
النسخ المتماثلة وتجاوز الأعطالالصلاحيات والأمان
زيادة الموارد بضغطةمراقبة البطء والكلفة

أمثلة لخدمات PostgreSQL المُدارة: Amazon RDS و Aurora، و Google Cloud SQL و AlloyDB، و Azure Database for PostgreSQL، و Supabase و Neon. وخدمات مماثلة لـ Oracle و MySQL. كل ما تعلمته في هذا المقرر يعمل عليها.

٢NoSQL: نماذج أخرى للبيانات

النوعالفكرةأمثلةيناسب
المستندات Documentكل سجل وثيقة JSON مرنة البنيةMongoDB، Firestoreبيانات متغيرة البنية، تطبيقات الجوال
مفتاح-قيمة Key-Valueقيمة تُجلب بمفتاحها فقط، بسرعة كبيرةRedis، DynamoDBالجلسات، والتخزين المؤقت
الأعمدة العريضةصفوف ضخمة موزعة على خوادم كثيرةCassandraسجلات بأحجام هائلة
الرسوم البيانية Graphعقد وعلاقاتNeo4jالشبكات الاجتماعية، والتوصيات
العلائقية SQLNoSQL المستندات
البنيةثابتة بقيودمرنة لكل وثيقة
العلاقات والربطقوية (JOIN)ضعيفة؛ تُكرر البيانات داخل الوثيقة
المعاملاتكاملة (ACID)محدودة غالبًا
المناسبالمال، والطلبات، والمخزونالمحتوى المرن، والسرعة على نطاق واسع

والواقع أن كثيرًا من الأنظمة تجمع الاثنين. و PostgreSQL نفسها تقدم أفضل ما في العالمين بنوع jsonb.

٣JSONB: وثائق مرنة داخل PostgreSQL

مواصفات المنتجات تختلف: للحاسب ذاكرة، وللشاشة حجم، وللكتاب صفحات. بدل عشرات الأعمدة الفارغة، نضع المواصفات في عمود jsonb:

query.sql
ALTER TABLE products ADD COLUMN attrs jsonb;UPDATE products SET attrs = '{"brand": "نور", "color": "فضي", "ram_gb": 16, "ports": ["USB-C", "HDMI"]}' WHERE id = 1;UPDATE products SET attrs = '{"brand": "نور", "color": "أسود", "storage_gb": 128}' WHERE id = 2;UPDATE products SET attrs = '{"brand": "رؤية", "color": "أسود", "size_in": 27, "ports": ["HDMI", "DP"]}' WHERE id = 3;UPDATE products SET attrs = '{"brand": "نور", "color": "أبيض", "wireless": true}' WHERE id = 4;UPDATE products SET attrs = '{"pages": 320, "author": "فريق المتجر"}' WHERE id = 7; SELECT name,       attrs ->> 'brand'          AS الشركة,       attrs ->> 'color'          AS اللون,       (attrs ->> 'ram_gb')::int  AS الذاكرةFROM products WHERE attrs IS NOT NULL ORDER BY id;
✓ عُدِّل
✓ عُدِّل صف واحد
✓ عُدِّل صف واحد
✓ عُدِّل صف واحد
✓ عُدِّل صف واحد
✓ عُدِّل صف واحد
النتيجة · 5 صفوف
nameالشركةاللونالذاكرة
حاسب محمولنورفضي16
جهاز لوحينورأسودNULL
شاشة 27 بوصةرؤيةأسودNULL
فأرة لاسلكيةنورأبيضNULL
تعلم SQLNULLNULLNULL
العاملالمعنىمثال
->يُرجع الحقل كـ jsonbattrs -> 'ports'
->>يُرجع الحقل كنصattrs ->> 'color'
@>هل تحتوي الوثيقة على …؟attrs @> '{"color": "أسود"}'
?هل المفتاح موجود؟attrs ? 'wireless'
query.sql
ALTER TABLE products ADD COLUMN attrs jsonb;UPDATE products SET attrs = '{"brand": "نور", "color": "فضي", "ram_gb": 16, "ports": ["USB-C", "HDMI"]}' WHERE id = 1;UPDATE products SET attrs = '{"brand": "نور", "color": "أسود", "storage_gb": 128}' WHERE id = 2;UPDATE products SET attrs = '{"brand": "رؤية", "color": "أسود", "size_in": 27, "ports": ["HDMI", "DP"]}' WHERE id = 3;UPDATE products SET attrs = '{"brand": "نور", "color": "أبيض", "wireless": true}' WHERE id = 4;UPDATE products SET attrs = '{"pages": 320, "author": "فريق المتجر"}' WHERE id = 7;CREATE INDEX ix_products_attrs ON products USING gin (attrs); SELECT name FROM products WHERE attrs @> '{"brand": "نور", "color": "أسود"}';SELECT name FROM products WHERE attrs -> 'ports' ? 'HDMI';
✓ عُدِّل
✓ عُدِّل صف واحد
✓ عُدِّل صف واحد
✓ عُدِّل صف واحد
✓ عُدِّل صف واحد
✓ عُدِّل صف واحد
✓ أُنشئ الفهرس
النتيجة · صف واحد
name
جهاز لوحي
النتيجة · صفّان
name
حاسب محمول
شاشة 27 بوصة

فهرس GIN يسرّع البحث بـ @> و ? داخل الوثائق على الجداول الكبيرة.

ويمكن بناء JSON من الجداول، كما يفعل الخادم قبل إرسال البيانات لتطبيق الجوال:

query.sql
SELECT jsonb_build_object(         'customer', c.name,         'orders', jsonb_agg(jsonb_build_object('id', o.id, 'status', o.status) ORDER BY o.id)       ) AS وثيقةFROM customers c JOIN orders o ON o.customer_id = c.idWHERE c.id = 1GROUP BY c.name;
النتيجة · صف واحد
وثيقة
{"orders":[{"id":1,"status":"shipped"},{"id":3,"status":"paid"},{"id":11,"status":"new"}],"customer":"سارة"}

٤المفهوم نفسه في Firestore

في قواعد المستندات مثل Firebase Firestore لا يوجد SQL؛ تُكتب الاستعلامات بدوال في لغة التطبيق. المفاهيم نفسها: مجموعة (≈ جدول)، ووثيقة (≈ صف)، وحقول (≈ أعمدة)، وفهارس. هذا للاطلاع فقط ولا يُشغَّل هنا:

firestore.js
// Firestore (JavaScript) — منتجات «نور» السوداءconst q = query(  collection(db, "products"),  where("attrs.brand", "==", "نور"),  where("attrs.color", "==", "أسود"));const snap = await getDocs(q);snap.forEach(doc => console.log(doc.data().name));
PostgreSQLFirestore
جدول productsمجموعة collection "products"
صفوثيقة document
WHERE attrs @> '{"brand": "نور"}'where("attrs.brand", "==", "نور")
JOINلا يوجد: تُكرر البيانات أو تُجلب بطلبات متعددة
إجراء مخزن أو محفزCloud Functions تعمل عند تغيّر الوثائق

توقّع وتحقّق

ما الذي يتولاه مزوّد الخدمة المُدارة؟

أنسب نوع لتخزين جلسات المستخدمين مؤقتًا:

العامل الذي يُرجع حقل JSON كنص:

نوع الفهرس المناسب لـ jsonb:

الخلاصة

تحدٍّ برمجي: مواصفات مرنة للمنتجات

متوسط

أضف إلى المنتجات عمود مواصفات jsonb، واملأه لمنتجين، وافهرسه، ثم ابحث فيه.

المطلوب:
  • عمود specs jsonb في products وفهرس GIN عليه.
  • المنتج 5 (لوحة مفاتيح): {"layout": "عربي", "wireless": false}، والمنتج 4 (فأرة): {"wireless": true, "dpi": 1600}.
  • آخر سطر: أسماء المنتجات اللاسلكية باستخدام @>.
👀 اعرض الناتج المطلوب
النتيجة المطلوبة
name
فأرة لاسلكية
✓ التحقق الآلي من حلّك:
  • الكود يعمل بلا أخطاء
  • المنتجات اللاسلكية: فأرة لاسلكية
  • مواصفات المنتج 4 صحيحة
  • مواصفات المنتج 5 صحيحة
  • فهرس GIN على specs
  • البحث بـ @>

💡 تلميح 1
القيم المنطقية في JSON بلا علامات تنصيص: true لا "true".
💡 تلميح 2
الفهرس: CREATE INDEX … ON products USING gin (specs);

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

solution.sql
ALTER TABLE products ADD COLUMN specs jsonb;UPDATE products SET specs = '{"layout": "عربي", "wireless": false}' WHERE id = 5;UPDATE products SET specs = '{"wireless": true, "dpi": 1600}' WHERE id = 4;CREATE INDEX ix_products_specs ON products USING gin (specs); SELECT name FROM products WHERE specs @> '{"wireless": true}';
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس