ليه الموديل مهم جدًا؟
كل أبلكيشن مبني طبقات فوق بعض، وكل طبقة بتخبي تعقيد اللي تحتها:
الموديل اللي بتختاره بيحدد إيه اللي سهل وإيه اللي صعب تعمله — فاختياره قرار كبير.
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.
مين أحسن النهارده؟
- Schema flexibility
- Locality أحسن (load المستند كله مرة واحدة)
- أقرب للـ objects في الكود
- مناسب لو الداتا شجرة ومش بتعمل joins كتير
- ❌ مش بتقدر تشاور على عنصر nested جوه مباشرة
- ❌ joins ضعيفة، many-to-many صعبة
- Joins ممتازة
- many-to-one و many-to-many مريحين
- ❌ shredding: تقطيع الشجرة لجداول كتير ممكن يبقى مزعج
التقارب: Postgres و MySQL بقوا يدعموا JSON، و RethinkDB/MongoDB بقوا يدعموا نوع من الـ joins. الموديلين بيقربوا من بعض، والهجين هو المستقبل.
لغات الاستعلام: Declarative vs Imperative
بتقول للكمبيوتر إزاي يعمل الحاجة خطوة بخطوة (loop على الصفوف وفلترة).
بتقول عايز إيه (الشروط والشكل)، والـ 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.