الأساسيات · فصل ٢

نماذج الداتا ولغات الاستعلام

Data Models and Query Languages
🎯 الهدف: تعرف تختار بين relational و document و graph حسب شكل العلاقات في الداتا بتاعتك.

ليه الموديل مهم جدًا؟

كل أبلكيشن مبني طبقات فوق بعض، وكل طبقة بتخبي تعقيد اللي تحتها:

الموديل اللي بتختاره بيحدد إيه اللي سهل وإيه اللي صعب تعمله — فاختياره قرار كبير.

Relational vs Document

الموديل العلائقي (اقترحه Codd سنة 1970): داتا في relations (جداول) فيها tuples (صفوف). كسب ضد الـ hierarchical والـ network models وفضل مسيطر 30 سنة تقريبًا.

NoSQL ظهرت (الاسم أصلًا كان هاشتاج لميت-أب 2009!) لأسباب: محتاجين scalability أكبر (كتابات كتير، داتا ضخمة)، تفضيل للـ open source، استعلامات متخصصة، وزهق من قيود الـ schema. والمستقبل غالبًا polyglot persistence: كذا نوع داتابيز جنب بعض.

مشكلة الـ Impedance Mismatch

الكود بتاعك بيفكر بـ objects، والداتابيز بتفكر بجداول — ومحتاج طبقة ترجمة (ORM زي Prisma/Hibernate) ومع ذلك مش بتخفي الفرق كله.

Many-to-One و Many-to-Many — هنا بتبان القصة

ليه نخزن region_id بدل اسم المدينة نص؟ عشان Normalization: معلومة ليها معنى بشري تتخزن مرة واحدة بس، ومن غيرها:

نفس الإملاء في كل مكانمفيش التباستعديل في مكان واحددعم الترجمة/اللغاتبحث أحسن

بس الـ normalization محتاج many-to-one relationships = joins. والـ document DBs دعمها للـ joins ضعيف، فالجوين بيتنقل لكود الأبلكيشن. ومع الوقت الداتا بتبقى مترابطة أكتر (الشركة تبقى entity ليها صفحة، التوصيات تشاور على يوزرز…) — يعني many-to-many.

مين أحسن النهارده؟

📄 Document
  • Schema flexibility
  • Locality أحسن (load المستند كله مرة واحدة)
  • أقرب للـ objects في الكود
  • مناسب لو الداتا شجرة ومش بتعمل joins كتير
  • ❌ مش بتقدر تشاور على عنصر nested جوه مباشرة
  • ❌ joins ضعيفة، many-to-many صعبة
🧮 Relational
  • Joins ممتازة
  • many-to-one و many-to-many مريحين
  • ❌ shredding: تقطيع الشجرة لجداول كتير ممكن يبقى مزعج

التقارب: Postgres و MySQL بقوا يدعموا JSON، و RethinkDB/MongoDB بقوا يدعموا نوع من الـ joins. الموديلين بيقربوا من بعض، والهجين هو المستقبل.

لغات الاستعلام: Declarative vs Imperative

Imperative (كود عادي)

بتقول للكمبيوتر إزاي يعمل الحاجة خطوة بخطوة (loop على الصفوف وفلترة).

Declarative (SQL)

بتقول عايز إيه (الشروط والشكل)، والـ optimizer يقرر إزاي.

مميزات الـ declarative: أقصر وأسهل، بيخبي تفاصيل التنفيذ فالداتابيز تقدر تحسّن نفسها من غير ما تغير الكويري، ومش بيحدد ترتيب، فـ سهل يتعمل parallel على كذا core/ماكينة.

MapReduce Querying

نموذج في النص: مش declarative بالكامل ولا imperative بالكامل. بتكتب دالتين map و reduce (لازم يكونوا pure functions: من غير side effects ولا queries إضافية) والفريمورك بيوزعها. MongoDB كان عنده MapReduce بس بعد كده عمل aggregation pipeline declarative (JSON-based) — يعني رجعوا لحاجة شبه SQL. 😄

الـ Graph Models

لو أغلب علاقاتك many-to-many، الجراف هو الطبيعي: Vertices (عُقد) و Edges (علاقات). أمثلة: سوشيال نتورك، صفحات الويب واللينكات، الطرق والخرايط. وكمان ممكن تخزن أنواع مختلفة في نفس الجراف (فيسبوك: ناس، أماكن، events، checkins، كومنتات).

الموديلالتكويناللغة
Property Graph (Neo4j, Titan)كل vertex: id + edges داخلة/خارجة + properties (key-value). كل edge: id + tail + head + label + properties.Cypher (declarative): (a)-[:BORN_IN]->(b). وممكن تعمل نفس الحاجة في SQL بـ WITH RECURSIVE بس الكويري بتطلع طويلة جدًا (≈ 4 سطور Cypher قصاد 29 سطر SQL).
Triple-Store (Datomic, AllegroGraph)كل حاجة جملة من 3 أجزاء: (subject, predicate, object) زي (جيم، بيحب، موز). الـ object إما قيمة أو vertex تاني.SPARQL (مرتبطة بالـ Semantic Web و RDF).
Datalogأقدم وأساس الحاجات دي (من الثمانينات). بتكتب rules وتبنيها فوق بعض زي الدوال.بتستخدمه Datomic و Cascalog. أقل سهولة للحاجات البسيطة بس قوي جدًا للمعقد.

🧪 Lab

جرّب نفس الداتا في موديلين بـ PostgreSQL (فيه jsonb فبيعمل الاتنين):

-- relationalCREATE TABLE users (id serial PRIMARY KEY, name text);CREATE TABLE positions (id serial PRIMARY KEY, user_id int REFERENCES users(id), title text, company text);-- document: البروفايل كله في عمود واحدCREATE TABLE profiles (id serial PRIMARY KEY, doc jsonb);INSERT INTO profiles (doc) VALUES ('{"name":"Saeed","positions":[{"title":"FE Engineer","company":"X"}]}');-- query جوه الـ JSONSELECT doc->>'name' FROM profiles WHERE doc @> '{"positions":[{"company":"X"}]}';

بعدين جرّب WITH RECURSIVE على جدول edges(from_id, to_id) عشان تحس ليه الـ graph queries بتطول في SQL.

✅ الخلاصة — Checklist

🧠 اختبر نفسك
١) عندك سيستم CV كل واحد مستند مستقل بيتعرض كله مرة واحدة — تختار إيه؟
Document model (locality + شكل شجرة طبيعي).
٢) ليه بنخزن ID بدل نص المدينة؟
Normalization: مصدر حقيقة واحد، مفيش تكرار، وتعديل في مكان واحد.
٣) ميزة SQL الكبيرة على access paths بتاعة CODASYL؟
الـ query optimizer هو اللي يختار المسار؛ تضيف index والكويري مايتغيرش.