<?xml version="1.0"?>
<rss version="2.0"><channel><title>DevOps: &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/?d=4</link><description>DevOps: &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</description><language>ar</language><item><title>&#x645;&#x642;&#x627;&#x631;&#x646;&#x629; &#x628;&#x64A;&#x646; MariaDB &#x648; MySQL</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-mariadb-%D9%88-mysql-r848/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2025_05/10037215.---MariaDB--MySQL-------.png.1727e3ababe7e6995141ed90dc60fdc1.png" /></p>
<p>
	قد يكون اختيار قاعدة البيانات المناسبة للمشروع أمرًا صعبًا، خاصةً مع وجود العديد من الخيارات.
</p>

<p>
	تقدم قاعدتا بيانات MariaDB و MySQL ميزات كثيرة، ولكن يمكن أن تؤثر نقاط القوة والضعف لكل منهما على الأداء وقابلية التوسع والتوافق مع التطبيقات المختلفة مثل WordPress، لذا سنوضح في هذا المقال الاختلافات الأساسية بين قاعدتي البيانات MariaDB و MySQL، وسنتحدث عن ميزاتهما ومدى سرعتهما وأمانهما وكيفية استخدامهما.
</p>

<h2 id="mariadbmysql">
	نظرة عامة على MariaDB و MySQL
</h2>

<p>
	نشأت كل من MariaDB <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">وMySQL</a> من الجذور نفسها، إذ يعود أصلهما إلى نظام قاعدة بيانات إنجرس Ingres الذي طوّرته جامعة كاليفورنيا في بيركلي.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="172725" href="https://academy.hsoub.com/uploads/monthly_2025_05/001_mysql.png.91ad6265b3b87b9f97ffafd8e707c94d.png" rel=""><img alt="001 mysql" class="ipsImage ipsImage_thumbnailed" data-fileid="172725" data-unique="fc0m8txik" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2025_05/001_mysql.thumb.png.92d3db649010f05310cfd880c0db119f.png"> </a>
</p>

<p>
	طُوِّرت <a href="https://academy.hsoub.com/devops/servers/databases/mysql/" rel="">MySQL</a> لأول مرة في عام 1995 واكتسبت شعبيةً كبيرةً لأنها كانت سهلة الاستخدام وسريعة، ولكن أصبح هناك خلاف بين مالكي MySQL وأوراكل Oracle لاحقًا، لذا جرى تطوير قاعدة بيانات جديدة بالاسم MariaDB.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="172726" href="https://academy.hsoub.com/uploads/monthly_2025_05/002_mariadb.png.76ca8c91307f524c84a08767be883ee4.png" rel=""><img alt="002 mariadb" class="ipsImage ipsImage_thumbnailed" data-fileid="172726" data-unique="9wa8yhljl" src="https://academy.hsoub.com/uploads/monthly_2025_05/002_mariadb.png.76ca8c91307f524c84a08767be883ee4.png"> </a>
</p>

<p>
	تم تطوير قاعدةَ بيانات <a href="https://mariadb.org/" rel="external nofollow">MariaDB</a> من طرف نفس مطوري MySQL في عام 2009، وكان الهدف هو الحفاظ على ميزات MySQL نفسها مع إضافة ميزات جديدة أيضًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="172723" href="https://academy.hsoub.com/uploads/monthly_2025_05/003____DBMS.png.49f59d617d64d113ddd2f20c51cc5fd7.png" rel=""><img alt="003_الحصة_السوقية_لأنظمة_DBMS.png" class="ipsImage ipsImage_thumbnailed" data-fileid="172723" data-ratio="48.33" data-unique="1q2ie65kv" style="width: 700px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2025_05/003____DBMS.thumb.png.4723a8dd8b5d3ce61ade5c3dcf422352.png"></a>
</p>

<p>
	تنمو الآن MariaDB و MySQL كل على حدة، ولكل منهما ميزاتها وفوائدها الرئيسية.
</p>

<h2 id="">
	الميزات والفوائد الرئيسية
</h2>

<p>
	تتشابه MariaDB و MySQL في الكثير من الأمور، لأنهما نشأتا من قاعدة الشيفرة البرمجية نفسها، ولكنهما تطورتا بطريقة مستقلة، مما أدى إلى بعض الاختلافات في ميزاتهما وفوائدهما.
</p>

<h3 id="mariadb">
	ميزات وفوائد MariaDB
</h3>

<p>
	تشتهر MariaDB بكونها سريعة وقادرة على التعامل مع عدد كبير من العمليات، ولديها ميزات خاصة تسرّع من عمل الاستعلامات وتجعلها تعمل بطريقة أفضل مع حركة المرور الكبيرة.
</p>

<p>
	تحتوي MariaDB أيضًا على طرق جديدة لتخزين البيانات، والتي يمكن أن تساعدها على التصرّف بطريقة أفضل في مواقف معينة.
</p>

<p>
	تتضمن بعض ميزات MariaDB الميزة MCS لتحليل البيانات وميزة MaxScale للمحافظة على سير الأمور وموازنة العمل وميزة Galera Cluster لنسخ البيانات بدقة.
</p>

<h3 id="mysql">
	ميزات وفوائد MySQL
</h3>

<p>
	تحسّنت <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">قاعدة بيانات MySQL</a> بمرور الوقت، ولا تزال تحظى بشعبية كبيرة لأن العديد من الأشخاص يستخدمونها مع إتاحة المساعدة؛ وتحتوي على طرق مختلفة لتخزين البيانات مثل InnoDB و MyISAM ولكل منها إيجابياتها وسلبياتها.
</p>

<p>
	تحتوي MySQL على ميزات مثل البحث عن الكلمات الكاملة والمنبّهات Trigger والإجراءات المُخزَّنة، والتي يمكن أن تكون مفيدةً لإنشاء تطبيقات قواعد بيانات معقدة.
</p>

<h2 id="mariadbmysql-1">
	مقارنة بين MariaDB و MySQL
</h2>

<p>
	هناك العديد من الاختلافات الرئيسية بين MySQL و MariaDB بالرغم من وجود بنية ووظائف متشابهة كما هو موضح في الجدول التالي:
</p>

<table>
	<thead>
		<tr>
			<th>
				الميزة
			</th>
			<th>
				قاعدة بيانات MariaDB
			</th>
			<th>
				قاعدة بيانات MySQL
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				محركات التخزين
			</td>
			<td>
				محركات InnoDB و Aria و MyISAM و TokuDB و XtraDB و MariaDB Column Store
			</td>
			<td>
				محرّكات InnoDB و MyISAM و Aria و NDB و TokuDB
			</td>
		</tr>
		<tr>
			<td>
				تحسين السرعة
			</td>
			<td>
				تحسين تنفيذ الاستعلامات وفهرسة أسرع وتحسين أداء مع مجموعات البيانات الكبيرة
			</td>
			<td>
				تحسينات مستمرة في الأداء والتركيز على السرعة
			</td>
		</tr>
		<tr>
			<td>
				اتصالات أكبر وأسرع
			</td>
			<td>
				تدعم المزيد من الاتصالات في وقت واحد وتحسّن الأداء عند الحِمل الكبير
			</td>
			<td>
				تحسين التعامل مع الاتصالات وتحسينات قابلية التوسع
			</td>
		</tr>
		<tr>
			<td>
				تحسين النسخ المتماثل Replication
			</td>
			<td>
				تقنية Galera Cluster للتوافرية العالية والنسخ المتماثل المتزامن ونسخ المجموعات المتماثل
			</td>
			<td>
				النسخ المتماثل غير المتزامن والنسخ المتماثل شبه المتزامن ونسخ المجموعات المتماثل
			</td>
		</tr>
		<tr>
			<td>
				الميزات أو الإضافات الجديدة
			</td>
			<td>
				ميزات وإضافات JSON وأنواع البيانات المكانية Spatial ودوال النافذة و MariaDB Serverless و MariaDB MaxScale
			</td>
			<td>
				ميزات وإضافات JSON وأنواع البيانات المكانية ودوال النافذة و MySQL Shell
			</td>
		</tr>
		<tr>
			<td>
				نموذج قاعدة البيانات الثانوية
			</td>
			<td>
				MariaDB Column Store لأحمال العمل التحليلي
			</td>
			<td>
				MySQL Enterprise Backup للاستعادة في الحالات الكارثية وتخزين البيانات
			</td>
		</tr>
		<tr>
			<td>
				تقنيع البيانات Data Masking
			</td>
			<td>
				إمكانات تقنيع البيانات المُضمَّنة لأمن البيانات والالتزام بها
			</td>
			<td>
				ميزات تقنيع البيانات المتاحة باستخدام إضافات خارجية
			</td>
		</tr>
		<tr>
			<td>
				الأعمدة الديناميكية
			</td>
			<td>
				MariaDB Column Store للتخزين العمودي الديناميكي
			</td>
			<td>
				دعم محدود للأعمدة الديناميكية
			</td>
		</tr>
		<tr>
			<td>
				المراقبة Monitoring
			</td>
			<td>
				أدوات مراقبة متقدمة مدمجة بما في ذلك مخطط الأداء Performance Schema وإضافات المراقبة
			</td>
			<td>
				ميزات المراقبة الأساسية مع الأدوات الإضافية المتوفرة في Enterprise Edition
			</td>
		</tr>
		<tr>
			<td>
				التوجيه Routing
			</td>
			<td>
				إمكانات التوجيه المُضمَّنة مع MaxScale لتحسين معالجة الاستعلامات
			</td>
			<td>
				إمكانات التوجيه المحدودة باستخدام أدوات خارجية أولًا
			</td>
		</tr>
		<tr>
			<td>
				التحليلات Analytics
			</td>
			<td>
				ميزات تحليلية متقدمة مع دعم للاستعلامات وأنواع البيانات المعقدة
			</td>
			<td>
				دعم التحليلات الأساسية مع ميزات أكثر تقدمًا في MySQL Enterprise Edition
			</td>
		</tr>
		<tr>
			<td>
				نجوم GitHub
			</td>
			<td>
				أكثر من 11000 نجمة
			</td>
			<td>
				أكثر من 17000 نجمة
			</td>
		</tr>
		<tr>
			<td>
				عمليات نسخ GitHub
			</td>
			<td>
				أكثر من 2500 عملية نسخ
			</td>
			<td>
				أكثر من 3000 عملية نسخ
			</td>
		</tr>
	</tbody>
</table>

<h3 id="-1">
	المقارنة بين معايير قياس الأداء
</h3>

<p>
	قد نجد صعوبةً في توفير معايير قياس أداء نهائية تنطبق على جميع السيناريوهات، ولكن أظهرت دراسات مختلفة وتجارب واقعية أن كلًا من MariaDB و MySQL يمكنهما تقديم أداء ممتاز في مجموعة متنوعة من حالات الاستخدام.
</p>

<p>
	يوضح الرسم البياني التالي عدد العمليات التي يمكن إجراؤها في الثانية OPS لأربعة إصدارات مختلفة من قواعد البيانات (MariaDB 10.0.21 و MariaDB 10.0.18 و MySQL 5.6.27 و MySQL 5.7.9) عند إجراء عمليات قراءة بسيطة مع أعداد مختلفة من المستخدمين من 1 إلى 256. يُظهِر الرسم البياني التالي أن الإصدار MySQL 5.7.9 أفضل من الإصدارات الأخرى دائمًا، مما يعني أن الإصدارات الأحدث أفضل.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="172729" href="https://academy.hsoub.com/uploads/monthly_2025_05/1003721004mariadboltp.png.50d2fde7be94543dc6948c60a7e88890.png" rel=""><img alt="1003721004mariadboltp.png" class="ipsImage ipsImage_thumbnailed" data-fileid="172729" data-ratio="44.00" data-unique="mxm4axh5m" style="width: 700px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2025_05/1003721004mariadboltp.thumb.png.779c298399eaf5f0d8b6d77d26eeb8fe.png"></a>
</p>

<p>
	ترتفع الأرقام مع زيادة عدد المستخدمين، ولكنها تتوقف عن الارتفاع عند حوالي 128 مستخدمًا لمعظم الإصدارات، وهذا يعني أن هناك حدًا لكمية العمليات التي يمكن لقاعدة البيانات التعامل معها بسبب العتاد أو البرمجيات.
</p>

<p>
	تُعَد هذه المقارنة مهمةً لفهم الاختلافات في السرعة وكمية العمل التي يمكن لكل إصدار التعامل معها بين MariaDB وMySQL، مما يساعدنا في اتخاذ خيارات مناسبة لترقية قاعدة بياناتنا وإعدادها الصحيح، ولكن يمكن أن تختلف خصائص الأداء المحددة وفقًا لعوامل مثل العتاد وحِمل العمل والضبط.
</p>

<h3 id="-2">
	التعامل مع أحمال العمل ذات حركة المرور العالية
</h3>

<p>
	يمكن ضبط كل من MariaDB و MySQL وتحسينهما للتعامل مع متطلبات التطبيقات ذات الطلب الكبير عند التعامل مع أحمال العمل ذات حركة المرور العالية، حيث تشمل العوامل الرئيسية التي يجب مراعاتها ما يلي:
</p>

<table>
	<thead>
		<tr>
			<th>
				العامل
			</th>
			<th>
				وصفه
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				العتاد Hardware
			</td>
			<td>
				تُعَد الموارد الكافية لوحدة المعالجة المركزية CPU والذاكرة والتخزين ضروريةً للتعامل مع أحمال العمل ذات الحركة العالية
			</td>
		</tr>
		<tr>
			<td>
				الفهرسة Indexing
			</td>
			<td>
				يمكن أن تحسّن الفهرسة المناسبة كثيرًا من أداء الاستعلامات من خلال تقليل كمية البيانات التي يجب مسحها
			</td>
		</tr>
		<tr>
			<td>
				تحسين الاستعلامات Query Optimization
			</td>
			<td>
				يمكن أن يساعد تحسين استعلامات SQL في تقليل استهلاك الموارد وتحسين أوقات الاستجابة
			</td>
		</tr>
		<tr>
			<td>
				التخبئة Caching
			</td>
			<td>
				يمكن أن يقلّل استخدام آليات التخبئة من عدد استعلامات قاعدة البيانات وتحسين الأداء العام
			</td>
		</tr>
		<tr>
			<td>
				النسخ المتماثل Replication والعنقدة Clustering
			</td>
			<td>
				يمكن أن يساعد تطبيق النسخ المتماثل والعنقدة في توزيع حِمل العمل عبر خوادم متعددة، مما يعزز قابلية التوسع والتوافرية
			</td>
		</tr>
	</tbody>
</table>

<h3 id="-3">
	المقارنة من حيث محركات التخزين
</h3>

<p>
	يؤثر اختيار محرّك التخزين تأثيرًا كبيرًا على أداء قاعدة البيانات ووظائفها، حيث تدعم كل من MariaDB و MySQL محرّكات متعددة، ولكن MariaDB تقدم مجموعةً أوسع من الخيارات، بما في ذلك XtraDB و ColumnStore، مما يوسّع إمكاناتها إلى ما هو أبعد من InnoDB و MyISAM وغيرها من محرّكات MySQL.
</p>

<p>
	تدعم MariaDB أيضًا كلًا من Blackhole و CSV و Aria و InnoDB و Archive و Connect و Cassandra Storage Engine، والعديد من المحرّكات الأخرى؛ بينما تتضمن محركات التخزين التي تدعمها MySQL أيضًا MyISAM و Merge و Federated و Archive و Memory و CSV و Blackhole و Example.
</p>

<p>
	<strong>ملاحظة</strong>: لا يهم عدد محركات التخزين التي تدعمها قاعدة البيانات، فالمهم هو استخدام قاعدة البيانات التي تدعم المحرّك المناسب للمتطلبات.
</p>

<h3 id="-4">
	المقارنة من حيث تحسين الاستعلامات
</h3>

<p>
	تتضمن كل من MariaDB و MySQL ميزات تحسين الاستعلام لتحسين الأداء وتقليل استهلاك الموارد، إذ يمكن أن تساعد هذه الميزات في ضمان تنفيذ الاستعلامات بكفاءة وتجنب الأعباء غير الضرورية.
</p>

<p>
	تتضمن بعض تقنيات تحسين الاستعلامات الشائعة ما يلي:
</p>

<table>
	<thead>
		<tr>
			<th>
				تقنية التحسين
			</th>
			<th>
				وصفها
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				الفهرسة
			</td>
			<td>
				يمكن أن يحسّن إنشاء الفهارس المناسبة كثيرًا من أداء الاستعلامات من خلال تقليل كمية البيانات التي يجب مسحها
			</td>
		</tr>
		<tr>
			<td>
				تخبئة الاستعلامات
			</td>
			<td>
				يمكن أن تقلّل تخبئة الاستعلامات التي يتكرر تنفيذها من الحاجة إلى عمليات بحث متكررة في قاعدة البيانات
			</td>
		</tr>
		<tr>
			<td>
				إعادة كتابة الاستعلام
			</td>
			<td>
				يمكن لقاعدة البيانات في بعض الأحيان إعادة كتابة الاستعلامات لتحسين أدائها أو تجنب الاختناقات المحتملة
			</td>
		</tr>
		<tr>
			<td>
				شرح الخطط
			</td>
			<td>
				يمكن استخدام شرح الخطط لتحليل خطط تنفيذ الاستعلام وتحديد مشكلات الأداء المحتملة
			</td>
		</tr>
	</tbody>
</table>

<h3 id="-5">
	المقارنة من حيث البحث عن نص كامل
</h3>

<p>
	يمكن لكل من MariaDB و MySQL البحث عن كلمات كاملة في النص، ويُعَد ذلك مفيدًا لأشياء مثل محركات البحث وأنظمة إدارة المستندات والمتاجر الإلكترونية.
</p>

<p>
	قد تختلف طريقة البحث عن الكلمات الكاملة التي تستخدمها MariaDB و MySQL بعض الشيء في كيفية عملها ومدى سرعتها، لذا يُفضَّل التحقق من احتياجات تطبيقنا ومقارنة كيفية بحث كلتا قاعدتي البيانات عن الكلمات الكاملة.
</p>

<h3 id="json">
	دعم JSON
</h3>

<p>
	تدعم كل من MariaDB و MySQL تنسيق <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D9%85%D8%A7-%D8%B9%D9%84%D9%8A%D9%83-%D9%85%D8%B9%D8%B1%D9%81%D8%AA%D9%87-%D8%B9%D9%86-%D8%AD%D9%82%D9%88%D9%84-json-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-mysql-r340/" rel="">JSON</a> وتنفذان العديد من الدوال نفسها، ولكن تخزّن MySQL تقارير JSON ككائنات ثنائية، بينما تخزنها MariaDB كسلاسل نصية.
</p>

<p>
	تظهر MySQL و MariaDB اختلافات في إمكاناتهما على التعامل مع JSON بالرغم من ارتباطهما الوثيق، حيث تفتخر MariaDB بمجموعة أوسع من دوال JSON بما في ذلك JSON_QUERY و JSON_EXISTS، والتي تفتقر MySQL إليها؛ ولكن MySQL تقدم الدالة JSON_TABLE لهيكلة بيانات JSON ضمن جدول، والتي هي ميزة غير موجودة في MariaDB.
</p>

<table>
	<thead>
		<tr>
			<th>
				الدالة
			</th>
			<th>
				قاعدة بيانات MariaDB
			</th>
			<th>
				قاعدة بيانات MySQL
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				الدالة JSON_ARRAY
			</td>
			<td>
				✔
			</td>
			<td>
				✔
			</td>
		</tr>
		<tr>
			<td>
				الدالة JSON_EXISTS
			</td>
			<td>
				✔
			</td>
			<td>
				✘
			</td>
		</tr>
		<tr>
			<td>
				الدالة JSON<em>OBJECT</em>AGG
			</td>
			<td>
				✔
			</td>
			<td>
				✔
			</td>
		</tr>
		<tr>
			<td>
				الدالة JSON_QUERY
			</td>
			<td>
				✔
			</td>
			<td>
				✘
			</td>
		</tr>
		<tr>
			<td>
				الدالة JSON_VALUE
			</td>
			<td>
				✔
			</td>
			<td>
				✔
			</td>
		</tr>
		<tr>
			<td>
				الدالة JSON_TABLE
			</td>
			<td>
				✘
			</td>
			<td>
				✔
			</td>
		</tr>
		<tr>
			<td>
				الدالة IS_JSON
			</td>
			<td>
				‫JSON_VALID
			</td>
			<td>
				‫JSON_VALID
			</td>
		</tr>
	</tbody>
</table>

<h3 id="oracle">
	التوافق مع Oracle
</h3>

<p>
	تتمتع MySQL ببعض ميزات أوراكل Oracle الأساسية المتوافقة، ولكن تُعَد MariaDB هي الوحيدة مفتوحة المصدر المتوافقة مع إجراءات وتسلسلات وأنواع البيانات المخزَّنة وغير ذلك لقاعدة بيانات أوراكل.
</p>

<p>
	قد تجد المؤسسات ذات الاستثمار الأكبر في نظام أوراكل البيئي أن قاعدة بيانات MySQL بديل جذاب بسبب وضع التوافق مع أوراكل، ولكن يُعَد دعم MySQL للغة PL/SQL الخاصة بأوراكل محدودًا. تُعَد قاعدة بيانات MariaDB خيارًا أفضل، إذ يمكنها العمل مع صيغة أوراكل ولديها دعم كامل للغة PL/SQL، ويكون ذلك مناسبًا للشركات التي تريد التحول من أوراكل مع الاحتفاظ بشيفرتها البرمجية القديمة واستخدام ميزات إجرائية متقدمة.
</p>

<h3 id="-6">
	ميزات الأمان
</h3>

<p>
	تحمي كلٌّ من MySQL و MariaDB البيانات من خلال التحقق من هوية المستخدمين واستخدام التشفير، ولكنهما تطبّقان التشفير بطريقة مختلفة، إذ تتيح MySQL إمكانية اختيار كيفية تشفير سجلات الإعادة والتراجع، ولكنها لا تحمي مساحات الجدول المؤقتة أو السجلات الثنائية. وتحتوي MariaDB على مزيدٍ من الخيارات للتشفير بما في ذلك حماية السجلات الثنائية والجداول المؤقتة، مما يجعل البيانات أكثر أمانًا.
</p>

<p>
	تستخدم MySQL و MariaDB أيضًا طرقًا مختلفةً للتحقق من هوية المستخدمين، إذ تحتوي MySQL على <code>validate_password</code> للتأكد من قوة كلمات المرور، وتحتوي MariaDB على مزيد من الخيارات مع إضافات مختلفة للتحقق من صحة البيانات. يُعَد أمان كلمة المرور أفضل في MariaDB باستخدام إضافة الاستيثاق ed25519 في الإصدار 10.4، والتي تُعَد أكثر أمانًا من طريقة SHA-1 القديمة، مما يعني أن MariaDB ملتزمة بأن تكون آمنة جدًا.
</p>

<h4 id="threadpooling">
	تجمع الخيوط Thread Pooling
</h4>

<p>
	تستخدم قواعد البيانات تجمع الخيوط للتعامل مع العديد من الاتصالات في وقت واحد، إذ تستخدم هذه الطريقة الخيوط نفسها للاتصالات الجديدة، مما يوفر من الموارد.
</p>

<p>
	تُعَد قاعدة بيانات MariaDB جيدةً جدًا في استخدام تجمّع الخيوط، إذ يحتوي إصدار المجتمع الخاص بها على تجمّع خيوط قوي يمكنه التعامل مع أكثر من 200000 اتصال في وقت واحد؛ وتحتوي MySQL أيضًا على تجمّع خيوط، ولكنها ليست جيدةً بالمقارنة مع تجمع الخيوط الموجود في MariaDB، وهي متوفرة في إصدار المؤسسة المدفوع.
</p>

<p style="text-align: center;">
	<img alt="1003721005تجمعالخيوط.png" class="ipsImage ipsImage_thumbnailed" data-fileid="172730" data-ratio="82.71" data-unique="kkdbml801" width="700" src="https://academy.hsoub.com/uploads/monthly_2025_05/1003721005.png.907496ed1bc3b9e6d3d8059080674a2e.png">
</p>

<h4 id="-7">
	التراخيص والقيود
</h4>

<p>
	تستخدم كل من MariaDB و MySQL ترخيص جنو العمومي General Public License -أو GPL اختصارًا، لكنهما يتبعان خطط ترخيص مختلفة. تُعَد MariaDB مرخصةً بالكامل بموجب ترخيص GPL، مما يعني أنها ستكون مجانيةً ومفتوحة المصدر دائمًا، ويُعَد ذلك مهمًا للمستخدمين الذين يقدّرون أهمية مجانية البرمجيات.
</p>

<p>
	تُعَد MySQL مُرخصَّة بترخيص مزدوج، فهي تحتوي على إصدار ترخيص GPL عام وإصدار تجاري خاص؛ إذ يحتوي الإصدار التجاري على مزيد من الميزات والدعم مثل تجمّع الخيوط، كما قد يؤدي ذلك إلى جعلها أسرع، ولكنه يمنع المستخدمين من تغيير الشيفرة البرمجية.
</p>

<p>
	قد تختار الشركات استخدام MySQL بسبب دعمها التجاري، ولكنها قد تحدّ من الوصول إلى الشيفرة البرمجية الأساسية نظرًا لاستراتيجيتها المزدوجة.
</p>

<h2 id="-8">
	اختيار قاعدة البيانات الصحيحة
</h2>

<p>
	إذا أردنا قاعدة بيانات أنشأها المجتمع وتتمتع بسرعة وأمان أفضل، فقد يكون استخدام قاعدة بيانات MariaDB مناسبًا. فقد أثبتت بعض الاختبارات أن MariaDB أسرع ويمكنها التعامل مع كمية عمليات أكبر من MySQL، كما أن MariaDB تتمتع ببعض ميزات أمان لا تتوفر في MySQL مثل تشفير البيانات أثناء تخزينها ونقلها، إلى جانب تمتع MariaDB بأمور لا تتوفر في MySQL، مثل الأعمدة الافتراضية ومحرّكات التخزين التسلسلية واستخدام محرّكات تخزين متعددة في جدول واحد.
</p>

<p>
	من ناحية أخرى، تم إنشاء قاعدة بيانات MariaDB من طرف المجتمع، لذا تُعَد أكثر انفتاحًا ووضوحًا من MySQL التي تملكها شركة أوراكل، حيث يمكن للمستخدمين المساعدة في جعل البرنامج وتطويره أكثر تركيزًا على احتياجات المجتمع.
</p>

<h2 id="mariadbmysql-2">
	حالات استخدام MariaDB و MySQL
</h2>

<p>
	تكون قاعدة MariaDB غالبًا أفضل للتطبيقات الكبيرة والسريعة والاستعلامات المعقدة، فهي تجعلها ميزاتها الخاصة خيارًا جيدًا للعمل الشاق، مثل ميزة Galera Cluster للحفاظ على تشغيل الأشياء وتحسينات محرّك تخزين InnoDB، بينما تكون MySQL غالبًا أفضل للتطبيقات الأصغر واحتياجات قواعد البيانات الأبسط.
</p>

<table>
	<thead>
		<tr>
			<th>
				شركات تستخدم MariaDB
			</th>
			<th>
				شركات تستخدم MySQL
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				سامسونج Samsung
			</td>
			<td>
				بي بي سي BBC
			</td>
		</tr>
		<tr>
			<td>
				شركة Financial Network, Inc.‎
			</td>
			<td>
				شركة ألعاب Big Fish
			</td>
		</tr>
		<tr>
			<td>
				شركة Virgin Media O2
			</td>
			<td>
				سبوتيفاي Spotify
			</td>
		</tr>
		<tr>
			<td>
				شركة Campus Cloud Services
			</td>
			<td>
				نتفليكس Netflix
			</td>
		</tr>
		<tr>
			<td>
				شركة Auto Europe
			</td>
			<td>
				ناسا NASA
			</td>
		</tr>
		<tr>
			<td>
				نوكيا Nokia
			</td>
			<td>
				 
			</td>
		</tr>
	</tbody>
</table>

<h2 id="mariadbwordpress">
	استخدام MariaDB مع WordPress
</h2>

<p>
	يمكن أن يؤدي استخدام WordPress مع قاعدة بيانات MariaDB إلى تحميل أسرع لموقع الويب، وهذا سيجذب زوّار الموقع أكثر؛ إذ تتميز MariaDB بقدرتها على تحسين الاستعلامات، ويمكنها التعامل مع عدد أكبر من الاتصالات في وقت واحد.
</p>

<p>
	من ناحية أخرى، يمكن لقاعدة بيانات MariaDB التعامل مع عدد أكبر من الاتصالات والمعاملات مقارنةً بقاعدة بيانات MySQL.
</p>

<p>
	كذلك، تتمتع MariaDB بميزات أمان أفضل مثل تشفير البيانات أثناء تخزينها، وطرق محسّنة للتحقق من هوية المستخدمين، وطرق أفضل لتعقّب ما يحدث.
</p>

<h2 id="mariadbcloudways">
	استخدام MariaDB مع موقع Cloudways
</h2>

<p>
	يوفر موقع Cloudways أحدث إصدارات MariaDB على جميع خوادمه التي أطلقها حديثًا، ويمكن تحديد إصدار MariaDB بناءً على متطلبات المشروع.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="172728" href="https://academy.hsoub.com/uploads/monthly_2025_05/006_mariadb_cloudways.png.d8e4d67f6a87eb222dc0d94da7b66278.png" rel=""><img alt="006 mariadb cloudways" class="ipsImage ipsImage_thumbnailed" data-fileid="172728" data-unique="ku420vw2v" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2025_05/006_mariadb_cloudways.thumb.png.cf8af91c94688b46a5be135c63fd76b7.png"> </a>
</p>

<p>
	<strong>ملاحظة</strong>: لا يمكن تخفيض إصدار MariaDB مرةً أخرى بعد الترقية إلى الإصدار الأعلى.
</p>

<h2 id="-9">
	الخلاصة
</h2>

<p>
	بهذا نكون قد وضحنا ميزات MariaDB و MySQL الرئيسية لإظهار الاختلاف بينهما لتسهيل المفاضلة بين قاعدة بيانات MariaDB أو MySQL.
</p>

<p>
	ترجمة -وبتصرّف- للقسم <a href="https://www.cloudways.com/blog/mariadb-vs-mysql/#comparison" rel="external nofollow">MariaDB vs MySQL: Understanding Key Differences and Choosing the Right Database</a> لصاحبته Hafsa Tahir.
</p>

<h2 id="-10">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D9%88%D8%AA%D8%B5%D8%AF%D9%8A%D8%B1-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-mysql-%D8%A3%D9%88-mariadb-r361/" rel="">كيفية استيراد وتصدير قواعد بيانات MySQL أو MariaDB</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%A3%D9%85%D9%8A%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-mysql-mariadb-%D8%B9%D9%84%D9%89-%D8%AE%D9%88%D8%A7%D8%AF%D9%8A%D9%85-%D9%84%D9%8A%D9%86%D9%83%D8%B3-r54/" rel="">كيفية تأمين قواعد البيانات MySQL ,MariaDB على خواديم لينكس</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%BA%D9%8A%D9%8A%D8%B1-%D9%85%D8%AC%D9%84%D8%AF-%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-mariadb-%D8%A5%D9%84%D9%89-%D9%85%D9%83%D8%A7%D9%86%D9%8D-%D8%A2%D8%AE%D8%B1-r349/" rel="">كيفية تغيير مجلد تخزين بيانات MariaDB إلى مكانٍ آخر</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">تعلم أساسيات MySQL</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%B1%D8%A8%D8%B7-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-mariadb-%D8%A8%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%84%D8%A7%D8%B1%D8%A7%D9%81%D9%8A%D9%84-laravel-r2580/" rel="">كيفية ربط قاعدة بيانات MariaDB بتطبيق لارافيل Laravel</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">848</guid><pubDate>Wed, 16 Jul 2025 16:07:01 +0000</pubDate></item><item><title>&#x62A;&#x62C;&#x627;&#x647;&#x644; &#x62D;&#x633;&#x627;&#x633;&#x64A;&#x629; &#x627;&#x644;&#x623;&#x62D;&#x631;&#x641; &#x627;&#x644;&#x639;&#x631;&#x628;&#x64A;&#x629; &#x648;&#x627;&#x644;&#x62A;&#x634;&#x643;&#x64A;&#x644; &#x641;&#x64A; &#x623;&#x646;&#x638;&#x645;&#x629; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;: &#x62D;&#x644; &#x645;&#x634;&#x643;&#x644;&#x629; &#x627;&#x644;&#x623;&#x644;&#x641; &#x628;&#x647;&#x645;&#x632;&#x629; &#x648;&#x628;&#x62F;&#x648;&#x646;&#x647;&#x627; &#x646;&#x645;&#x648;&#x630;&#x62C;&#x64B;&#x627;</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%AA%D8%AC%D8%A7%D9%87%D9%84-%D8%AD%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D8%A7%D9%84%D8%A3%D8%AD%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%AA%D8%B4%D9%83%D9%8A%D9%84-%D9%81%D9%8A-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%AD%D9%84-%D9%85%D8%B4%D9%83%D9%84%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D9%81-%D8%A8%D9%87%D9%85%D8%B2%D8%A9-%D9%88%D8%A8%D8%AF%D9%88%D9%86%D9%87%D8%A7-%D9%86%D9%85%D9%88%D8%B0%D8%AC%D9%8B%D8%A7-r798/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_11/--------------.png.5820116b6edb32d614a626a6c22bc930.png" /></p>
<p>
	عندما تبدأ تعلم قواعد البيانات لأول مرة، ستواجه عدة مشكلات في التعامل مع النصوص العربية، ولأنها خاصةٌ باللغة العربية لن تجد حلولًا سهلة على الإنترنت. نحاول في هذا المقال تلخيص حلول لحل هذه المشكلة الشائعة في قواعد البيانات.
</p>

<p>
	هناك حروف عديدة في اللغة العربية يتعامل معها الناس أحيانًا وكأنها شيء واحد، وتتعامل معها أنظمة قواعد البيانات على أنها حروف مختلفة مثل الألف "ا" والألف ذات الهمزة.
</p>

<p>
	عند إنشاء دالة بحث في موقع الويب فعليك تجاهل هذه الاختلافات، فلن يمكنك حل المشكلة عند استخدام الترميز غير الحساس لحالة الأحرف "utf8_unicode_ci"، ووفقًا لهذا الترميز لا يعد الحرفان "ا" و "أ" <a href="https://collation-charts.org/mysql60/mysql604.utf8_unicode_ci.middle_eastern.html" rel="external nofollow">متساويين في حالة ربط المحارف character mapping</a>، بل سيُعدّان مختلفان، وعند البحث عن أحدها لن يظهر الآخر. هناك ثلاثة حلول لهذه المشكلة:
</p>

<ul>
	<li>
		إنشاء ترميز محارف مخصص custom collation في قاعدة البيانات.
	</li>
	<li>
		إضافة حقل موحّد normalized في جدولك.
	</li>
	<li>
		استخدام <a href="https://academy.hsoub.com/devops/linux/%d9%85%d9%82%d8%af%d9%85%d8%a9-%d9%81%d9%8a-%d8%a7%d9%84%d8%aa%d8%b9%d8%a7%d8%a8%d9%8a%d8%b1-%d8%a7%d9%84%d9%86%d9%85%d8%b7%d9%8a%d8%a9-regular-expressions-r63/" rel="">التعابير النمطية regular expressions</a> في <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D9%87%D9%85-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-queries-%D9%81%D9%8A-mysql-r295/" rel="">الاستعلامات queries</a>.
	</li>
</ul>

<p>
	سنوضح لك كيفية تطبيق هذه الحلول على <a href="https://academy.hsoub.com/devops/servers/databases/mysql/" rel="">MySQL</a>. أما بالنسبة لأنظمة قواعد البيانات الأخرى، فيمكنك البحث في التوثيق عن حلول مشابهة. سيُطبّق كل حل على جدول المثال التالي:
</p>

<pre class="ipsCode">+----+-------------- +
| id | name         |
+----+--------------+
|  1 | احمد         |
|  2 | أحمد         |
|  3 | أسامه        |
|  4 | أسامة        |
|  5 | اسامه        |
|  6 | اسَامه        |
+----+--------------+
6 rows in set
</pre>

<h2 id="">
	إنشاء ترميز محارف مخصص
</h2>

<p>
	هذا هو الحل الموصى به في معظم الحالات، إذ لن تغيّر أي بيانات في قاعدة البيانات، لكن كل ما ستفعله هو إعداد <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">قاعدة البيانات</a> لتتعامل مع هذه الأحرف على أنها حرف واحد.
</p>

<p>
	سنعتمد في هذا على توثيق MySQL بإضافة ترميز UCA إلى مجموعة محارف يونيكود Unicode.
</p>

<p>
	أولًا، سنحتاج إلى تعديل ملف MySQL خاص يحتوي على مجموعات الأحرف وإضافة مجموعتنا الجديدة هناك. اسم الملف هو "Index.xml"، ويختلف موقع الملف من نظام إلى آخر. يمكننا معرفة موقع الملف من قاعدة بيانات "information_schema"؛ وهي هي قاعدة البيانات التي تُخزّن فيها البيانات الوصفية metadata والمعلومات الخاصة بقواعد بيانات MySQL. يمكنك الاطلاع على مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D8%AE%D8%B5%D8%A7%D8%A6%D8%B5-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D8%B2%D8%A7%D9%8A%D8%A7-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D9%82%D8%AF%D9%85%D9%87%D8%A7-r520/" rel="">خصائص قواعد البيانات والمزايا التي تقدمها</a> على أكاديمية حسوب لمزيدٍ من المعلومات حول خصائص قواعد البيانات وبعض المصطلحات الأساسية.
</p>

<p>
	شغّل الاستعلام التالي في قاعدة بيانات "information_schema":
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5410_6" style=""><span class="pln">SHOW VARIABLES LIKE </span><span class="str">'character_sets_dir'</span><span class="pun">;</span></pre>

<p>
	من المفترض أن تحصل النتيجة التالية أو ما يشبهها:
</p>

<pre class="ipsCode">+--------------------+----------------------------+
| Variable_name      | Value                      |
+--------------------+----------------------------+
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------+----------------------------+
1 row in set (0.00 sec)
</pre>

<p>
	يكون مسار الملف على نظام <a href="https://academy.hsoub.com/devops/linux/%D9%81%D9%8A-%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D8%AE%D8%AA%D9%84%D9%81-ubuntu-%D8%B9%D9%86-debian%D8%9F-r235/" rel="">دبيان لينكس Debian Linux</a>، هو "usr/share/mysql/charsets/Index.xml/".
</p>

<p>
	خذ نسخة احتياطية من الملف، وافتحها، وانتقل إلى العنصر <code>&lt;charset name="utf8"</code>‎<code>&gt;</code>، إذ سنضيف ترميزنا المخصص تحتها.
</p>

<p>
	نحن بحاجة إلى رقم معرّف id واسم لترميزنا، إذ يجب أن يكون المعرّف ضمن النطاق المحجوز من الرقم 1024 إلى 2047 لأنه النطاق المحجوز للمستخدم، أما بالنسبة لاسم الترميز فليكن <code>utf8_arabic_ci</code>؛ إذ تدل <code>ci</code> على تجاهل حساسية الأحرف العربية، ويمكنك اختيار ما شئت من الأسماء.
</p>

<p>
	لنُضِفْ الترميز إلى ملف "Index.xml"، ثم نشرح ما تعنيه قواعد الترتيب. ضِف ما يلي:
</p>

<pre class="ipsCode prettyprint lang-xml prettyprinted" id="ips_uid_5410_8" style=""><span class="tag">&lt;collation</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"utf8_arabic_ci"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"1029"</span><span class="tag">&gt;</span><span class="pln">
 </span><span class="tag">&lt;rules&gt;</span><span class="pln">
     </span><span class="tag">&lt;reset&gt;</span><span class="pln">\u0627</span><span class="tag">&lt;/reset&gt;</span><span class="pln">   </span><span class="com">&lt;!-- الألف دون همزة-ا --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u0623</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الألف بالهمزة فوقها-أ --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u0625</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الألف بالهمزة تحتها-إ --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u0622</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الألف بالمدة فوقها -آ --&gt;</span><span class="pln">
 </span><span class="tag">&lt;/rules&gt;</span><span class="pln">
 </span><span class="tag">&lt;rules&gt;</span><span class="pln">
     </span><span class="tag">&lt;reset&gt;</span><span class="pln">\u0629</span><span class="tag">&lt;/reset&gt;</span><span class="pln">   </span><span class="com">&lt;!-- التاء المربوطة-ة --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u0647</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الهاء-ه --&gt;</span><span class="pln">
 </span><span class="tag">&lt;/rules&gt;</span><span class="pln">
 </span><span class="tag">&lt;rules&gt;</span><span class="pln">
     </span><span class="tag">&lt;reset&gt;</span><span class="pln">\u0000</span><span class="tag">&lt;/reset&gt;</span><span class="pln">   </span><span class="com">&lt;!-- قيمة يونيكود المساوية لقيمة فارغة null --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u064E</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الفتحة --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u064F</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الضمّة --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u0650</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الكسرة --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u0651</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!--الشدّة --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u064F</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- السكون --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u064B</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الفتحتان --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u064C</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الضمتان --&gt;</span><span class="pln">
     </span><span class="tag">&lt;i&gt;</span><span class="pln">\u064D</span><span class="tag">&lt;/i&gt;</span><span class="pln">           </span><span class="com">&lt;!-- الكسرتان --&gt;</span><span class="pln">
 </span><span class="tag">&lt;/rules&gt;</span><span class="pln">
</span><span class="tag">&lt;/collation&gt;</span></pre>

<p>
	يُبلّغ هذا الجزء المضاف MySQL أن "utf8<em>arabic</em>ci" -أو أيًا كانت تسميته- هو ابن لمجموعة محارف <a href="https://academy.hsoub.com/programming/php/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D9%85%D8%B2%D8%A9-%D8%A8%D8%AA%D8%B1%D9%85%D9%8A%D8%B2-utf-8-%D9%81%D9%8A-php-r1125/" rel="">utf8</a>، مضيفًا القواعد التالية:
</p>

<ul>
	<li>
		'أ'، و 'إ'، و 'آ' هن نفس حرف 'ا' (جميع أشكال الألف هي حرف واحد).
	</li>
	<li>
		'ه' هو نفس الحرف 'ة'، لذا فإن "نسمة" هي نفس "نسمه".
	</li>
	<li>
		تُتجاهل أحرف التشكيل تمامًا كما لو أنها غير موجودة.
	</li>
</ul>

<p>
	يمكنك إضافة المزيد من القواعد كما تريد.
</p>

<p>
	بعد حفظ الملف، أعد تشغيل خادم MySQL لاستخدام ترتيبنا.
</p>

<p>
	نكتب على نظام Debian ما يلي:
</p>

<pre class="ipsCode">sudo service mysql restart
</pre>

<p>
	انتقل الآن إلى الجدول الذي يحتوي على النص العربي وغيّر ترميز الأعمدة إلى الترميز الجديد. سنفعل ذلك في جدول المثال بهذا الاستعلام:
</p>

<pre class="ipsCode">ALTER TABLE persons
MODIFY name VARCHAR(50)
CHARACTER SET 'utf8'
COLLATE 'utf8_arabic_ci';
</pre>

<p>
	<strong>ملاحظة</strong>: إذا كنت تستخدم <a href="https://academy.hsoub.com/apps/web/wordpress/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-filezilla-%D9%88-phpmyadmin-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%88%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D9%88%D9%82%D8%B9-%D9%88%D9%88%D8%B1%D8%AF%D8%A8%D8%B1%D9%8A%D8%B3-r367/" rel="">PHPMyAdmin</a> أو واجهة رسومية مشابهة للتعامل مع MySQL، فلا تتوقع العثور على الترميز المخصص في القائمة المنسدلة للترميزات المتاحة.
</p>

<p>
	سيتعين عليك كتابة استعلام مثل ما ورد أعلاه لتغيير العمود إلى الترميز الجديد.
</p>

<p>
	إذا نجح الاستعلام، فيجب تعيين كل شيء إلى الترميز الجديد. لنجري استعلام بحث search query ونرn ما إذا كان يعمل كما ينبغي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5410_10" style=""><span class="pln">SELECT </span><span class="pun">*</span><span class="pln"> FROM persons WHERE name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"اسامة"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">+----+--------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> id </span><span class="pun">|</span><span class="pln"> name         </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----+--------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">أسامه</span><span class="pln">        </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">أسامة</span><span class="pln">        </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">اسامه</span><span class="pln">        </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">اسَامه</span><span class="pln">        </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----+--------------+</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> rows </span><span class="kwd">in</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.00</span><span class="pln"> sec</span><span class="pun">)</span></pre>

<p>
	عُرضت أشكال الألف المختلفة (بهمزة أو بغيرها)، وكذلك التاء المربوطة والهاء، لكن مع تجاهل التشكيل (لاحظ أن الاسم الأخير في النتائج <code>اسَامه</code> يحتوي على تشكيل).
</p>

<p>
	كان هذا هو الحل الأول، إذ لم نتطرق إلى البيانات نفسها هنا أو تعديلها، بل أُجريَت جميع التغييرات على نظام قواعد البيانات نفسه، ولكن ماذا لو لم يتح لك الوصول إلى ملفات مجموعات الأحرف، مثلًا عندما تستخدم استضافة مشتركة إذ تكون الصلاحيات مقيدة؟ أو عندما تستخدم قاعدة البيانات <a href="https://academy.hsoub.com/devops/servers/databases/%D9%83%D9%8A%D9%81-%D9%88%D9%85%D8%AA%D9%89-%D9%86%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-sqlite-r111/" rel="">SQLite</a> وليس لديك خيار لإضافة ترتيب جديد؟ هنا يأتي الحل الثاني ليفي بالغرض في هذه الحالات.
</p>

<h2 id="normalized">
	إضافة حقل موحد normalized
</h2>

<p>
	لا يتطلب هذا الحل تحرير ملفات الضبط، وهو مستقل عن نظام قاعدة البيانات؛ إذ يجب أن يعمل حتى لو غيرت نظام قواعد البيانات لأي سبب من الأسباب، ومع ذلك، سيتطلب الأمر إضافة عمود إضافي إلى جدولنا وبعض معالجة البيانات. الفكرة سهلة، أضِف عمودًا جديدًا واملأه بالنص العربي في حقل مُوَحَّد، ثم استخدم العمود المُوَحَّد في استعلاماتك. لنرى كيف نفعل ذلك.
</p>

<p>
	سنستخدم بعض أكواد <a href="https://academy.hsoub.com/programming/php/" rel="">PHP</a> في هذا المثال لإضافة العمود الذي المُوَحَّد إلى جدولنا. يمكنك إجراء دوال مماثلة بأي <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغة برمجة</a> بمجرد أن تفهم الفكرة. استفد من دالة PHP هذه:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_5410_12" style=""><span class="kwd">function</span><span class="pln"> normalize_name</span><span class="pun">(</span><span class="pln">$name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    $patterns     </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">(</span><span class="pln"> </span><span class="str">"/إ|أ|آ/"</span><span class="pln"> </span><span class="pun">,</span><span class="str">"/ة/"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"/َ|ً|ُ|ِ|ٍ|ٌ|ّ/"</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
    $replacements </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">(</span><span class="pln"> </span><span class="str">"ا"</span><span class="pln"> </span><span class="pun">,</span><span class="pln">  </span><span class="str">"ه"</span><span class="pln">      </span><span class="pun">,</span><span class="pln"> </span><span class="str">""</span><span class="pln">         </span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> preg_replace</span><span class="pun">(</span><span class="pln">$patterns</span><span class="pun">,</span><span class="pln"> $replacements</span><span class="pun">,</span><span class="pln"> $name</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ما تفعله هذه الدالة سهل جدًا، فهي تستبدل كل تاء مربوطة <code>ة</code> بهاء <code>ه</code>، وجميع أشكال الألف <code>أإآ</code> بألف بدون همزة <code>ا</code>، وتزيل التشكيل. دعونا نرى ذلك في المثال:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_5410_14" style=""><span class="pln">normalize_name</span><span class="pun">(</span><span class="str">"أحمد"</span><span class="pun">);</span><span class="pln">  </span><span class="com">//‪ تعيد احمد ‪</span><span class="pln">
normalize_name</span><span class="pun">(</span><span class="str">"آمنة"</span><span class="pun">);</span><span class="pln">  </span><span class="com">//‪ تعيد امنه</span><span class="pln">
normalize_name</span><span class="pun">(</span><span class="str">"أسامه"</span><span class="pun">);</span><span class="pln"> </span><span class="com">//‪ تعيد اسامه</span><span class="pln">
normalize_name</span><span class="pun">(</span><span class="str">"مٌحَمَّد"</span><span class="pun">);</span><span class="pln">  </span><span class="com">//‪ تعيد محمد</span></pre>

<p>
	حسنًا، حصلنا الآن على دالة توحيد النصوص. ستكون الخطوة التالية هي إضافة عمود جديد إلى جدولنا وملؤه بالاسم المُوَحَّد. يجب أن تملأ برمجية صغيرة بيانات العمود فلا داعي لذكرها هنا. بعد ذلك، يجب أن يكون لدينا جدول يحتوي على البيانات التالية:
</p>

<pre class="ipsCode">1  احمد   احمد
2  أحمد   احمد
3  أسامه  اسامه
4  أسامة  اسامه
5  اسامه  اسامه
6  اسَامه  اسامه
</pre>

<p>
	العمود الثاني في التخطيط layout السابق هو حقل الاسم المُوَحَّد. حصلنا الآن على بياناتنا الموحّدة، فكيف نستخدمها لحل مشكلتنا؟
</p>

<p>
	إذا بحث المستخدم عن اسم <code>آسامة</code>، فسنمرر هذا الاسم إلى دالة توحيد النص أولًا، والتي ستعيد الاسم المُوَحَّد<code>اسامه</code>، ثم سنستعلم عن عمود <code>normazlized_name</code> الذي أنشأناه، ونعرض عمود الاسم الأصلي في نتائج البحث:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5410_16" style=""><span class="pln">SELECT id</span><span class="pun">,</span><span class="pln"> name FROM persons WHERE normalized_name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"اسامه"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">+----+--------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> id </span><span class="pun">|</span><span class="pln"> name         </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----+--------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">أسامه</span><span class="pln">        </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">أسامة</span><span class="pln">        </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">اسامه</span><span class="pln">        </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">اسَامه</span><span class="pln">        </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----+--------------+</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> rows </span><span class="kwd">in</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.00</span><span class="pln"> sec</span><span class="pun">)</span></pre>

<p>
	هذا كل ما في الأمر، إذ أدى البحث عن <code>آسامة</code> إلى ظهور كافة الاختلافات في الاسم.
</p>

<p>
	باختصار، أضفنا الحقل الذي وحدنا نصّه إلى الجدول، ومرّرنا نص البحث إلى دالة توحيد النص، وبحثنا عن الاسم الذي المُوَحَّد، وعرضنا الاسم الأصلي.
</p>

<p>
	يعد هذا حلًا أكثر معيارية وقابلية للتنفيذ في أكثر من قاعدة بيانات، ولكنه يتطلب مزيدًا من العمل.
</p>

<h2 id="-1">
	استخدام التعابير النمطية في الاستعلامات
</h2>

<p>
	في هذا الحل، لن نغيّر أي ملفات ضبط، ولن نضيف أي بيانات إضافية إلى قاعدة البيانات. ومع ذلك، فإن البحث المعتمد على <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1374/" rel="">التعابير النمطية Regexp</a> أبطأ من البحث العادي، وستفقد ميزة استخدام الفهارس التي قد تؤثر على الأداء تأثيرًا سيئًا. ما تزال دالة التعابير النمطية Regex مفقودة في <a href="https://academy.hsoub.com/programming/sql/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-sql%D8%9F-r1651/" rel="">لغة SQL القياسية</a>، ولكن معظم أنظمة قواعد البيانات توفر الدعم لها بصيغ مختلفة.
</p>

<p>
	لتطبيق هذا الحل، سنستبدل النمط القياسي "regexp" بنص البحث الأصلي.
</p>

<p>
	تُنفّذ التعبيرات العادية في MySQL باستخدام <code>REGEXP</code> أو مرادفها <code>RLIKE</code>. يمكنك الاطلاع على مقال <a href="https://academy.hsoub.com/programming/sql/%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-sql-r854/" rel="">دوال التعامل مع النصوص في SQL</a> لمعرفة المزيد حول كيفية كتابتها.
</p>

<p>
	للبحث عن كافة تواجدات كلمة <code>اسامة</code> سنستخدم النمط التالي:
</p>

<pre class="ipsCode">"[ا|أ|إ|آ]سام[ه|ة]"
</pre>

<p>
	يعني هذا النمط البحث عن أي شكل من أشكال الألف في بداية الكلمة، والبحث عن التاء المربوطة أو الهاء "ه" في نهايتها. لنجرب ذلك على جدول الأمثلة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5410_18" style=""><span class="pln">SELECT id</span><span class="pun">,</span><span class="pln"> name FROM persons WHERE name REGEXP </span><span class="str">"[ا|أ|إ|آ]سام[ه|ة]"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">+----+------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> id </span><span class="pun">|</span><span class="pln"> name       </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----+------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">أسامه</span><span class="pln">      </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">أسامة</span><span class="pln">      </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">اسامه</span><span class="pln">      </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----+------------+</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> rows </span><span class="kwd">in</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.01</span><span class="pln"> sec</span><span class="pun">)</span></pre>

<p>
	عُرضت <code>اسامة</code> أينما وجدت، ما عدا الذي يحتوي على التشكيل كما ذكرنا من قبل.
</p>

<p>
	سيتعين علينا كتابة دالة لإنشاء هذا النمط إذا أردنا استخدام هذه الطريقة في حقول البحث. سأعطيك مثالا لذلك في PHP، ولكن هذا مجرد مثال وعلى الأرجح ستحتاج إلى طريقة مختلفة:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_5410_20" style=""><span class="kwd">function</span><span class="pln"> generate_pattern</span><span class="pun">(</span><span class="pln">$search_string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    $patterns     </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">(</span><span class="pln"> </span><span class="str">"/(ا|إ|أ|آ)/"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"/(ه|ة)/"</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
    $replacements </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">(</span><span class="pln"> </span><span class="str">"[ا|إ|أ|آ]"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"[ه|ة]"</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> preg_replace</span><span class="pun">(</span><span class="pln">$patterns</span><span class="pun">,</span><span class="pln"> $replacements</span><span class="pun">,</span><span class="pln"> $search_string</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستنشئ الدالة أنماطًا على النحو التالي:
</p>

<pre class="ipsCode">generate_pattern("أسامة"); // return '[ا|إ|أ|آ]س[ا|إ|أ|آ]م[ة|ه]'
generate_pattern("أسامه"); // return '[ا|إ|أ|آ]س[ا|إ|أ|آ]م[ة|ه]'
generate_pattern("احمد");  // return '[ا|إ|أ|آ]حمد'
</pre>

<p>
	لاحظ في السطر الأول والثاني أن الدالة حلّت محل الألف في منتصف <code>اسامة</code> أيضًا. ستحتاج إلى حصرها لتستبدل الألف فقط في بداية الكلمة فقط، ولتستبدل التاء المربوطة والهاء في نهاية الكلمة فقط. سنترك الأمر لك لضبط الأنماط.
</p>

<h2 id="-2">
	الخاتمة
</h2>

<p>
	تعرفنا في هذا المقال عن الطرق المتبعة لإنجاز البحث غير الحساس لحالة الأحرف العربية.
</p>

<p>
	اللغة العربية لغة عظيمة وغنية جدًا، وهذا يتطلب معالجة خاصة في التخطيطات والبرمجة وقواعد البيانات، مما يخلق تحديات يتعين علينا التعامل معها نحن المبرمجون العرب.
</p>

<p>
	مشاركة تجاربنا هي المفتاح لإنشاء مجتمع قوي ومفيد. ولإضافة مساهمتنا إلى مجتمع المطورين العالمي. نأمل أن تجد هذه المقالة مفيدة.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://a-essam.medium.com/arabic-case-insensitive-in-database-systems-how-to-solve-alef-with-and-without-hamza-problem-c54ee6d40bed" rel="external nofollow">Arabic Case Insensitive In Database Systems: How To Solve Alef With and Without Hamza Problem</a> لصاحبه أحمد عصام Ahmed Essam.
</p>

<h2 id="-3">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1374/" rel="">التعابير النمطية في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AD%D9%8A%D8%AF-normalization-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r551/" rel="">فهم عملية التوحيد Normalization المستخدمة عند تصميم قاعدة البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">798</guid><pubDate>Fri, 15 Dec 2023 13:02:02 +0000</pubDate></item><item><title>&#x645;&#x627; &#x647;&#x64A; &#x645;&#x62D;&#x631;&#x643;&#x627;&#x62A; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;&#x61F;</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_11/----.png.4411e0368f07d05bfd9a249d3a6133fa.png" /></p>
<p>
	تصادف المهتمين بتعلم قواعد البيانات العديد من المصطلحات التي تسبب ارباكًا للقادمين الجدد سواء كانت غايته تعلم استثمارها أو تصميميها أو برمجة تطبيقات ومواقع ويب ترتبط بها. ومن أكثر هذه المصطلحات إشكالًا هو مصطلح "محركات قواعد البيانات Database Engines" الذي يجري الخلط بينه وبين قواعد البيانات بحد ذاتها وقد يعدّهما الكثيرون الشيء ذاته. سنشرح في هذا المقال ماهية قواعد البيانات ونتعرف على محركات قواعد البيانات ووظائفها ودورها في تزويد المستخدم النهائي بالبيانات المطلوبة.
</p>

<h2 id="">
	ما هي قواعد البيانات
</h2>

<p>
	تُعرّف قاعدة البيانات Database ببساطة على أنها مجموعة من البيانات المخزّنة بشكل منظم يتيح استرجاعها وتعديلها وحذفها. وانطلاقًا من هذا التعريف يمكن أن نفكّر بعدد من النقاط:
</p>

<ul>
	<li>
		تضم قواعد البيانات كمًا كبيرًا من البيانات المعالجة أو البيانات الخام.
	</li>
	<li>
		ترتبط قواعد البيانات بوسائط تخزين، أي أن جميع البيانات موجودة ضمن ملفات أو بنى ومخزّنة رقميًا.
	</li>
	<li>
		توجد طريقة محددة نخبر بها قاعدة البيانات بطبيعة العمل الذي نرغبه بتنفيذه على البيانات.
	</li>
	<li>
		توجد طريقة محددة تفهم فيها قاعدة البيانات ما نطلبه منها.
	</li>
	<li>
		توجد طريقة محددة تنفذ من خلالها قاعدة البيانات التعليمات المطلوبة منها.
	</li>
	<li>
		توجد طريقة محددة لإيصال نتيجة التعليمات إلينا.
	</li>
</ul>

<p>
	بناء على النقاط السابقة، تتكوّن قاعدة البيانات من المكوّنات التالية:
</p>

<ul>
	<li>
		البيانات
	</li>
	<li>
		وحدات التخزين
	</li>
	<li>
		نظام إدارة قواعد البيانات
	</li>
</ul>

<h3 id="-1">
	البيانات
</h3>

<p>
	تُعرّف <a href="https://academy.hsoub.com/programming/general/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1726/" rel="">البيانات</a> بكل بساطة على أنها كل ما يُخزّن لاستراجعه والعمل عليه وتعديله وتحليله للوصول إلى المعلومات المطلوبة.
</p>

<h3 id="-2">
	وحدات التخزين
</h3>

<p>
	وتعد البنية التحتية لقواعد البيانات، إذ تتوضع فيها البيانات بشكل محددٍ ومنظم يُسهّل الوصول إليها. ولهذا المكون بالطبع شقان رئيسيان: أولهما شق برمجي وهي ما يُعرف بالمعمارية Architcture ويحدد طريقة تمثيل البيانات وتخزينها والآخر يتعلق بوسائط تخزين البيانات وهي المكوّن المادي الذي تُخزَّن فيه البيانات وتقرأ وتعدل.
</p>

<p>
	لماذا أشرنا إلى وسائط التخزين كمكوّن من مكونات قاعدة البيانات؟ حتى نوّسع مفهوم قواعد البيانات التقليدي. فلا وجود لقاعدة البيانات دون وسائط تخزين من ناحية أولى، ولأن قواعد البيانات قابلة للتوزيع من ناحية أخرى. فقد تجدها على وسيط تخزين واحد أو على عدة وسائط تخزين في نفس الموقع أو في أصقاع مختلفة من العالم (خوادم قواعد بيانات)، ناهيك عن دور وسائط التخزين في سرعة الوصول إلى قواعد البيانات وقدرتها على تخديم كم كبير من الطلبات.
</p>

<p>
	إذا لنفكرّ دائمًا بوحدات التخزين على أنها تجهيزات التخزين مع معمارية تخزين البيانات عليها.
</p>

<h3 id="-3">
	نظام إدارة قواعد البيانات
</h3>

<p>
	يضم نظام إدارة البيانات Database management system واختصارًا DBMS الأقسام التالية:
</p>

<ul>
	<li>
		برمجيات التحكم والإشراف
	</li>
	<li>
		محركات قواعد البيانات
	</li>
	<li>
		واجهات تخاطب برمجية <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>
	</li>
</ul>

<h4 id="-4">
	برمجيات التحكم والإشراف
</h4>

<p>
	تدير هذه البرمجيات عددًا من الوظائف التي تختلف من قاعدة بيانات إلى أخرى، نذكر منها:
</p>

<ul>
	<li>
		التحكم بمنح أذونات الدخول والعمل.
	</li>
	<li>
		التأكد من صحة وسلامة البيانات.
	</li>
	<li>
		التأكد من خضوع العمليات إلى قواعد محددة.
	</li>
	<li>
		تسهيل استعادة البيانات في حال حدوث خلل.
	</li>
</ul>

<h4 id="-5">
	محركات قواعد البيانات
</h4>

<p>
	وهي برمجيات تدير جميع المهام الوظيفية التي صممت قاعدة البيانات لتنفيذها، وتُعد نواة قواعد البيانات. سنتكلم عنها بالتفصيل لاحقًا.
</p>

<h4 id="api">
	واجهات تخاطب برمجية <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>
</h4>

<p>
	<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">واجهات تخاطب برمجية</a> هي مجموعة من البرمجيات التي تدير التخاطب بين محرّكات قواعد البيانات والعميل وبين محرّكات قواعد البيانات ووسائط التخزين.
</p>

<p>
	إن أردت الاستزادة، فيمكنك الرجوع إلى مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">دليلك الشامل إلى قواعد البيانات</a>.
</p>

<h2 id="-6">
	ماهية محركات قواعد البيانات
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2023_11/----.png.ec6bc92d2d4efd521ba618e8d94d4670.png" data-fileid="138759" data-fileext="png" rel=""><img alt="محركات قواعد البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="138759" data-ratio="62.50" data-unique="7ipbbn3tk" style="width: 600px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_11/----.thumb.png.15cac29102134fedad8e77af87c6d8e3.png"></a>
</p>

<p>
	يُقصد بكلمة "محرك engine" في تكنولوجيا المعلومات عمومًا بأنها وحدة برمجية تضم الشيفرة الأساسية (أو النواة) التي تقود أي تكنولوجيا وظيفيًا، وقواعد البيانات ليست استثناءً. وعادة ما يكون لمصطلح "محرّك" دلالة من ناحية الملكية، إذ يشير هذا المصطلح بأن هذه الوحدة البرمجية مملوكة من قبل شركة معينة تعمل على تطويرها وحمايتها.
</p>

<p>
	ووفقًا لهذا التعريف إضافة إلى مفهوم نظام إدارة قواعد البيانات يمكننا أن نرى سبب وجود الكثير من مزودي قواعد البيانات والكثير من أنظمة قواعد البيانات التي تختلف أو تتشابه بطريقة عملها مثل Oracle DB و MS SQL Server و MySQL و PostgreSQL و Apache Cassandra و Google Bigtable.
</p>

<h3 id="-7">
	الهيكليات التي تبنى عليها محركات قواعد البيانات
</h3>

<p>
	تُبنى قواعد البيانات عادة وفق إحدى هيكليتي (أو خوارزميتي) الفهرسة التاليتين:
</p>

<ul>
	<li>
		هيكلية "شجرة بي B-tree" أو إحدى نسخها: وهي -باختصار شديد- هيكلية مخصصة لتحسين فعالية المحرّك في قراءة البيانات. تعتمد على هذه الهيكلية قواعد بيانات شهيرة مثل Oracle DB و MS SQL Server وIBM DB2 وPostgreSQL و MySQL ذات المحرّك InnoDB.
	</li>
	<li>
		هيكلية "شجرة LSM": وهي هيكلية مصممة لتحسين فعالية المحرّك عندما تكون عمليات كتابة البيانات هي السائدة. تعتمد على هذه الهيكلية قواعد بيانات شهيرة مثل Apache Cassandra و Google Bigtable و LevelDB و RocksDB وقد ظهرت نسخة لقاعدة البيانات MySQL أخرى تعتمد على توزيعة من RocksDB تعرف بالاسم MyRocks بدلًا من المحرك InnoDB.
	</li>
</ul>

<p>
	حاولت بعض قواعد البيانات استخدام كلا الهيكليتين مثل MongoDB من خلال محركها WiredTiger الذي يأتي بإعدادين مختلفين لدعم B-tree و LSM Tree لكن الأمور لم تسر على ما يرام واختارت الشركة توزيع النسخة التي تعتمد على B-tree.
</p>

<h3 id="-8">
	ما هو دور محركات قواعد البيانات؟
</h3>

<p>
	تؤدي محرّكات قواعد البيانات عمومًا معظم وظائف قواعد البيانات وأهمها:
</p>

<ul>
	<li>
		إنشاء وقراءة وتحديث وحذف البيانات من قواعد البيانات واختصارًا CRUD.
	</li>
	<li>
		التخزين المؤقت للبيانات ضمن ذواكر مؤقتة caches أو مخازن مؤقتة buffers.
	</li>
	<li>
		ضمان تحقق ميزات ACID لقاعدة البيانات (الكلّية atomicity، التناسق consistency، العزل isolation، الاستمرارية durability).
	</li>
	<li>
		التأكد من إنجاز العمليات المتزامنة بالشكل المطلوب Multiversion Concurrency Control (القراءة والكتابة إلى العنوان ذاته في نفس الوقت).
	</li>
	<li>
		تنفيذ أية عملية ضرورية قبل العمل على البيانات (تحديد موقع التخزين، تهيئة بنية مناسبة، معالجة ما قبل التخزين،..).
	</li>
</ul>

<h3 id="-9">
	هل محركات قواعد البيانات مستقلة عن قواعد البيانات؟
</h3>

<p>
	قد تتساءل، هل يتمتع محرك قاعدة البيانات باستقلالية عن منظومة إدارة قواعد البيانات؟ ليس بالضرورة في واقع الأمر. لا يمكن التمييز في كثير من الحالات بين محرّك قاعدة البيانات ومنظومة إدارة قواعد البيانات لعدم وجود فصل رسمي من قبل الشركة المطوّرة وخاصة في قواعد البيانات المدفوعة مثل أوراكل Oracle-DB أو Microsoft SQL Server. إن الغاية الأساسية من وجود محرّك قواعد بيانات مستقل أو قائم بذاته هو إمكانية نقله واستخدامه وتعديله ليناسب قاعدة بيانات أخرى، لذلك نجد توجهًا كهذا في قواعد البيانات مفتوحة المصدر مثل MySQL (انظر مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-mysql-%D9%88-mongodb-r627/" rel="">مقارنة بين MySQL و MongoDB</a>).
</p>

<p>
	لهذا السبب لا تميز الكثير من الأدبيات المتعلقة بقواعد البيانات بين منظومة إدارة قواعد البيانات ومحرّكات قواعد البيانات، حتى أن بعضها يعد محركات قواعد البيانات هي نفسها قواعد البيانات.
</p>

<h3 id="-10">
	العلاقة بين محركات قواعد البيانات والواجهات البرمجية
</h3>

<p>
	قلنا أن الواجهة البرمجية هي وسيلة للتخاطب بين المحرّكات وبين المستخدم أو بين المحرّكات ووسائط التخزين. تُستخدم عادة منهجيتين في تخاطب المستخدم مع محركات قواعد البيانات:
</p>

<ul>
	<li>
		استخدام لغة استعلام بنيوية <a href="https://wiki.hsoub.com/SQL" rel="external">SQL</a> وهي لغة خاصة تُستخدم في تعريف وإنشاء الجداول والسجلات والعمل عليها، وهذا النوع هو الأكثر شيوعًا وخاصة في قواعد البيانات المجدولة أو <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">قواعد البيانات العلائقية Relational database</a> مثل أوراكل و PostgreSQL.
	</li>
	<li>
		استخدام أساليب لا تعتمد كليًا على SQL وتعرف بالاختصار <a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-nosql%D8%9F-r640/" rel="">NoSQL</a> وقد ازدادت شعبية هذا النوع من الاستعلامات مع ظهور التخزين البعيد والسحابي والاتجاه نحو تحسين السرعة والتوفر الدائم للبيانات. تعتمد على هذه الواجهات قواعد بيانات عديدة نذكر منها قواعد بيانات الملفات مثل XML و <a href="https://academy.hsoub.com/devops/servers/databases/mongodb/" rel="">MongoDB</a>، وقواعد بيانات (مفتاح- قيمة) مثل MongoDB، وقواعد البيانات الرسومية مثل <a href="https://en.wikipedia.org/wiki/Azure_Cosmos_DB" rel="external nofollow">Azure Cosmos DB</a>.
	</li>
	<li>
		استخدام واجهات مخصصة للغات البرمجة، وهي مفيدة جدًا للمبرمجين الذين يرغبون بربط تطبيقاتهم مع قواعد بيانات محلية أو بعيدة على خوادم خاصة. صممت الكثير من المكتبات لربط البرمجيات المكتوبة ب<a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات برمجة</a> مختلفة مع قواعد بيانات مختلفة نذكر منها Mongoose التي تربط تطبيقات React مع قاعدة البيانات MongoDB و ++SQLAPI لربط تطبيقات مكتوبة بلغة ++C مع قاعدة البيانات SQL Server.
	</li>
</ul>

<p>
	وبالتالي لا علاقة لمحركات قواعد البيانات بلغات الاستعلام أو واجهات البرمجة المستخدمة فالغاية في النهاية هي التخاطب مع هذه المحرّكات لتنفيذ المطلوب.
</p>

<h3 id="-11">
	العلاقة بين محركات قواعد البيانات ونوع قاعدة البيانات
</h3>

<p>
	تُصمم قواعد البيانات لتتعامل بالطريقة الأمثل مع هيكلية تخزين البيانات في قواعد البيانات، نذكر من هذه الهيكليات:
</p>

<ul>
	<li>
		قواعد البيانات العلائقيّة ويُشار إلى منظومتها بالاختصار RDBMS: وتخزن فيها البيانات على شكل جداول مترابطة من صفوف (سجلات) وأعمدة (قيم).
	</li>
	<li>
		قواعد بيانات ملفات Document Database: وتخزّن فيها البيانات ضمن ملفات بأسلوب محدد يسهّل استخلاص البيانات والتعامل معها مثل أسلوب الوسوم tags في ملفات XML.
	</li>
	<li>
		قواعد بيانات قاموسية Dictionary Database: وتخزّن فيها البيانات على شكل مفتاح-قيمة، أي يمكن الوصول إلى أي قيمة بمجرد معرفة مفتاحها والعكس بالعكس.
	</li>
	<li>
		قواعد بيانات كائنية التوجّه Object-oriented Databases: ويجري فيها تخزين البيانات على شكل كائنات مختلفة وتستخدم لتخزين الملفات ومقاطع الصوت والفيديو وهي حديثة العهد نسبيًا.
	</li>
</ul>

<p>
	يفرض أسلوب التخزين المختلف محركات قواعد بيانات مختلفة وبالتالي طريقة عمل مختلفة وواجهات برمجية مختلفة بين محرّك قواعد البيانات من جهة ووسائط التخزين من جهة أخرى. ولا بد من الإشارة إلى وجود قواعد بيانات تدعم أكثر من أسلوب لتخزين البيانات وبالتالي ستكون محرّكاتها مهيأة لهذا الأمر مع وجود تبعات لا مفر منها تتعلق بسرعة الأداء وموثوقيته. لهذا السبب قد تجد عدة إصدارات مخصصة من قاعدة بيانات لدعم الأنواع المختلفة لهيكلية التخزين.
</p>
<iframe allowfullscreen="" data-controller="core.front.core.autosizeiframe" data-embedauthorid="3889" data-embedcontent="" src="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/?do=embed" style="margin: auto;"></iframe>

<h2 id="-12">
	قواعد البيانات الأكثر شعبية وميزات محركاتها
</h2>

<p>
	نورد تاليًا لمحة عن أكثر قواعد البيانات استخدامًا في مختلف المجالات وبعض الميزات الخاصة بمحركاتها:
</p>

<ul>
	<li>
		قاعدة البيانات Oracle-DB
	</li>
	<li>
		قاعدة البيانات MySQL
	</li>
	<li>
		قاعدة البيانات Microsoft SQL Server
	</li>
	<li>
		قاعدة البيانات PostgreSQL
	</li>
	<li>
		قاعدة البيانات MongoDB
	</li>
</ul>

<h3 id="oracledb">
	قاعدة البيانات Oracle-DB
</h3>

<p>
	تُعد هذه القاعدة من أكثر قواعد البيانات شهرة واستخدامًا في شتى المجالات وإليك بعضًا من ميزاتها:
</p>

<ul>
	<li>
		<strong>هيكلية التخزين الأساسية</strong>: علائقية RDBMS.
	</li>
	<li>
		<strong>هيكلية التخزين الثانوية</strong>: قواعد بيانات ملفات وقواعد بيانات رسومية وقواعد علائقية فراغية spatial RDBMS.
	</li>
	<li>
		<strong>مفتوحة المصدر</strong>: لا.
	</li>
	<li>
		<strong>الشركة المصممة</strong>: Oracle.
	</li>
	<li>
		<strong>الأنظمة التي تتعامل معها (بما فيها الخوادم)</strong>: AIX و HP-UX و Linux و OS X و Solaris و Windows.
	</li>
	<li>
		<strong>لغات البرمجة التي تدعمها</strong>: معظم اللغات الشعبية ++C و بايثون و جافا و PHP وغيرها الكثير.
	</li>
	<li>
		<strong>الواجهات البرمجية وغيرها من طرق الوصول</strong>: JDBC و ODBC و ODP.NET و Oracle Call Interface ‏(OCI).
	</li>
	<li>
		<strong>لغات الاستعلام</strong>: PL/SQL
	</li>
</ul>

<p>
	<strong>ميزات المحرّك</strong>:
</p>

<ul>
	<li>
		دعم عمليات CRUD
	</li>
	<li>
		دعم ميزات ACID
	</li>
	<li>
		دعم إقامة البيانات في الذاكرة
	</li>
	<li>
		دعم الحفاظ على البيانات واستعادتها
	</li>
	<li>
		دعم التعديل المتزامن للبيانات
	</li>
	<li>
		الدعم المباشر للتناسق Immediate Consistency
	</li>
</ul>

<h3 id="mysql">
	قاعدة البيانات MySQL
</h3>

<p>
	لا تقل هذه القاعدة شهرة من ناحية الميزات والاستخدامات وعدد المستخدمين عن Oracle وتستخدم في شتى المجالات وإليك بعضًا من ميزاتها:
</p>

<ul>
	<li>
		<strong>هيكلية التخزين الأساسية</strong>: علائقية RDBMS.
	</li>
	<li>
		<strong>هيكلية التخزين الثانوية</strong>: قواعد بيانات ملفات وقواعد علائقية فراغية spatial RDBMS.
	</li>
	<li>
		<strong>مفتوحة المصدر</strong>: نعم.
	</li>
	<li>
		<strong>الشركة المصممة</strong>: Oracle.
	</li>
	<li>
		<strong>الأنظمة التي تتعامل معها (بما فيها الخوادم)</strong>: FreeBSD و Linux و OS X و Solaris و Windows
	</li>
	<li>
		<strong>لغات البرمجة التي تدعمها</strong>: معظم اللغات الشعبية ++C و بايثون و جافا و PHP وغيرها الكثير.
	</li>
	<li>
		<strong>الواجهات البرمجية وغيرها من طرق الوصول</strong>: JDBC و ODBC و Proprietary native <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> و ADO.NET.
	</li>
	<li>
		<strong>لغات الاستعلام</strong>: SQL.
	</li>
</ul>

<p>
	<strong>ميزات المحرّك</strong>:
</p>

<ul>
	<li>
		دعم عمليات CRUD
	</li>
	<li>
		دعم ميزات ACID
	</li>
	<li>
		دعم إقامة البيانات في الذاكرة
	</li>
	<li>
		دعم الحفاظ على البيانات واستعادتها
	</li>
	<li>
		دعم التعديل المتزامن للبيانات
	</li>
	<li>
		الدعم المباشر للتناسق Immediate Consistency
	</li>
</ul>

<h3 id="microsoftsqlserver">
	قاعدة البيانات Microsoft SQL Server
</h3>

<p>
	وهي قاعدة البيانات الشهيرة من مايكروسوفت وتُعد من أكثر قواعد البيانات شعبية وإليك بعضًا من ميزاتها:
</p>

<ul>
	<li>
		<strong>هيكلية التخزين الأساسية</strong>: علائقية RDBMS.
	</li>
	<li>
		<strong>هيكلية التخزين الثانوية</strong>: قواعد بيانات ملفات وقواعد بيانات رسومية و قواعد علائقية فراغية spatial RDBMS.
	</li>
	<li>
		<strong>مفتوحة المصدر</strong>: لا.
	</li>
	<li>
		<strong>الشركة المصممة</strong>: مايكروسوفت.
	</li>
	<li>
		<strong>الأنظمة التي تتعامل معها (بما فيها الخوادم)</strong>: Linux و Windows.
	</li>
	<li>
		<strong>لغات البرمجة التي تدعمها</strong>: معظم اللغات الشعبية ++C و بايثون و جافا و PHP ودعمًا خاصًا للغات (NET.) مثل #C وفيجوال بيسك.
	</li>
	<li>
		<strong>الواجهات البرمجية وغيرها من طرق الوصول</strong>: JDBC و ODBC و ADO.NET و OLE DB و Tabular Data Stream ‏(TDS)
	</li>
	<li>
		<strong>لغات الاستعلام ولغات سكربت الخادم</strong>: لغات NET. و بايثون و R و Transact SQLو جافا (في الإصدار 2019 وما بعد).
	</li>
</ul>

<p>
	<strong>ميزات المحرّك</strong>:
</p>

<ul>
	<li>
		دعم عمليات CRUD
	</li>
	<li>
		دعم ميزات ACID
	</li>
	<li>
		دعم إقامة البيانات في الذاكرة
	</li>
	<li>
		دعم الحفاظ على البيانات واستعادتها
	</li>
	<li>
		دعم التعديل المتزامن للبيانات
	</li>
	<li>
		الدعم المباشر للتناسق Immediate Consistency
	</li>
</ul>

<h3 id="postgresql">
	قاعدة البيانات PostgreSQL
</h3>

<p>
	إليك بعضًا من ميزات هذه القاعدة الشهيرة:
</p>

<ul>
	<li>
		<strong>هيكلية التخزين الأساسية</strong>: علائقية RDBMS.
	</li>
	<li>
		<strong>هيكلية التخزين الثانوية</strong>: قواعد بيانات ملفات وقواعد علائقية فراغية spatial RDBMS.
	</li>
	<li>
		<strong>مفتوحة المصدر</strong>: نعم.
	</li>
	<li>
		<strong>الشركة المصممة</strong>: PostgreSQL Global Development Group .
	</li>
	<li>
		<strong>الأنظمة التي تتعامل معها (بما فيها الخوادم)</strong>: FreeBSD و Linux و OS X و Solaris و Windows و NetBSD و Unix و Hp-UX.
	</li>
	<li>
		<strong>لغات البرمجة التي تدعمها</strong>: معظم اللغات الشعبية ++C و بايثون و جافا و PHP ولغات (NET.).
	</li>
	<li>
		<strong>الواجهات البرمجية وغيرها من طرق الوصول</strong>: native C library و streaming <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> for large objects و JDBC و ODBC ADO.NET.
	</li>
	<li>
		<strong>لغات الاستعلام</strong>: SQL.
	</li>
</ul>

<p>
	<strong>ميزات المحرّك</strong>:
</p>

<ul>
	<li>
		دعم عمليات CRUD
	</li>
	<li>
		دعم ميزات ACID
	</li>
	<li>
		دعم الحفاظ على البيانات واستعادتها
	</li>
	<li>
		دعم التعديل المتزامن للبيانات
	</li>
	<li>
		الدعم المباشر للتناسق Immediate Consistency
	</li>
</ul>

<h3 id="mongodb">
	قاعدة البيانات MongoDB
</h3>

<p>
	إليك بعضًا من ميزات هذه القاعدة الشهيرة:
</p>

<ul>
	<li>
		<strong>هيكلية التخزين الأساسية</strong>: قواعد بيانات ملفات.
	</li>
	<li>
		<strong>هيكلية التخزين الثانوية</strong>: قواعد علائقية فراغية spatial RDBMS وقواعد علائقية مرتبطة بالسلاسل الزمنية Time Serieses RDBMS.
	</li>
	<li>
		<strong>مفتوحة المصدر</strong>: نعم.
	</li>
	<li>
		<strong>الشركة المصممة</strong>: MongoDB, Inc.
	</li>
	<li>
		<strong>الأنظمة التي تتعامل معها (بما فيها الخوادم)</strong>: Linux و OS X و Solaris و Windows
	</li>
	<li>
		<strong>لغات البرمجة التي تدعمها</strong>: معظم اللغات الشعبية.
	</li>
	<li>
		<strong>الواجهات البرمجية وغيرها من طرق الوصول</strong>: بروتوكول خاص باستخدام JSON
	</li>
	<li>
		<strong>لغات الاستعلام</strong>: Read-only SQL وجافاسكربت.
	</li>
</ul>

<p>
	<strong>ميزات المحرّك</strong>:
</p>

<ul>
	<li>
		دعم عمليات CRUD
	</li>
	<li>
		دعم محدود لميزات ACID
	</li>
	<li>
		دعم إقامة البيانات في الذاكرة
	</li>
	<li>
		دعم الحفاظ على البيانات واستعادتها
	</li>
	<li>
		دعم التعديل المتزامن للبيانات
	</li>
	<li>
		الدعم المباشر للتناسق Immediate Consistency والتنسيق العرضي Eventual Consistency
	</li>
</ul>

<h2 id="-13">
	خاتمة
</h2>

<p>
	حاولنا في هذا المقال التمييز ما بين محركات قواعد البيانات وقواعد البيانات من الناحية الوظيفية ورأينا أن المحركات هي الشيفرة البنيوية التي تمكّن قاعدة البيانات من تنفيذ عملياتها، ولهذا الأمر أهميته الخاصة لأن محاولات بناء وتطوير قواعد بيانات جديدة مفتوحة المصدر بالاستفادة من شيفرات محركات قواعد بيانات أخرى قد بدأت بالنضوج وبالتالي لا بد من توضيح هذا المفهوم لاختيار قاعدة البيانات الأنسب للتطبيقات حاليًا ومستقبلًا.
</p>

<h2 id="-14">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تعرف على مكونات قاعدة البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">أنواع قواعد البيانات وأهم مميزاتها واستخداماتها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">مدخل إلى تصميم قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">797</guid><pubDate>Mon, 13 Nov 2023 13:00:00 +0000</pubDate></item><item><title>&#x645;&#x642;&#x627;&#x631;&#x646;&#x629; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; MySQL &#x648; MongoDB</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-mysql-%D9%88-mongodb-r808/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_04/-MySQL--MongoDB(1).png.5f2bdea9f7d3c8d7f9dc37525a6f00b9.png" /></p>
<p>
	يعرض الفيديو مقارنة بين قواعد بيانات MySQL و MongoDB، وهما أحد أشهر محركات قواعد البيانات حاليًا، تصنف MySQL على أنها من قواعد البيانات العلائقية relational database، بينما تصنف MongoDB على أنها NoSQL تعتمد على مفهوم المستندات document-oriented database.
</p>

<p>
	نوضح لك في الفيديو مفهوم قاعدة البيانات وأنواعها ومفهوم كل من MySQL و MongoDB، لنواصل بعدها عرض مقارنة شاملة بينهما توضح مدى الاختلاف الموجود بينهما، وصولًا إلى توضيح متى يجب أن تستخدم MySQL ومتى يكون من الأفضل استخدام MongoDB.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="639" id="ips_uid_7365_5" referrerpolicy="strict-origin-when-cross-origin" src="https://academy.hsoub.com/applications/core/interface/index.html" title="مقارنة قواعد البيانات MySQL و MongoDB" width="800" data-embed-src="https://www.youtube.com/embed/UL-gPrgoRFo"></iframe>
</p>

<p>
	إذا كنت مهتمًا بتعلم المزيد حول قواعد بيانات MySQL و MongoDB فتابع <a href="https://academy.hsoub.com/devops/servers/databases/" rel="">قسم قواعد البيانات</a> ليصلك كل مقال جديد من أكاديمية حسوب بهذا الشأن، وإن أردت تعلم قواعد البيانات وكيفية التعامل معها باحترافية، فلا تنس الاشتراك <a href="https://academy.hsoub.com/learn/computer-science/" rel="">بدورة علوم الحاسوب</a> المقدمة من أكاديمية حسوب.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-mysql-%D9%88-mongodb-r627/" rel="">مقارنة بين MySQL و MongoDB</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">دليلك الشامل إلى قواعد البيانات DataBase</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">808</guid><pubDate>Thu, 05 Oct 2023 15:00:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x623;&#x647;&#x645;&#x64A;&#x629; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%87%D9%85%D9%8A%D8%A9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_06/---.png.09058012a9474c742ba64bfb74e082be.png" /></p>
<p>
	تبرز أهمية قواعد البيانات في عالم الأعمال اليوم أكثر من أي وقت مضى، حيث يعد استخدام قواعد البيانات أمرًا ضروريًا في معظم القطاعات التي تتطلب تخزين كم هائل من المعلومات المختلفة مثل البنوك والدوائر الحكومية المدنية مثل مكاتب السجل المدني والجامعات ومراكز التسوق والمتاجر الرقمية كي تتمكن من أداء خدماتها على أكمل وجه.
</p>

<p>
	سنطلعك في مقال اليوم على أهمية قواعد البيانات ومميزاتها ودورها الفعال في تنظيم وجمع كل بياناتك في مكان واحد وتسهيل البحث عن أي بيانات تحتاجها بسرعة وسهولة، أو حتى تحليلها واستنتاج معلومات قيمة لتحسين عملك منها وغيرها الكثير من الفوائد.
</p>

<h2>
	ما هي قاعدة البيانات؟
</h2>

<p>
	قبل أن نتحدث عن أهمية قواعد البيانات دعنا نفهم أولاً ما هي قاعدة البيانات بالأساس وما هي أنواعها ومكوناتها؟
</p>

<p>
	<a href="https://academy.hsoub.com/devops/servers/databases/" rel="">قاعدة البيانات Database</a> أو ما يعرف اختصارًا DB هي مجموعة من البيانات المخزنة إلكترونيًا والمنظمة في تنسيق معين يسهل البحث فيها ومعالجتها.
</p>

<p>
	يمكن أن تصمم قواعد البيانات وفق عدة نماذج تختلف في طريقة تخزين البيانات، أشهرها هو تنظيمها على شكل مجموعة جداول مرتبطة ببعضها، على سبيل المثال لدينا هنا مثال بسيط على نموذج لقاعدة بيانات تخزن معلومات عن الطلاب والدورات التي يتبعونها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="128218" href="https://academy.hsoub.com/uploads/monthly_2023_06/214386662_.png.af2eff2fd2260a714aeb6beb4dd54712.png" rel=""><img alt="مثال على قاعدة بيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="128218" data-ratio="56.33" data-unique="kbaxayip9" style="width: 900px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_06/.thumb.png.3937022b6ebb2d1cc377fa3c6f29ddbf.png"></a>
</p>

<p>
	لاحظ أنك تستطيع البحث عن عدة معلومات من قاعدة البيانات أعلاه، كما يمكنك العثور على إجابات حول عدة أسئلة منها العدد الكلي للطلاب المسجلين، وعدد الطلاب المنتسبين إلى دورة معينة، ومعرفة الدورة الأكثر شعبية …إلخ.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة علوم الحاسوب
		</p>

		<p class="banner-subtitle">
			دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/computer-science/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<img alt="دورة علوم الحاسوب" src="https://academy.hsoub.com/learn/assets/images/courses/computer-science.png">
	</div>
</div>

<h2>
	أهمية قواعد البيانات
</h2>

<p>
	إذا كنت تتساءل عن أهمية قواعد البيانات، ولماذا يتوجب عليك استخدام قواعد البيانات في المشاريع والأعمال؟ فإليك قائمة بأبرز فوائد استخدام قواعد البيانات:
</p>

<ul>
	<li>
		تخزين قدر كبير من البيانات
	</li>
	<li>
		تخزين البيانات بطريقة منظمة
	</li>
	<li>
		تسهيل البحث عن البيانات ومعالجتها
	</li>
	<li>
		تمكين النسخ الاحتياطي البيانات
	</li>
	<li>
		توفير إمكانية تحليل البيانات واستخراج المعلومات المفيدة منها
	</li>
	<li>
		تطوير البرامج والتطبيقات التفاعلية
	</li>
</ul>

<p>
	دعنا نناقش كل فائدة من بينها بمزيد من التفصيل.
</p>

<h3>
	تخزين قدر كبير من البيانات
</h3>

<p>
	يزداد الاعتماد على جمع البيانات بشكل كبير في الآونة الأخيرة ولك أن تتخيل كمية البيانات المتراكمة التي تجمعها الأعمال يوميًا والتي تعد أحد أصولها المهمة والقيمة التي عليها الحفاظ عليها وتخزينها بأفضل طريقة. وتعد قاعدة البيانات الوسيلة المناسبة لتخزين هذه البيانات بحيث يمكن العثور على المعلومات المطلوبة بسرع.
</p>

<h3>
	تخزين بيانات سليمة ومنظمة
</h3>

<p>
	تمكن قاعدة البيانات من تنظيم البيانات المخزنة بطريقة تساعدك على الاستفادة منها وإدارتها بأفضل طريقة. وهناك عدة طرق لتنظيم أو نمذجة البيانات في قاعدة البيانات وأشهرها النموذج العلائقي الذي يخزن البيانات ضمن جداول مرتبطة ببعضها البعض وتسمى قاعدة البيانات التي تتبع هذا النموذج قاعدة البيانات العلائقية.
</p>

<p>
	أضف إلى ذلك أن قواعد البيانات تفرض على المدخلات أن تكون سليمة وبشروط محددة مسبقًا، مثل أن يكون الاسم بعدد حروف لا تقل عن 4 أو أن يكون رقم الهاتف المدخل بعدد أرقام 7 بالضبط أو البريد الإلكتروني صالح وهكذا، وللمزيد حول هذه النقطة انظر مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D9%88%D9%82%D9%8A%D9%88%D8%AF%D9%87%D8%A7-%D9%84%D8%B6%D9%85%D8%A7%D9%86-%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r544/" rel="">قواعد السلامة وقيودها لضمان سلامة البيانات في قواعد البيانات</a>
</p>

<h3>
	تسهيل البحث عن البيانات ومعالجتها
</h3>

<p>
	إن تخزين البيانات بطريقة منظمة ضمن قاعدة البيانات يسهل عملية البحث عن البيانات التي تحتاجها من البيانات المحفوظة واستعادتها وتعديلها عند الحاجة، كما يمكنك من إضافة شروط وفلاتر للعثور على البيانات التي تحقق شروطًا معينة.
</p>

<p>
	ويمكن بالطبع تخزين البيانات في أي وسيط رقمي مثل الحاسوب عبر نظام الملفات وناقشنا ذلك مع مقارنة مع قاعدة البيانات في مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%88%D8%A7%D8%AE%D8%AA%D9%84%D8%A7%D9%81%D9%87-%D8%B9%D9%86-%D9%86%D8%B8%D8%A7%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r509/" rel="">تحليل نظام الملفات لإدارة البيانات وتخزينها واختلافه عن نظام قاعدة البيانات</a> فارجع إليه للمزيد.
</p>

<h3>
	الحفاظ على تناسق البيانات
</h3>

<p>
	عادة ما تُمنح صلاحية الوصول لقاعدة البيانات وتحرير بياناتها لعدة أشخاص فإذا قام أكثر من شخص بتحرير نفس البيانات على التزامن وفي ذات اللحظة قد تحدث أخطاء في صحة وتناسق البيانات وهنا تبرز أهمية استخدام قواعد البيانات التي تحتوي على تحكم في التزامن يمنع المستخدمين الآخرين من تعديل أي بيانات أثناء قيام أحد المستخدمين بتعديلها وهذا يحافظ على بياناتك متسقة وصحيحة.
</p>

<h3>
	تمكين النسخ الاحتياطي للبيانات
</h3>

<p>
	تبرز أهمية قواعد البيانات في توفير ميزة النسخ الاحتياطي للبيانات مما يحافظ على البيانات الهامة ويمكننا من استردادها في حال حذفها أو تخريبها نتيجة أي عطل أو خطأ مقصود أو غير مقصود.
</p>

<h3>
	توفير إمكانية تحليل البيانات واستخراج المعلومات المفيدة منها
</h3>

<p>
	لم تعد الشركات اليوم تهتم فقط بتخزين البيانات في قواعد البيانات للبحث فيها ومعالجتها، بل أصبحت تهتم بأكثر من ذلك وهو فهم البيانات المخزنة لديها، فالبيانات اليوم تعد بمثابة النفط الجديد في عالم الأعمال ويمكن من خلال جمعها وتنظيفها وحفظها في قواعد بيانات مخصصة وتحليلها استخراج معلومات قيمة تساعد الشركات على اتخاذ قرارات مفيدة لتطوير أعمالها وتحسين إنتاجيتها.
</p>

<h3>
	تطوير البرامج والتطبيقات التفاعلية
</h3>

<p>
	تعد قواعد البيانات أحد العناصر الضرورية أيضًا في عملية تطوير التطبيقات والمواقع التفاعلية للشركات، ففيها يتم تخزين جميع البيانات المتعلقة بالتطبيق ويتم تطوير واجهات مخصصة للتعامل معها من خلال التطبيق، فإذا كنت مهتمًًا بتطوير التطبيقات سيكون عليك الاهتمام بقواعد البيانات كجزء من عملية التطوير.
</p>

<h2>
	ما هو نظام إدارة قواعد البيانات DBMS وما أهميته؟
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="128217" href="https://academy.hsoub.com/uploads/monthly_2023_06/---.png.05d125177c1edb1a28b48e5b6fd574f8.png" rel=""><img alt="أهمية قواعد البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="128217" data-ratio="62.50" data-unique="d33tpirgy" style="width: 600px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_06/---.thumb.png.5f35dcba35a9bcba68fe0afb075f81cb.png"></a>
</p>

<p>
	لا يسمح للمستخدمين الوصول مباشرة إلى بيانات قاعدة البيانات والتعامل معها بل يتم التعامل مع البيانات المخزنة في قاعدة البيانات عادة من خلال نظام وسيط يسمى <strong>نظام إدارة قواعد البيانات</strong> <strong>D</strong>ata<strong>b</strong>ase <strong>M</strong>anagement <strong>S</strong>ystem أو اختصارًا <strong>DBMS</strong>.
</p>

<p>
	يعد نظام إدارة قاعدة البيانات بمثابة برج التحكم في قاعدة البيانات فمن خلاله يمكن للمستخدمين التعامل مع بيانات قاعدة البيانات وإدارتها بكفاءة، وفي حال تم ارتكاب أي خطأ مثل تخزين بيانات غير صحيحة فسيقوم نظام إدارة قاعدة البيانات بمعنك من ذلك للحفاظ على تناسق البيانات وصحتها.
</p>

<p>
	كما يساهم نظام إدارة قواعد البيانات في الحفاظ على أمن البيانات ويتولى مهمة تشفير البيانات وإدارة المستخدمين الذين يمكنهم التعامل مع البيانات ومنع أي محاولات للوصول غير المصرح به للبيانات ويوفر آليات من أجل <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D9%8A%D8%A7%D8%B7%D9%8A-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r477/" rel="">النسخ الاحتياطي</a> واستعادة البيانات في حالة حدوث أي عطل طارئ فيها.
</p>

<p>
	تتوافر العديد من أنظمة إدارة قواعد البيانات منها أنظمة تجارية توفرها الشركات بمقابل مادي مثل أوراكل Oracle و Microsoft SQL Server و IBM DB2، وأخرى مجانية ومفتوحة المصدر طورتها مجتمعات المطورين المتطوعين مثل MySQL و PostgreSQL.
</p>

<p>
	إذَا قواعد البيانات لا تعمل لوحدها وإنما تعمل ضمن منظومة متكاملة يوفرها نظام إدارة قواعد البيانات ويمكن أن نخلص أهمية نظام إدارة قواعد البيانات بالنقاط التالية:
</p>

<ul>
	<li>
		توفير الوظائف الأساسية للتعامل مع البيانات مثل تخزين البيانات وتحديثها وحذفها
	</li>
	<li>
		توفير آليات لفرز البيانات والبحث فيها بسهولة وسرعة.
	</li>
	<li>
		التحقق من القيود المفروضة على البيانات المراد تخزينها في قاعدة البيانات ومنع أي أخطاء في عملية إدخال البيانات.
	</li>
	<li>
		حماية البيانات من الوصول غير المصرح به.
	</li>
	<li>
		تشفير البيانات المخزنة لحمايتها من الاختراق.
	</li>
	<li>
		منع أكثر من مستخدم من تحرير نفس البيانات في نفس الوقت للحفاظ على اتساقها وتجنب حدوث أي تضارب.
	</li>
	<li>
		توفير آلية لاستعادة البيانات في حال حدوث أي فشل أو تلف فيها.
	</li>
</ul>

<h2>
	أهمية الأنواع المختلفة لقواعد البيانات
</h2>

<p>
	كنا قد تحدثنا في مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">دليلك الشامل إلى قواعد البيانات DataBase</a> عن الأنواع المختلفة لقواعد البيانات والتي تعتمد نماذج مختلفة لتخزين البيانات وتنظيمها ضمن قاعدة البيانات وفي هذه الفقرة سنسلط الضوء على اثنين من أهم أنواع قواعد البيانات ونوضح أهميتهما ومجال استخدامها في مجال التطوير.
</p>

<h3>
	أهمية قواعد البيانات العلائقية Relational databases
</h3>

<p>
	تنظم العناصر الموجودة في قاعدة البيانات العلائقية بشكل مجموعة من الجداول المرتبطة بحيث يخزن كل جدول مجموعة البيانات ذات الصلة ببعضها ويتم ربط المعلومات من جداول متعددة من خلال تضمين معرف فريد يسمى المفتاح الأساسي في الجدول الرئيسي وإضافته إلى أي جدول آخر نريد ربطه مع هذا الجدول وحينها يسمى مفتاح خارجي وبهذا ينشئ الربط بين المفتاح الأساسي والمفتاح الخارجي علاقة بين الجدولين.
</p>

<p>
	[قاعدة بيانات علائقية.PNG]
</p>

<p>
	تبرز أهمية قواعد البيانات العلائقية عند الحاجة لبناء أنظمة برمجية تتطلب صرامة وتنظيم في تنسيق البيانات مثل الأنظمة المحاسبية وأنظمة إدارة المخزون وأنظمة المبيعات حيث تخزن البيانات بشكل جداول بهيكلية محددة.
</p>

<p>
	على سبيل المثال يمكن أن تتضمن قاعدة بيانات شركة مبيعات مجموعة جداول مثل جدول المنتجات وجدول الموظفين وجدول المبيعات …إلخ وترتبط البيانات الموجودة في هذه الجداول ببعضها البعض.
</p>

<p>
	وكما تلاحظ في المثال أعلاه تنظم قواعد البيانات العلائقية المعلومات بطريقة فعالة ومتكاملة وتمنع تكرار البيانات وتسهل لك التعامل مع هذه البيانات ومعالجتها والبحث فيها، لكن القصور في هذا النوع هو بطء سرعة المعالجة نظرًا لضرورة الحفاظ على تكامل البيانات وصعوبة التعامل مع البيانات الضخمة.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="315" id="ips_uid_1639_6" src="https://academy.hsoub.com/applications/core/interface/index.html" title="YouTube video player" width="560" data-embed-src="https://www.youtube.com/embed/Idq1QrXEfQk"></iframe>
</p>

<h3>
	أهمية قواعد البيانات غير العلائقية NoSQL Databases
</h3>

<p>
	توفر قواعد البيانات غير العلائقية أو ما يعرف <a href="https://academy.hsoub.com/devops/servers/databases/%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D9%81%D8%B1%D9%88%D9%82%D8%A7%D8%AA-%D8%A8%D9%8A%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-sql-%D9%88%D9%86%D8%B8%D9%8A%D8%B1%D8%A7%D8%AA%D9%87%D8%A7-nosql-r71/" rel="">بقواعد بيانات NoSQL</a> طريقة مناسبة لتخزين البيانات غير المنظمة التي يصعب تخزينها في جداول منظمة مثل بيانات تطبيقات الويب وتطبيقات التعرف على الصور والتعرف على الصوت باستخدام الذكاء الاصطناعي وتطبيقات إنترنت الأشياء والأنظمة التي تستخدم البيانات الضخمة أو تتطلب معالجة كميات كبيرة من البيانات.
</p>

<p>
	تخزن قواعد البيانات غير العلائقية البيانات وفق 4 نماذج وهي قاعدة بيانات قيمة مفتاح Key-value ومخزن العمود الموسع Wide-column Store وقاعدة بيانات المستند Document وقاعدة بيانات الرسم البياني Graph.
</p>

<p>
	وتبرز أهمية قواعد البيانات غير العلائقية في كونها سريعة ومرنة ومناسبة للتعامل مع البيانات كبيرة الحجم وتخفف القيود المفروضة على تناسق وتنظيم البيانات المفروضة في أنواع قواعد البيانات الأخرى وهي مناسبة لتوسع الأعمال حيث يمكنك زيادة أدائها بسهولة عند الحاجة لتلائم متطلبات عملك.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="315" id="ips_uid_1639_7" src="https://academy.hsoub.com/applications/core/interface/index.html" title="YouTube video player" width="560" data-embed-src="https://www.youtube.com/embed/ZLlfTf4w9KU"></iframe>
</p>

<p>
	استعرضنا لك اثنين من أشهر أنواع قواعد البيانات واستعرضنا أهم حالات استخدامهما، وتذكر أنه من الضروري أن تختار نوع قاعدة بيانات الأنسب لمشروعك كي تستفيد من مميزاته بالشكل الصحيح وتنجز مشروعك بأفضل أداء.
</p>

<p>
	هناك بالطبع العديد من الأنواع الأخرى مثل قواعد البيانات الهرمية والشبكية وقواعد البيانات كائنية التوجه ومستودعات البيانات…إلخ. ولمطالعة مزيد من التفاصيل حول ميزات كل نوع منها يمكنك قراءة مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">أنواع قواعد البيانات وأهم مميزاتها واستخداماتها</a>.
</p>

<h2>
	أهمية قواعد البيانات في سوق العمل
</h2>

<p>
	إن فهمك لأساسيات قواعد البيانات ومهارات التعامل معها في المشاريع العملية يوفر لك العديد من الفرص في سوق العمل الكبير المتعلق بقواعد البيانات -نظرًا للطلب الشديد- ويمكنك من شغل عدة أدوار وظيفية ذات رواتب مجزية سنذكر أهمها.
</p>

<h3>
	مسؤول قاعدة البيانات Database administrator
</h3>

<p>
	مسؤول قاعدة البيانات DBA هو المسؤول عن <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">تصميم وإنشاء قاعدة البيانات</a> وإنشاء حسابات مستخدمي قاعدة البيانات ومنح صلاحيات الوصول المناسبة إليها هذه حسب الحاجة، إضافة إلى إدارة قاعدة البيانات وإصلاحها وصيانة حلول النسخ الاحتياطي لقواعد البيانات الخاصة بالعمل لمنع فقدان البيانات، وحذف قاعدة البيانات عند الضرورة والتأكد من أن قواعد بيانات العمل والتطبيقات التي تتعامل معها تعمل بالشكل المطلوب.
</p>

<h3>
	مدير قاعدة البيانات Database manager
</h3>

<p>
	هو المسؤول عن إدارة وصيانة وحماية كافة قواعد البيانات المستخدمة في مقر العمل كما أنه يشرف ويدرب الموظفين الذين يتعاملون مع قواعد البيانات هذه للتأكد من أن التعامل معها يتم بطريقة صحيحة وآمنة.
</p>

<h3>
	محلل بيانات Data analyst
</h3>

<p>
	هو المسؤول عن جمع البيانات المرتبطة بالعمل وتنظيفها من أي بيانات خاطئة أو مكررة وتحليلها إلى معلومات مفيدة وعرضها بشكل تقارير مفهومة وسهلة القراءة وعرضها على أصحاب القرار في العمل. وللتعرف على المزيد من المعلومات حول هذا التخصص أنصح بقراءة مقال <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">الدليل الشامل إلى تحليل البيانات</a>
</p>

<h3>
	عالم بيانات Data scientists
</h3>

<p>
	عالم البيانات هو شخص محترف في تحليل البيانات ويملك مهارات عالية في البرمجة والإحصاء والرياضيات والتعلم الآلي لتحليل البيانات واستنتاج المعلومات القيمة منها ومهارات تقنية لحل المشكلات المعقدة واستكشاف المشكلات التي يجب حلها.
</p>

<p>
	وهو مسؤول عن إنشاء نماذج التعلم الإحصائي وإيجاد وسائل جديدة لتحليل بيانات الشركة التي يعمل بهما والعمل على إيجاد أفضل الحلول لمشاكل العمل. وللاطلاع على مزيد من المعلومات حول هذا التخصص يمكنك مطالعة مقال <a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">الدليل الشامل إلى علم البيانات</a>
</p>

<p>
	كانت هذه نبذة عن أهم الأدوار الوظيفية التي تتعامل مع قواعد البيانات إلى جانب العديد من الأدوار الأخرى التي قد تختلف تسميتها من جهة لأخرى لكنها ترتبط بشكل أساسي بتطوير و<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تصميم قواعد البيانات</a> أو بإدارة قاعدة البيانات أو بتشغيل قاعدة البيانات أو بتحليل البيانات المحفوظة في قواعد البيانات.
</p>

<h2>
	كيف أتعلم قواعد البيانات؟
</h2>

<p>
	بعد أن تعرفت على أهمية قواعد البيانات والطلب عليها في سوق العمل قد تتساءل ما هي الخطوات التي علي اتباعها كي تتعلم قواعد البيانات وإليك أهم الخطوات:
</p>

<ol>
	<li>
		تعلم المفاهيم والمصطلحات الأساسية حول قواعد البيانات وأنواعها وطرق تصميمها ومتى تستخدم كل نوع منها.
	</li>
	<li>
		تعلم التعامل مع أنظمة إدارة قواعد البيانات مثل MySQL و Oracle أو PostgreSQL و Ruby on Rails. توفر هذه الطرق طرقًا سريعة وفعالة للاستعلام عن قاعدة البيانات من الواجهة الخلفية الخاصة بك. يجب أن يعرف كل شخص من محللي الأعمال إلى خبراء إدارة قواعد البيانات هذه المهارات.
	</li>
	<li>
		تعلم برمجة قواعد البيانات من خلال مشاريع وتطبيقات عملية فهي تعزز فرصتك في الحصول على فرص أكبر في سوق العمل.
	</li>
	<li>
		طور مهاراتك الشخصية مثل مهارات التحليل المنطقي ومهارات التواصل الفعال لأن العمل في مجال قواعد البيانات يتطلب منك التعاون والتواصل مع باقي أعضاء فريق التطوير.
	</li>
	<li>
		اختر مصادر تعليمية مفيدة والتزم بها ولا تشتت نفسك بكثرة المصادر.
	</li>
</ol>
<iframe allowfullscreen="" data-controller="core.front.core.autosizeiframe" data-embedauthorid="3889" data-embedcontent="" src="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/?do=embed" style="margin: auto;"></iframe>

<p>
	ستجد في أكاديمية حسوب الكثير من مصادر تعلم قواعد البيانات وهي:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/" rel="">الدروس والمقالات التي تشرح أساسيات قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">كتاب تصميم قواعد البيانات</a> من الصفر للاحتراف متاح للتحميل مجانًا
	</li>
	<li>
		<a href="https://academy.hsoub.com/store/7-%D8%AF%D9%88%D8%B1%D8%A9-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">دورة علوم الحاسوب</a> ستجد مسارًا كاملًا يعرفك على قواعد البيانات بمختلف أنواعها وستتعمق بمختلف جوانب لغة الاستعلام SQL، وستطبقها عمليًا خطوةً بخطوة على قواعد بيانات SQLite، وستتطلع على مفاهيم قواعد بيانات NoSQL.
	</li>
</ul>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="315" id="ips_uid_1639_8" src="https://academy.hsoub.com/applications/core/interface/index.html" title="YouTube video player" width="560" data-embed-src="https://www.youtube.com/embed/EkvUFDevMlM"></iframe>
</p>

<h2>
	الخلاصة
</h2>

<p>
	تعرفنا في مقال اليوم على أهمية قواعد البيانات التي تعد أحد المفاهيم المهمة في عالم البرمجة وتقنية المعلومات وتعرفنا على أهم خصائصها واكتشفنا أنواع قواعد البيانات ومميزات كل نوع منها، واستعرضنا أهم الوظائف المرتبطة بتخصص قواعد البيانات.
</p>

<p>
	وختمنا المقال بجملة من النصائح التي تساعدك على تعلم قواعد البيانات ودخول سوق العمل بأفضل الطرق وأسرعها ونرحب بأن تشاركنا أي أسئلة أو استفسارات تتعلق بأهمية قواعد البيانات في قسم التعليقات أسفل المقال.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database-development-r553/" rel="">عملية تطوير قواعد البيانات Database Development</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تعرف على مكونات قاعدة البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">700</guid><pubDate>Mon, 05 Jun 2023 15:00:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x645;&#x643;&#x648;&#x646;&#x627;&#x62A; &#x642;&#x627;&#x639;&#x62F;&#x629; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_04/----.png.2d5b93126c2cf3eae87ef80ab8ddf38a.png" /></p>
<p>
	تعد قواعد البيانات أحد العناصر الأساسية اليوم في مختلف الشركات والمؤسسات التي تسعى لتطوير حلول برمجية خاصة بها، فجميع تطبيقات الأعمال اليوم مثل تطبيقات التجارة الإلكترونية وإدارة المخزون وإدارة العلاقات مع العملاء وغيرها من التطبيقات التقنية تحتاج إلى قاعدة بيانات لتخزين المعلومات الخاصة بها ومعالجتها وإتاحتها للاستخدام.
</p>

<p>
	في مقال اليوم سنتعرف على مفهوم قواعد البيانات ونظام إدارة قواعد البيانات DBMS ومكونات قاعدة البيانات ونتعرف على أهمية قواعد البيانات في أتمتة الأعمال التجارية المختلفة.
</p>

<h2>
	ما هي قاعدة البيانات؟
</h2>

<p>
	<a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">قاعدة البيانات</a> هي نظام يدير البيانات إلكترونيًا فالمهمة الأساسية لقواعد البيانات هي توفير آلية لتخزين كمية كبيرة من البيانات بطريقة فعالة وخالية من الأخطاء وتوفير إمكانية الحصول على المعلومات المطلوبة من هذه البيانات عند الحاجة.
</p>

<p>
	تحتاج الشركات والأفراد اليوم إلى تخزين العديد من البيانات لمختلف الاستخدامات، على سبيل المثال إليك بعض الاستخدامات المفيدة لقواعد البيانات:
</p>

<ul>
	<li>
		تخزن الأعمال التجارية كافة بيانات العمليات التجارية مثل المبيعات والطلبات وخدمة العملاء فتحليل هذه البيانات يمكن أن يساهم في اتخاذ قرارات تساعد في تحسين سير العمل وزيادة المبيعات بشكل كبير.
	</li>
	<li>
		تخزن مؤسسات العمل المختلفة بيانات العملاء والمستخدمين الذين يزورون مواقع الشركات على الويب أو يتفاعلون على منصات التواصل الاجتماعي مثل الأسماء وعناوين البريد الإلكتروني والمواقع الجغرافية والاهتمامات وما شابه فتتبع هذه البيانات من شأنه أن يساعد في التوصية بالمنتجات والخدمات الأفضل وإدارة الحملات التسويقية بنجاح.
	</li>
	<li>
		تستفيد مؤسسات الرعاية الصحية من تخزين كافة المعلومات الصحية الشخصية لتقديم الرعاية اللازمة لهم بشكل آمن بناءً على سجلاتهم السابقة.
	</li>
	<li>
		تخزن المؤسسات المالية كافة المعلومات حول الأسهم والمبيعات والسندات وعمليات التداول.
	</li>
	<li>
		تحتاج المؤسسات التعليمية والجامعات إلى تخزين كافة المعلومات عن الطلاب وتحصيلهم الدراسي والدورات والمناهج التي يدرسونها.
	</li>
	<li>
		تخزن شركات الخطوط الجوية كافة البيانات المتعلقة بحجوزات التذاكر ومواعيد إقلاع وهبوط الطائرات وكافة الجداول الزمنية في قواعد بيانات مخصصة.
	</li>
	<li>
		يمكن أن تستخدم قواعد البيانات أيضًا لحفظ بياناتك الشخصية مثل الدروس والمحاضرات التي تتعلمها أو الصور الشخصية الخاصة بك لتنظيمها وتسهيل البحث فيها.
	</li>
</ul>

<h2>
	ما هي مكونات قاعدة البيانات؟
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="123418" href="https://academy.hsoub.com/uploads/monthly_2023_04/----.png.0b60fdb44699759e50d7cd48c274e748.png" rel=""><img alt="تعرف-على-مكونات-قاعدة-البيانات.png" class="ipsImage ipsImage_thumbnailed" data-fileid="123418" data-ratio="62.50" data-unique="ya4mup2ss" style="width: 600px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_04/----.thumb.png.80ac465d63dd5e1f2b213dc970f877ac.png"></a>
</p>

<p>
	تتكون أنظمة قواعد البيانات من 3 مكونات أساسية هي:
</p>

<ol>
	<li>
		قاعدة البيانات التي تتضمن البيانات نفسها
	</li>
	<li>
		برنامج إدارة قواعد البيانات DataBase Management System أو اختصارًا DBMS
	</li>
	<li>
		البنية التحتية المستخدمة لحفظ قاعدة البيانات والوصول إليها وهي تشمل العتاد عمومًا من حواسيب وخوادم وأقراص للتخزين.
	</li>
</ol>

<h3>
	1. قاعدة البيانات DataBase
</h3>

<p>
	قاعدة البيانات هي البنية أو الهيكلية المسؤولة عن تخزين البيانات وإدارتها في نظام الحاسوب والتي يتم التحكم فيها بواسطة نظام إدارة قواعد البيانات، وتسمى كل من البيانات ونظام إدارة قواعد البيانات مع التطبيقات المرتبطة بها باسم نظام قاعدة بيانات أو اختصارًا قاعدة البيانات.
</p>

<p>
	هناك عدة أنواع من قواعد البيانات أشهرها قواعد البيانات العلاقيّة وهي تتكون من مجموعة من الجداول بينها علاقات التي يتم فيها تخزين سجلات البيانات الفردية مع علاقات ضابطة ترتبط بين هذه السجلات وتنظمها.
</p>

<p>
	وهناك نوع آخر شهير لقواعد البيانات يعرف باسم قواعد البيانات غير العلاقيّة أو قواعد بيانات NoSQL وقد تم تطوير هذا النوع الحديث من قواعد البيانات من أجل تخزين الكميات الكبيرة من البيانات غير المنظمة ضمن بنية مرنة لا تلتزم بمخطط صارم مثل بيانات الويب وتطبيقات البيانات الضخمة وتطبيقات الزمن الحقيقي، وللتعرف على الفروقات بينهما راجع مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D9%81%D8%B1%D9%88%D9%82%D8%A7%D8%AA-%D8%A8%D9%8A%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-sql-%D9%88%D9%86%D8%B8%D9%8A%D8%B1%D8%A7%D8%AA%D9%87%D8%A7-nosql-r71/" rel="">شرح الفروقات بين قواعد بيانات SQL ونظيراتها NoSQL</a>.
</p>

<p>
	تستخدم قواعد البيانات غير العلاقيّة عدة هياكل لتخزين البيانات مثل:
</p>

<ul>
	<li>
		قواعد بيانات المستندات Document databases
	</li>
	<li>
		المخازن المعتمدة على الأعمدة Column-oriented databases
	</li>
	<li>
		مخازن مفتاح-قيمة Key-value stores
	</li>
	<li>
		مخازن الرسوم البيانية Graph databases
	</li>
</ul>

<p>
	كما تتوافر العديد من قواعد البيانات الأخرى مثل قواعد البيانات كائنية التوجه وقواعد البيانات السحابية وقواعد البيانات الموزعة وإذا كنت مهتمًا بالتعرف على المزيد من التفاصيل حول مميزات واستخدامات ومكونات قاعدة البيانات لكل نوع منها أنصحك بقراءة مقال تعرف على <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">أنواع قواعد البيانات وأهم مميزاتها</a>.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="450" id="ips_uid_7955_5" src="https://academy.hsoub.com/applications/core/interface/index.html" title="YouTube video player" width="800" data-embed-src="https://www.youtube.com/embed/1Sb2wC7S5Rw"></iframe>
</p>

<h3>
	2. نظام إدارة قواعد البيانات DBMS
</h3>

<p>
	<a href="https://academy.hsoub.com/devops/servers/databases/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%88%D8%A7%D8%AE%D8%AA%D9%84%D8%A7%D9%81%D9%87-%D8%B9%D9%86-%D9%86%D8%B8%D8%A7%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r509/" rel="">نظام إدارة قواعد البيانات DBMS</a> هو عبارة عن برنامج يساعد مسؤولي قواعد البيانات والمؤسسات على إدارة قواعد البيانات الخاصة بهم فهو يوفر العديد من الأدوات التي تسهل عمليات إدارة واسترجاع البيانات من قاعدة البيانات.
</p>

<p>
	يوفر نظام إدارة قواعد البيانات عادة واجهة إدارة مركزية تسهل إجراء كافة المهام الإدارية على قاعدة البيانات والتحكم بها ومن أبرز مهام نظام إدارة قواعد البيانات:
</p>

<ul>
	<li>
		تكوين وإدارة حسابات مستخدمي قاعدة البيانات بسهولة وتحديد سياسات الوصول.
	</li>
	<li>
		تبسيط عمليات النسخ الاحتياطي للبيانات من خلال توفير واجهات سهلة لإنشاء وإدارة النسخ الاحتياطية من قاعدة البيانات ونقلها من موقع لآخر.
	</li>
	<li>
		توفير أدوات متكاملة لمراقبة وضبط أداء قواعد البيانات وتحسين الاستعلامات من قواعد البيانات.
	</li>
	<li>
		توفير نظام لاسترداد البيانات كليًا أو جزئيًا إلى حالتها السابقة بسهولة وسرعة.
	</li>
</ul>

<p>
	يستخدم نظام إدارة قواعد البيانات العلاقيّة RDBMS لغة معيارية تسمى <a href="https://academy.hsoub.com/programming/sql/" rel="">لغة الاستعلام الهيكلية SQL</a> من أجل استرجاع البيانات أو بعبارة أخرى الاستعلام عنها وإدارة هذه البيانات مثل تعديلها أو حذفها أو إضافة سجلات جديدة فيها كما يمكن للغة SQL إجراء الكثير من العمليات الأخرى على قواعد البيانات بما في ذلك تحسين قواعد البيانات وصيانتها.
</p>
<iframe allowfullscreen="" data-controller="core.front.core.autosizeiframe" data-embedauthorid="3889" data-embedcontent="" src="https://academy.hsoub.com/files/16-%D9%85%D9%84%D8%A7%D8%AD%D8%B8%D8%A7%D8%AA-%D9%84%D9%84%D8%B9%D8%A7%D9%85%D9%84%D9%8A%D9%86-%D8%A8%D9%84%D8%BA%D8%A9-sql/?do=embed" style="margin: auto;"></iframe>

<p>
	ومن أشهر نظم إدارة قواعد البيانات العلاقيّة نذكر مايكروسوفت أكسس <a href="https://academy.hsoub.com/tags/%D9%85%D8%A7%D9%8A%D9%83%D8%B1%D9%88%D8%B3%D9%88%D9%81%D8%AA%20%D8%A3%D9%83%D8%B3%D8%B3/" rel="">Microsoft Access</a> وMySQL و MariaDB و PostgreSQL و SQLite …إلخ.
</p>

<p>
	وتجدر الإشارة إلى أن مصنعي قواعد البيانات المختلفة يستخدمون لغة SQL الخاصة بهم لذا يمكن أن تجد أسماء مختلفة للغة SQL خاصة بكل نظام إدارة قواعد البيانات مثل PL SQL التي تستخدمها قواعد بيانات أوراكل Oracle Database و T-SQL والتي تعني Transact-SQL التي تستخدمها قواعد بيانات مايكروسوفت فهذه التسميات ما هي سوى امتداد للغة SQL فهي اللغة القياسية أو المعيارية للاستعلام عن قاعدة البيانات.
</p>

<p>
	كما تعتمد قواعد البيانات غير العلاقيّة على نظم إدارة قواعد بيانات خاصة بها فهناك على سبيل المثال أنظمة إدارة قواعد بيانات خاصة بقواعد بيانات المستندات DoDBMS مثل MongoDB و Azure Cosmos DB وأنظمة إدارة قواعد بيانات خاصة بقواعد البيانات المعتمدة على الأعمدة CDBMS مثل Apache Cassandra و Apache HBase وأنظمة إدارة قواعد بيانات خاصة بقواعد بيانات الرسوم GDBMS مثل GraphDB و Neo4j و ArangoDB وغيرها.
</p>

<h2>
	ما هي مكونات نظام إدارة قواعد البيانات؟
</h2>

<p>
	يتكون أي نظام إدارة قواعد البيانات من العناصر التالية:
</p>

<ul>
	<li>
		محرك التخزين Storage engine
	</li>
	<li>
		لغة الاستعلام عن البيانات Query language
	</li>
	<li>
		معالج الاستعلام Query processor
	</li>
	<li>
		محرك تحسين قاعدة البيانات Optimization engine
	</li>
	<li>
		مدير السجل Log manager
	</li>
	<li>
		فهرس البيانات الوصفية Metadata catalog
	</li>
	<li>
		أدوات للمراقبة وإصدار التقارير Reporting and monitoring tools
	</li>
	<li>
		أدوات مساعدة للبيانات Data utilities
	</li>
</ul>

<h3>
	1. محرك التخزين
</h3>

<p>
	يعد محرك التخزين المكون الأساسي لنظام إدارة قواعد البيانات DBMS وهو المسؤول عن التفاعل مع نظام الملفات الذي يخزن البيانات على مستوى نظام التشغيل حيث تمرّ جميع الاستعلامات التي تتفاعل مع البيانات الأساسية عبر محرك التخزين هذا.
</p>

<h3>
	2. لغة الاستعلام
</h3>

<p>
	يدعم أي نظام إدارة قواعد بيانات لغة أو تقنية للاستعلام تمكنها من التفاعل مع قاعدة البيانات مثل لغة الاستعلام الهيكلية SQL ولغة MQL وهي اختصار لعبارة MongoDB Query Language.
</p>

<p>
	وغالبًا ما تقسم تعليمات لغة الاستعلام نفسها لعدة عناصر حسب المهام التي تقوم بها مثل:
</p>

<ul>
	<li>
		<p>
			<strong>لغة معالجة البيانات Data Manipulation Language أو اختصارًا DML:</strong> تتضمن الأوامر التي تعالج البيانات الموجودة داخل قاعدة البيانات نفسها مثل إنشاء قيم جديدة وحذفها وتعديلها …إلخ.
		</p>
	</li>
	<li>
		<p>
			<strong>لغة تعريف البيانات Data Definition Language أو اختصارًا DDL:</strong> تتضمن مجموعة الأوامر التي يمكن استخدامها لتحديد وتعديل الهيكلية أو البنية العامة لقاعدة البيانات
		</p>
	</li>
	<li>
		<p>
			<strong>لغة التحكم في البيانات Data Control Language أو اختصارًا DCL:</strong> وهي تتضمن الأوامر التي تمكننا من التحكم بصلاحيات الوصول إلى محتوى قاعدة البيانات.
		</p>
	</li>
	<li>
		<p>
			<strong>لغة التحكم في المعاملات Transaction Control Language أو اختصارًا TCL</strong> وهي تتضمن الأوامر التي تتحكم بالتعاملات الداخلية التي تمت على قاعدة البيانات وتمكننا على سبيل المثال من التراجع عن التغييرات التي قمنا بها أو حفظ وتثبيت هذه التغييرات.
		</p>
	</li>
</ul>

<h3>
	3. معالج الاستعلام
</h3>

<p>
	يلعب معالج الاستعلام دور الوسيط بين قاعدة البيانات وبين الاستعلامات التي يجريها المستخدم على قاعدة البيانات فهو يفسر استعلامات المستخدمين ويحولها إلى أوامر يمكن بقاعدة البيانات فهمها وتنفيذها وإرجاع النتيجة الصحيحة.
</p>

<h3>
	4. محرك تحسين قاعدة البيانات
</h3>

<p>
	يوفر محرك التحسين تقارير حول أداء قاعدة البيانات ويساعدنا على تحسين قاعدة البيانات نفسها وتحسين أداء الاستعلامات التي تنفذ على قاعدة البيانات.
</p>

<h3>
	5. مدير السجلات
</h3>

<p>
	تخزن كافة سجلات نظام إدارة قواعد البيانات سواء عمليات تسجيل دخول المستخدم أو عمليات النسخ الاحتياطي لقاعدة البيانات أو العمليات على البيانات…إلخ. ضمن مدير السجلات لإعطاء فكرة عامة عن كافة الإجراءات التي تتم على قاعدة البيانات وتسهيل الوصول لها والاطلاع عليها.
</p>

<h3>
	6. فهرس البيانات الوصفية
</h3>

<p>
	عند إنشاء أي عنصر داخل قاعدة البيانات يحتفظ نظام إدارة قواعد البيانات بسجل لهذا الكائن ويخزن بعض البيانات الوصفية عنه ضمن فهرس مركزي يعرف باسم فهرس البيانات الوصفية Metadata ويساعد هذا الفهرس على تكوين نظرة عامة على بنية قاعدة البيانات بالكامل.
</p>

<h3>
	7. أدوات للمراقبة وإصدار التقارير
</h3>

<p>
	لا يخلو أي نظام إدارة قواعد بيانات من أدوات مخصصة للمراقبة لإعداد التقارير التي تمكن المستخدمين من إنشاء تقارير حول نسبة استهلاك الموارد ونشاط المستخدمين والإجراءات التي تم القيام بها …إلخ.
</p>

<h3>
	8. مكونات بيانات مساعدة
</h3>

<p>
	تتضمن كافة أنظمة إدارة قواعد البيانات أدوات ومكونات مساعدة إضافية مدمجة فيها تساعد في التعامل مع البيانات وتقدم العديد من الخدمات المفيدة مثل فحص سلامة وصحة البيانات وإصلاح الأخطاء في البيانات وجدولة عمليات النسخ الاحتياطي وإدارة الوصول المتعدد إلى قاعدة البيانات من قبل عدة مستخدمين في نفس الوقت والعديد من الخدمات الأخرى المفيدة التي توفر تجربة مستخدم أفضل.
</p>

<p>
	إن تواجد كافة هذه المكونات ضمن مكان واحد من شأنه تسهيل عمل مسؤولي قواعد البيانات في تنفيذ جميع المهام المتعلقة بإدارة وصيانة قواعد البيانات بسرعة وكفاءة لذا يعد نظام إدارة قواعد البيانات أحد مكونات قاعدة البيانات الأساسية والتي لا غنى عنها لإدارة البيانات وتنظيمها بأفضل شكل.
</p>

<h2>
	الخلاصة
</h2>

<p>
	في مقال اليوم تعرفنا على مكونات قاعدة البيانات وأنواعها المختلفة ومكونات نظام إدارة قواعد البيانات المختلفة التي تعد حجر الزاوية في التطبيقات التقنية المطبقة في مختلف المجالات.
</p>

<p>
	وأود أن أشير في الختام إلى أن تعلم قواعد البيانات أمر ضروري لأي شخص يرغب في تعلم علوم الحاسوب والبرمجة فلا غنى عن إنشاء قاعدة بيانات من أجل تخزين وإدارة البيانات التي تستخدمها هذه التطبيقات والبرامج لذا اغتنم وقتك وابدأ من الآن بتعلم قواعد البيانات وأنواعها وتقنياتها المختلفة وإن واجهك أي سؤال أو اعترضتك أي مشكلة لا تتردد في مشاركتها معنا في قسم التعليقات أسفل المقال.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%AE%D8%B5%D8%A7%D8%A6%D8%B5-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D8%B2%D8%A7%D9%8A%D8%A7-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D9%82%D8%AF%D9%85%D9%87%D8%A7-r520/" rel="">خصائص قواعد البيانات والمزايا التي تقدمها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">المفاهيم الأساسية في قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">694</guid><pubDate>Sat, 29 Apr 2023 17:03:01 +0000</pubDate></item><item><title>&#x623;&#x646;&#x648;&#x627;&#x639; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x648;&#x623;&#x647;&#x645; &#x645;&#x645;&#x64A;&#x632;&#x627;&#x62A;&#x647;&#x627; &#x648;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645;&#x627;&#x62A;&#x647;&#x627;</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_04/-------.png.d45b2e43e2880fae29d640fe611c2fc7.png" /></p>
<p>
	في مقال اليوم نقدم شرحًا وافيًا عن أنواع قواعد البيانات الأكثر شيوعًا والتي يحتاج أي مطور لمعرفتها لتطوير التطبيقات المختلفة ونوضح طريقة تخزين البيانات ضمنها وأبرز مميزاتها ونذكر أمثلة متنوعة عن كل نوع منها ونساعدك على اختيار نوع قاعدة البيانات الأنسب لتخرين بياناتك.
</p>

<p>
	فالبيانات اليوم عصب حياتنا المعاصرة ولا غنى عنها لتسيير أعمال الأنظمة الحديثة، وجميع النشاطات التجارية في مختلف المجالات باتت تحتاج إلى تخزين كم هائل من البيانات حول عملاءها وموظفيها ومعاملاتها ومنتجاتها وفواتيرها …إلخ. ولا تقتصر أهمية البيانات على الأنشطة التجارية بل حتى الحياة الشخصية حيث تخزن الأجهزة الإلكترونية المحيطة بنا الكثير من التفاصيل عنا.
</p>

<p>
	لذا، كان لابد من طريقة لتخزين وتنظيم هذه البيانات وإدارتها بشكل فعال، ومن هنا ظهر مفهوم قاعدة البيانات وابتكرت أنواع مختلفة من قواعد البيانات لكل منها منهجية مختلفة في تصميمها وطريقة تعاملها مع البيانات.
</p>

<h2>
	ما هي قواعد البيانات؟
</h2>

<p>
	قبل أن نتعرف على أنواع قواعد البيانات المختلفة دعنا نعرف في البداية ما معنى البيانات وما هي قاعدة البيانات وما أهميتها.
</p>

<p>
	البيانات اليوم أحد الركائز الأساسية لأي مجال عمل معاصر، ولتنظيم هذه البيانات وتسهيل التعامل معها يتم تخزينها ضمن قواعد بيانات Database أو بالمعنى الأدق حاوية بيانات تسهل إدارة هذه البيانات وتحافظ على أمنها وسلامتها وبالتالي <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة البيانات</a> هي بمثابة مستودع أو حاوية للبيانات.
</p>

<p>
	وتحتاج قاعدة البيانات إلى نظام خاص لإدارتها وهو ما يعرف بنظام إدارة قواعد البيانات Database Management System أو اختصارًا DBMS كي يسمح لنا بالاتصال المباشر مع قاعدة البيانات وتخزين البيانات فيها أو استخراج البيانات المخزنة فيها أو ما يعرف بالاستعلام عن البيانات Query بالإضافة إلى معالجتها من تحديث وحذف ونقل …إلخ.
</p>

<p>
	من المصطلحات الأساسية المرتبطة بقواعد البيانات كذلك مخطط قاعدة البيانات Database Schema وهو عبارة عن مخطط منطقي يشبه المخطط المعماري لأي بناء يصف هيكيلة قاعدة البيانات وبنيتها من جداول وأعمدة كل جدول ونوع البيانات الذي يأخذه كل عمود والارتباطات بين أعمدة الجداول والقيود المطبقة على البيانات المدخلة أو المعالجة وغيرها من التفاصيل.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة علوم الحاسوب
		</p>

		<p class="banner-subtitle">
			دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/computer-science/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<img alt="دورة علوم الحاسوب" src="https://academy.hsoub.com/learn/assets/images/courses/computer-science.png">
	</div>
</div>

<h2>
	أنواع قواعد البيانات
</h2>

<p>
	هناك أنواع مختلفة من قواعد البيانات تعتمد على خصائص البيانات التي تخزنها وطريقة تخزين هذه البيانات ومن أهم أنواع قواعد البيانات التي يحتاج المبرمج لفهمها:
</p>

<ol>
	<li>
		قواعد البيانات العلاقية Relational Databases
	</li>
	<li>
		قواعد البيانات غير العلاقية Non-Relational Databases
	</li>
	<li>
		قواعد البيانات كائنية التوجه Object Oriented Databases
	</li>
	<li>
		قواعد البيانات السحابية Cloud Databases
	</li>
	<li>
		قواعد البيانات المركزية Centralized Databases
	</li>
	<li>
		قواعد البيانات الموزعة Distributed Databases
	</li>
</ol>

<p>
	سنتعرف في الفقرات التالية على شرح مفصل عن كل نوع من هذه الأنواع وأهم مميزاتها وحالات استخدامها.
</p>

<h3>
	1. قواعد البيانات العلاقية SQL
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="123414" href="https://academy.hsoub.com/uploads/monthly_2023_04/1062972940_.png.8ccbba11de9ebb99a37e474699af07ea.png" rel=""><img alt="قاعدة بيانات علائقية.png" class="ipsImage ipsImage_thumbnailed" data-fileid="123414" data-unique="tz5f02xla" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_04/.thumb.png.d88e6940bdfd279822827d16b3700d29.png"> </a>
</p>

<p>
	<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D8%A6%D9%82%D9%8A%D8%A9-rdm-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r522/" rel="">قواعد البيانات العلاقية</a> Relational Databases -أو العلائقية- أو تعرف أيضًا بقواعد بيانات SQL هي من أكثر أنواع قواعد البيانات شيوعًا واستخدامًا، وهي تخزن البيانات ضمن جداول منظمة لها مخطط ثابت، ويتكون كل جدول من مجموعة من الصفوف والأعمدة التي ترتبط بعلاقات مع بعضها البعض لتشكل قاعدة بيانات ومن هنا جاءت تسميتها بالعلاقية لتميزها بوجود تلك العلاقات بين الجداول.
</p>

<p>
	تمثل الأعمدة خصائص أو سمات الجدول ويمثل الصف القيمة الفعلية لهذه الخاصية ويمثل كل سطر في الجدول سجلًا ويتضمن كل جدول في قاعدة البيانات عمودًا يسمى المفتاح لا يتكرر بين سجل وآخر ويميز السجلات عن بعضها.
</p>

<p>
	كي تتعامل مع البيانات المخزنة في قواعد البيانات العلاقية تحتاج لاستخدام <a href="https://academy.hsoub.com/programming/sql/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B3%D8%B1%D9%8A%D8%B9%D8%A9-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%87%D9%8A%D9%83%D9%84%D9%8A%D8%A9-sql-r1368/" rel="">لغة الاستعلام الهيكلية SQL</a> وهي عبارة عن لغة برمجة قياسية تستخدم للتخاطب مع قاعدة البيانات العلاقية وتخزين البيانات فيها ومعالجتها وصيانتها.
</p>

<p>
	تتميز قواعد البيانات العلاقية بأنها قابلة للتوسع وسهولة إضافة بيانات جديدة إلى الجداول دون التأثير على السجلات المخزنة مسبقًا كما أنها توفر حماية عالية للبيانات لأن البيانات مقسمة إلى جداول مما يمكننا من جعل بعض الجداول سرية وعدم السماح بالوصول إليها سوى من قبل مستخدمين بصلاحيات إدارية محددة.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="450" id="ips_uid_8593_6" src="https://academy.hsoub.com/applications/core/interface/index.html" title="YouTube video player" width="800" data-embed-src="https://www.youtube.com/embed/Idq1QrXEfQk"></iframe>
</p>

<p>
	تستخدم قواعد البيانات العلاقية في العديد من التطبيقات إلا أنها تعد مناسبة أكثر لمجموعات البيانات التي لها بنية منظمة يمكن نمذجتها ضمن جداول محددة ومصممة مسبقًا، كما أنها تعتبر ملائمة لمستودعات البيانات لكونها تسهل تنفيذ استعلامات معقدة على بيانات من مصادر متعددة.
</p>

<p>
	من أبرز الأمثلة على قواعد البيانات العلاقية نذكر:
</p>

<ul>
	<li>
		أوراكل
	</li>
	<li>
		<a href="https://academy.hsoub.com/apps/productivity/office/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D8%B9%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D8%A7%D9%8A%D9%83%D8%B1%D9%88%D8%B3%D9%88%D9%81%D8%AA-%D8%A3%D9%83%D8%B3%D8%B3-microsoft-access-r701/" rel="">مايكروسوفت أكسس</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-mysql-%D9%88-mongodb-r627/" rel="">MySQL</a>
	</li>
	<li>
		Microsoft SQL Serve
	</li>
	<li>
		IBM Db2
	</li>
	<li>
		MariaDB
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-postgresql-r481/" rel="">PostgreSQL</a>
	</li>
</ul>

<h3>
	2. قواعد البيانات غير العلاقية NoSQL
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="123413" href="https://academy.hsoub.com/uploads/monthly_2023_04/1063181822_.png.0f25b80b94ab9d3bc35e677a9d1d6989.png" rel=""><img alt="قاعدة بيانات غير علائقية.png" class="ipsImage ipsImage_thumbnailed" data-fileid="123413" data-unique="qs44pl99m" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_04/.thumb.png.26aecd71b81d112953797043c8de2bb9.png"> </a>
</p>

<p>
	نظرًا للزيادة الهائلة في حجم البيانات الموجودة والحاجة إلى تحليل البيانات الضخمة التي يتم إنشاؤها كل يوم في الشركات الكبرى وتطبيقات الويب والمتاجر الإلكترونية الضخمة، لم تعد قواعد البيانات العلاقية ملائمة للتعامل مع هذا الكم من البيانات ومعالجتها بسرعة ودعم الحوسبة السحابية لها دون تعزيزها بموارد إضافية.
</p>

<p>
	هذه القيود دفعت لظهور نوع جديد من أنواع قواعد البيانات عرف باسم قواعد البيانات غير العلاقية Non-Relational Database أو ما يعرف بقواعد بيانات Not Only SQL أو اختصارًا NoSQL كي تلائم مجموعات البيانات الكبيرة بشكل أفضل وسميت بهذا الاسم لأنها لا تخزن البيانات على شكل جداول فحسب بل تعتمد على طرق وأساليب مختلفة سنتعرف عليها بعد قليل، وهي قادرة على التعامل مع مشكلات الأداء في البيانات الضخمة big data وتستطيع تحليل ومعالجة كمٍّ هائل من البيانات بمرونة وكفاءة عالية.
</p>

<p>
	فقواعد البيانات غير العلاقية NoSQL Databases هي نوع من أنواع قواعد البيانات المستخدمة لتخزين مجموعة ضخمة من البيانات التي تتميز يكونها غير متجانسة وغير مرتبطة مع بعضها البعض وهي تعرف باسم البيانات غير المهيكلة Unstructured Data وهي بيانات يصعب الاحتفاظ بها في جداول لها مخطط ثابت ومنظم.
</p>

<p>
	من الأمثلة على البيانات غير المهيكلة رسائل البريد الإلكتروني وصفحات الويب التي تتضمن على كمية كبيرة من البيانات المتباينة على هيئة نصوص أو صور أو مقاطع فيديو أو روابط …إلخ. لهذا السبب برز استخدام قواعد بيانات NoSQL بشكل واسع في التطبيقات الحديثة التي تحتاج لمعالجة مثل هذه.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="450" id="ips_uid_8593_7" src="https://academy.hsoub.com/applications/core/interface/index.html" title="YouTube video player" width="800" data-embed-src="https://www.youtube.com/embed/ZLlfTf4w9KU"></iframe>
</p>

<p>
	كما تعد قواعد البيانات غير العلاقية مناسبة للاستخدام في تطبيقات نظم الزمن الحقيقي التي تتطلب سرعة في الاستجابة وتطبيقات الحوسبة السحابية وتستخدمها اليوم كبرى شركات الإنترنت مثل جوجل و أمازون لمعالجة الكم الهائل من البيانات الخاصة بها.
</p>

<p>
	وتتميز قاعدة بيانات NoSQL ببساطة بنائها فلا تحتاج إلى مخطط وبنية وروابط لذلك تجدها مستخدمة في التطبيقات البسيطة التي لا تحتاج إلى بناء مخطط وهيكل وروابط في قاعدة بياناتها حيث بناء قاعدة بيانات علائقية تحتاج إلى وقت وبعض الجهد بل وأحيانًا خبرة في وضع المخطط وتنفيذه فليست بالعملية السهلة مثل بناء قاعدة بيانات غير علائقية.
</p>

<p>
	ومن أبرز الأمثلة على قواعد بيانات غير علاقية نذكر:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/redis/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-redis%D8%9F-r668/" rel="">Redis</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-mysql-%D9%88-mongodb-r627/" rel="">MongoDB</a>
	</li>
	<li>
		Oracle NoSQL
	</li>
	<li>
		HBase
	</li>
	<li>
		Neo4j
	</li>
	<li>
		OrientDB
	</li>
	<li>
		RavenDB
	</li>
	<li>
		Amazon S3
	</li>
	<li>
		Cassandra
	</li>
</ul>

<p>
	توفر قواعد البيانات غير العلائقية عدة تنسيقات أو طرق لتخزين ونمذجة البيانات كالتالي:
</p>

<ul>
	<li>
		<p>
			<strong>قواعد بيانات المفاتيح والقيمة A key-value database:</strong> وهي أبسط أنواع قواعد البيانات غير العلاقية وتعتمد على تخزين كل عنصر على شكل خاصية أو مفتاح وقيمة مرتبطة به الأمر الذي يسهل استرداد المعلومات منها من خلال استعلامات بسيطة، ومثال عليها Redis و DynanoDB.
		</p>
	</li>
	<li>
		<p>
			<strong>قواعد بيانات المستندات Document databases:</strong> نوع من أنواع قواعد البيانات المستخدمة لتخزين البيانات من مختلف الأنواع سواء كانت سلاسل نصية أو أرقام أو قيم منطقية أو مصفوفات أو كائنات بشكل مستندات بتنسيق <a href="https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-json-%D9%81%D9%8A-javascript-r548/" rel="">JSON</a>، وهذا النوع يساعد المطورين في تخزين البيانات باستخدام نفس تنسيق نموذج المستندات المستخدم في الشيفرات البرمجية للتطبيقات. ويعد MongoDB مثالًا شهيرًا عليها.
		</p>
	</li>
	<li>
		<p>
			<strong>قواعد بيانات المخطط البياني Graph Databases</strong>: يستخدم هذا النوع لتخزين كميات هائلة من البيانات ضمن رسم بياني مكون من عقد تخزن كيانات البيانات وروابط تعبر عن العلاقات بين هذه العقد، من الأمثلة عليه قواعد البيانات Neo4j و Janusgraph ومن أبرز تطبيقاتها مواقع التواصل الاجتماعي التي تربط المستخدمين فيما بينهم وتقترح الصداقات المناسبة بناء على هذه الروابط.
		</p>
	</li>
	<li>
		<p>
			<strong>قواعد بيانات الأعمدة Column Store Database</strong> يعرف هذا النوع كذلك باسم مخزن العمود العريض Wide column store وهو طريقة مشابهة لتمثيل البيانات في قواعد البيانات العلائقية إلا أن البيانات تخزن في جداول مكونة من صفوف وأعمدة عريضة أو ديناميكية قابلة للتوسع وتوفر قدرة تخزين إضافية فليس من الضروري أن يكون لكل صف نفس مجموعة الأعمدة، وتناسب أنواع محددة من البيانات مثل ملفات تعريف المستخدمين. ومن الأمثلة عليها Cassandra و HBase.
		</p>
	</li>
</ul>

<p>
	النوعان السابقان هما أهم نوعان وأكثرهما استخدامًا، وسنتطرق لهما كثيرًا، أما الأنواع التالية فهي الأقل استخدامًا ومن الجيد التعرف عليهما عن قرب أيضًا.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			هل ترغب في برمجة قواعد بيانات وإدارتها بكفاءة وفاعلية؟
		</p>

		<p class="banner-subtitle">
			وظّف مبرمج قواعد بيانات محترف من مستقل
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://mostaql.com/freelancers/skill/database-programming" rel="external">أضف مشروعك الآن</a>
		</div>
	</div>
</div>

<h3>
	3. قواعد البيانات كائنية التوجه
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="123412" href="https://academy.hsoub.com/uploads/monthly_2023_04/214586613_.png.c803b14473630ffbd59721db20d24e03.png" rel=""><img alt="قاعدة بيانات كائنية التوجه.png" class="ipsImage ipsImage_thumbnailed" data-fileid="123412" data-unique="a1txbpycj" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_04/.thumb.png.fa8868cf657b98991a3f6058726707c5.png"> </a>
</p>

<p>
	قواعد البيانات كائنية التوجه Object Oriented Database هي نوع من قواعد البيانات قائم على مفهوم الكائنات وهو يجمع بين <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">مبادئ البرمجة الكائنية (<abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr>)</a> ومفاهيم قواعد البيانات العلاقية.
</p>

<p>
	ففي قاعدة البيانات العلاقية يتم تخزين البيانات في جداول مكونة من صفوف وأعمدة وبعدها تقوم لغات البرمجة الكائنية التوجه مثل <a href="https://academy.hsoub.com/programming/java/" rel="">Java</a> و <a href="https://academy.hsoub.com/programming/cpp/" rel="">C++‎</a> بقراءة هذه البيانات وتحويلها إلى كائنات في الذاكرة ومعالجتها وإعادة تخزينها من جديد ما يتطلب وقتًا لذا تختصر قواعد البيانات كائنية التوجه الأمر وتعمل على مبدأ تخزين البيانات الكائنات مباشرة في التخزين الدائم وتخزن الكائنات بأكملها في قاعدة البيانات.
</p>

<p>
	ولكون البيانات تمثل وتخزن في نظام قاعدة البيانات كائنية التوجه بشكل كائنات تشبه كائنات العالم الحقيقي بشكل مشابه للأسلوب المستخدم في لغة البرمجة الكائنية وتعبر عن العلاقات بين هذه الكائنات فهذا يجعلها ملائمة لتصميم المشكلات المعقدة ويسهل عملية حفظ البيانات واسترجاعها بكفاءة ومرونة.
</p>

<p>
	تستخدم قواعد البيانات كائنية التوجه في التطبيقات التي تتطلب أداءً عاليًا وتحتاج لاسترداد البيانات بسرعة كالمجالات البحثية والعلمية وفي مجال الاتصالات وعلم الفلك وغيرها من المجالات التي تتطلب تخزين بيانات معقدة واسترجاعها بسرعة وإجراء حسابات معقدة عليها.
</p>

<p>
	هذا النوع من قواعد البيانات ليس شائع الاستخدام كقواعد البيانات العلاقية ومن أشهر قواعد البيانات كائنية التوجه هي:
</p>

<ul>
	<li>
		DB4o
	</li>
	<li>
		Objectivity/DB
	</li>
	<li>
		ObjectDB
	</li>
	<li>
		ObjectDatabase++‎
	</li>
	<li>
		ObjectStore
	</li>
</ul>

<h3>
	4. قواعد البيانات السحابية
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="123417" href="https://academy.hsoub.com/uploads/monthly_2023_04/584638319_.png.54ff6d6850cc1e8759735483be80cf39.png" rel=""><img alt="قاعدة البيانات السحابية.png" class="ipsImage ipsImage_thumbnailed" data-fileid="123417" data-unique="awq6ln16x" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_04/.thumb.png.8fffef5dd97e27c636027f1b7dc9ae59.png"> </a>
</p>

<p>
	قاعدة البيانات السحابية Cloud Database ما هي إلا قاعدة بيانات تقليدية تستفيد من ميزات <a href="https://academy.hsoub.com/devops/cloud-computing/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%AD%D9%88%D8%B3%D8%A8%D8%A9-%D8%A7%D9%84%D8%B3%D8%AD%D8%A7%D8%A8%D9%8A%D9%91%D8%A9-%D8%A7%D9%84%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D9%91%D8%A9%D8%8C-%D9%88%D9%83%D9%8A%D9%81-%D8%AA%D8%B5%D8%A8%D8%AD-%D9%85%D9%87%D9%86%D8%AF%D8%B3-%D8%AD%D9%88%D8%B3%D8%A8%D8%A9-%D8%B3%D8%AD%D8%A7%D8%A8%D9%8A%D9%91%D8%A9-r457/" rel="">الحوسبة السحابية</a> حيث تخزن بياناتها ضمن بيئة افتراضية أو سحابة عامة أو خاصة أو هجينة ويتم تنفيذ العمليات عليها عبر منصة حوسبة سحابية عامة أو خاصة أو مختلطة تابعة لجهة خارجية.
</p>

<p>
	تتميز قواعد البيانات السحابية بمرونتها وقابليتها لزيادة أو إنقاص الموارد المخصصة لكل مستخدم كسعة التخزين وعرض النطاق الترددي بكل سهولة وحسب الحاجة فأنت تدفع فقط مقابل ما تحتاجه وهذا يوفر كلفة تخزين وصيانة البيانات.
</p>

<p>
	كما أنها تتيح للشركات دعم تطبيقات البرمجيات كخدمة <a href="https://academy.hsoub.com/questions/3474-%D9%85%D8%A7%D8%B0%D8%A7-%D8%AA%D8%B9%D9%86%D9%8A-%D8%AE%D8%AF%D9%85%D8%A9-saas-%D9%81%D9%8A-%D8%A7%D9%84%D8%AD%D9%88%D8%B3%D8%A8%D8%A9-%D8%A7%D9%84%D8%B3%D8%AD%D8%A7%D8%A8%D9%8A%D8%A9%D8%9F/#comment-7516" rel="">SaaS</a> والوصول لها عبر الإنترنت وتتميز بسهولة إدارتها وتوفير كلفة البنية التحتية والصيانة لأن مزود الاستضافة هو من يتولى هذا الأمر عادة لذا باتت الخيار المفضل للعديد من الشركات في الآونة الأخيرة لاسيما الشركات الناشئة التي لا تمتلك الميزانية الكافية لتنشئ بنية تحتية محلية خاصة بها.
</p>

<p>
	هناك العديد من المنصات والشركات الكبرى التي توفر خدمات إنشاء قواعد البيانات السحابية ومن أبرزها:
</p>

<ul>
	<li>
		خدمات أمازون ويب AWS
	</li>
	<li>
		منصة جوجل السحابية
	</li>
	<li>
		Oracle Database
	</li>
	<li>
		OpenStack
	</li>
	<li>
		*Kamatera Cloud
	</li>
</ul>

<h3>
	5. قواعد البيانات المركزية
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="123416" href="https://academy.hsoub.com/uploads/monthly_2023_04/1210485633_.png.97231489008e133cdacd76da7a58aefa.png" rel=""><img alt="قاعدة البيانات المركزية.png" class="ipsImage ipsImage_thumbnailed" data-fileid="123416" data-unique="fnpvuro4j" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_04/.thumb.png.bdb9f275bc932d6213434fda77de631f.png"> </a>
</p>

<p>
	قاعدة البيانات المركزية Centralized Database هي قاعدة بيانات تخزن كافة بياناتها في مكان واحد مركزي يمكن للمستخدمين الذين يملكون الصلاحيات الوصول له من مواقع متفرقة وهذا بدوره يتيح لعدة أشخاص إمكانية العمل على نفس البيانات في الوقت ذاته.
</p>

<p>
	تستخدم الشركات الكبيرة قواعد البيانات المركزية لتخزين كافة البيانات التي تريد مشاركتها بين عدة مستخدمين، معلومات العملاء وبيانات المخزون والسجلات المالية للشركة. كما يمكن يتم استخدامها من قبل المؤسسات الحكومية وفي الجامعات لإنشاء قاعدة بيانات مركزية تضم كافة بيانات المكتبات لكافة الكليات ليصل لها الطلاب من مختلف التخصصات.
</p>

<p>
	تتميز قواعد البيانات المركزية بأنها تضمن جودة ودقة البيانات وتقلل من مخاطر التلاعب بها وتحافظ على اتساقها لأنها تدير البيانات في مستودع أو خادم مركزي شامل يتم الوصول له عادة عبر الاتصال بالإنترنت.
</p>

<p>
	وتكون كلفة صيانتها منخفضة، إلا أنها في ذات الوقت قد لا تكون فعالة من ناحية الوقت لأن حجمها قد يكون كبيرًا جدًا الأمر الذي يزيد من زمن الاستجابة لجلب البيانات منها كما أن حدوث أي فشل في الحاسوب المركزي الذي يخزن البيانات قد يسبب فقدان كافة البيانات.
</p>

<h3>
	6. قواعد البيانات الموزعة
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="123415" href="https://academy.hsoub.com/uploads/monthly_2023_04/1370815820_.png.52a275e5592a9baa5b04dc35baa9374f.png" rel=""><img alt="قاعدة البيانات الموزعة.png" class="ipsImage ipsImage_thumbnailed" data-fileid="123415" data-unique="52hsxi51u" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_04/.thumb.png.73d003a05173f9cef058664ae6c7e368.png"> </a>
</p>

<p>
	في قواعد البيانات الموزعة Distributed Database أو اختصارًا DDBs يتم تخزين البيانات في مواقع مادية مختلفة لكنها تكون متصلة ببعضها البعض بواسطة شبكة تتيح الوصول لكافة هذه البيانات المخزنة في عدة مواقع ما يجعل هذه القواعد الموزعة تبدو للمستخدمين النهائيين كأنها قاعدة بيانات مخزنة في مكان مادي واحد.
</p>

<p>
	تستخدم قواعد البيانات الموزعة لحل المشكلات التي قد تنشأ من استخدام جهاز واحد لتخزين قاعدة بيانات مركزية واحدة مثل زيادة الإنتاجية ووقت الاستجابة وقابلية التوسع.
</p>

<p>
	يمكن أن تصنف قواعد البيانات الموزعة إلى نوعين مختلفين هما:
</p>

<ul>
	<li>
		<p>
			قواعد بيانات موزعة متجانسة Homogenous: تخزن قواعد البيانات في هذه الحالة على نفس أنواع الأجهزة التي تستخدم نفس أنظمة التشغيل وتستخدم برمجيات إدارة قواعد بيانات DBMS متطابقة ويكون كل موقع على علم بجميع المواقع الأخرى ويتعاون معها لمعالجة طلبات المستخدمين ويتم الوصول إلى قاعدة البيانات من خلال واجهة واحدة كما لو كانت قاعدة بيانات واحدة.
		</p>
	</li>
	<li>
		<p>
			قواعد بيانات موزعة غير متجانسة Heterogenous: تخزن قواعد البيانات في هذه الحالة في مواقع مختلفة وعلى أجهزة تعمل بأنظمة تشغيل متنوعة وقد تستخدم أنواع قواعد بيانات مختلفة كذلك مثل العلاقية أو كائنية التوجه كما أنها قد تستخدم برمجيات إدارة قواعد بيانات مختلفة عن بعضها البعض وقد لا يكون أحد المواقع على علم بوجود المواقع الأخرى للبيانات مما ينتج عنه محدودية في معالجة بعض الطلبات.
		</p>
	</li>
</ul>

<h2>
	الخلاصة
</h2>

<p>
	تعرفنا في مقال اليوم على مفهوم قواعد البيانات وأنواعها المختلفة وألقينا نظرة متعمقة على الطرق المختلفة للتعامل كل نوع من هذه الأنواع مع البيانات وإدارتها وأسلوب تخزينها وتمثيل العلاقات فيما بينها.
</p>

<p>
	كما تعرفنا على حالات استخدام كل نوع من أنواع قواعد البيانات المختلفة، ولك أن تختار من بينها النوع الأنسب لمتطلبات عملك وللمزيد من المعلومات حول ماهية قواعد البيانات وأهميتها وأنواعها المختلفة يمكنك مطالعة مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">دليلك الشامل إلى قواعد البيانات</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">مدخل إلى تصميم قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">المفاهيم الأساسية في قواعد البيانات وتصميمها</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">693</guid><pubDate>Sat, 15 Apr 2023 17:00:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x62A;&#x635;&#x645;&#x64A;&#x645; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_12/639ab70f27443_----.png.41bed027648b7e495f644d5232caed07.png" /></p>
<p>
	منذ بداية ظهور الشبكة العنكبوتية تغيرت حياتنا تغيرًا جذريًا سواء كنا مستهلكين أو مُنتجين اضطررنا لنقل جزء من حياتنا أو أعمالنا إلى هذه الشبكة وسرعان ما أصبحت الشبكة جزءًا رئيسيًا من حياتنا اليومية ومن أنشطتنا التجارية أيضًا، اقتصر الأمر في البداية على الحواسيب ولم تحدث القفزة الكبيرة التي عززت اندماج الإنترنت في عصرنا الحالي إلا عندما تطورت صناعة أجهزة الهواتف المحمولة وانتشرت بأيدي جميع المستهلكين فمنذ أن أعلن ستيف جوبز عن تحفته في عام 2007 وهو جهاز الآيفون ثم انتقلت صناعة الهواتف المحمولة من مجرد جهاز مخصص للاتصالات والتواصل إلى حاسوب شخصي مصغّر قادر على أداء العديد من المهام والوظائف ولكن الأهم من ذلك عرض الإعلانات!
</p>

<p>
	عندما أثبت ستيف جوبز بأنه يمكننا تطوير جهاز حاسوب بحجم كف اليد لم تتغير صناعة الأجهزة الذكية فحسب بل نشأ سوق جديد وهو سوق الأجهزة القابلة للارتداء ليظهر لدينا العديد من الأجهزة الذكية مثل النظارات والساعات والألبسة وأجهزة مراقبة الصحة والكثير من الأجهزة الأخرى كما تطورت الأجهزة الموجودة في الأسواق مثل الشاشات الذكية وأدوات المنزل الذكي.
</p>

<p>
	احتوت جميع الأجهزة الذكية على نظام تشغيل يخزن البيانات ويعالجها ويتتبع بيانات المستخدمين ويعرض بعضها إعلانات تناسب اهتماماتهم. ومع وجود هذا الكم الكبير من الأجهزة الذكية والمواقع والشبكات الاجتماعية أدى ذلك إلى توليد بيانات كبيرة جدًا لأنه في الحقيقة كل حركة حرفيًا يمكن أن تُسجل وتحفظ في قاعدة البيانات فمثلًا سواء كنت جالسًا أما تلفازك الذكي وتقلب القنوات أو ذاهبًا للركض وبيدك ساعة ذكية تراقب حركتك أو حتى عالقًا في سيارتك في وسط زحمة المرور خانقة ومشغلًا ميزة التتبع الجغرافي GPS، فإنك في كل نشاط تقريبًا تولّد بيانات يمكن استثمارها والاستفادة منها.
</p>

<p>
	هذه الوفرة من البيانات غيرت طبيعة المنافسة لطالما استفاد عمالقة التكنولوجيا من تأثير الشبكة فمثلًا كلما زاد عدد مستخدمي شبكة فيسبوك، زادت جاذبية الاشتراك بهذه شبكة. الأمر الذي يساعد على جمع المزيد من البيانات، وبالتالي سيكون لدى الشركة مجال أكبر لتحسين منتجاتها، والذي بدورها تجذب المزيد من المستخدمين وتضاف المزيد من البيانات وهكذا دواليك.
</p>

<p>
	على سبيل المثال، تجمع شركة تسلا البيانات من سياراتها الذاتية مثل معلومات حول السرعة وسجل الشحن والصيانة ومعلومات متنوعة عن أداء النظام الكهربائي للسيارة والكثير من المعلومات الأخرى الدقيقة بالإضافة إلى جمع البيانات الخاصة بنظام القيادة الآلي ولكن مشاركة هذه البيانات اختياري وليس اجباري كما صرحت الشركة، ومن خلال هذه البيانات استطاعت الشركة تطوير ميزات تنافسية مثل تحسين نظام القيادة الذاتية وإمكانية توفير أكثر من 30% من كلفة التأمين على السيارة (في حال مشاركة معلومات القيادة) وفهم أفضل لأنماط القيادة التي يتبعها المستهلكين لذلك من السهل فهم كيف <a href="https://www.csmonitor.com/Business/In-Gear/2013/0927/Is-Tesla-Motors-really-worth-almost-half-the-value-of-GM" rel="external nofollow">استطاعت</a> شركة تسلا أن تصل بقيمتها السوقية إلى نصف قيمة شركة جنرال موتورز وذلك في عام 2013 بالرغم من أن تسلا لم تبع سوى 25 ألف سيارة خلال 10 سنوات بالمقابل باعت شركة جنرال موتورز 450 مليون سيارة على مدى 105 سنة من تاريخ الشركة، بالطبع لا يعود الأمر كله للبيانات ولكن لعبت البيانات جزءًا كبيرًا في تقييم الشركة وهذا يدل على قوة البيانات الضخمة وكيف يمكن أن تساعد الشركات على رفع قيمتها وحفر خنادق حولها لتجنب وصول الشركات المنافسة إليها وإلى عملائها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="117527" href="https://academy.hsoub.com/uploads/monthly_2023_01/smart-car-interface-projection-hologram.jpg.805df938a3c8ed8b952db036d9e71037.jpg" rel=""><img alt="نموذج عن السيارات الذكية بتصميم قواعد البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="117527" data-ratio="66.73" data-unique="xyjc7xqmh" style="width: 550px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_01/smart-car-interface-projection-hologram.thumb.jpg.41d563868affec32f973d6b137350c24.jpg"></a>
</p>

<p>
	ولكن أين تتجمع كل هذه البيانات؟ وهل تخزن جميعها وتستثمر؟ في الحقيقة تعد عملية تجميع البيانات وتنقيتها وفرزها واستخلاص المناسب منها من أصعب العمليات يمكنك تخيل الأمر على أن البيانات هي نفايات وموجودة في مكب نفايات عملاق، كيف يمكننا الاستفادة منها؟ في البداية نحتاج إلى تصميم مكب النفايات ليناسب النفايات الموجودة فيه وهذه هي عملية تصميم قواعد البيانات وبعد أن وضعنا النفايات في المكب سنحتاج إلى آلات لفرز هذه النفايات؟ وهنا يأتي دور عمليات تنقية البيانات وتنقيحها وحذف المكرر منها …إلخ، كلما اعتنينا بطريقة تصميم قواعد البيانات وطرق تنظيفها استفدنا أكثر من هذه البيانات وبالتأكيد كلما حسنا من أي خطوة في هذه السلسة مثل طريقة جمع البيانات من الأساس سهلت الخطوات التي تليها.
</p>

<p>
	سنستعرض في هذا المقال أهمية البيانات في عصرنا الحالي كمجال دراسي واستثمار لأصحاب الشركات على المدى الطويل وسنتعرف على خطوات تصميم قاعدة بيانات وما هي الوظائف المرتبطة بقواعد البيانات؛ وسنتبع التدرج الآتي في عرض عناصره:
</p>

<ol>
	<li>
		البيانات كمحرك رئيسي للتطوير
	</li>
	<li>
		ما هو تصميم قواعد البيانات؟
	</li>
	<li>
		التخصصات المرتبطة بقواعد البيانات
	</li>
	<li>
		من أين أبدأ بتعلم تصميم قواعد البيانات؟
	</li>
	<li>
		التخصص في قطاعات البيانات
	</li>
	<li>
		التوظيف وفرص العمل في تخصصات البيانات
	</li>
	<li>
		اقتصاد البيانات Data Economy
	</li>
</ol>

<h2>
	البيانات كمحرك رئيسي للتطوير
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="114082" href="https://academy.hsoub.com/uploads/monthly_2022_12/data.jpg.19b7371fe42d144dc3bbbeb2092801a6.jpg" rel=""><img alt="البيانات كمحرك رئيسي للتطوير" class="ipsImage ipsImage_thumbnailed" data-fileid="114082" data-unique="k3hmqw89z" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/data.thumb.jpg.243ee7fd1a014371a5668e5e0fc3682f.jpg"></a>
</p>

<p>
	كلما زادت كمية البيانات التي تجمعها الشركات عن مستخدميها زادت قوة هذه الشركات وتحسنت طريقة فهمها لهم لأنه في الواقع أظهرت لنا البيانات السلوك الحقيقي للمستهلكين مثلًا في مجال <a href="https://academy.hsoub.com/entrepreneurship/ecommerce/" rel="">التجارة الإلكترونية</a> وبأن قرارات الشراء الخاصة بهم يمكن جدًا ألا تكون ناجمة عن تخطيط ودراسة وإنما تأثيرات خارجية لا علاقة لها بالمنتج أو الجودة أو السعر بطريقة مباشرة (لمزيد من المعلومات حول القرارات اللاعقلانية للمستهلكين ننصح بقراءة مقال <a href="https://academy.hsoub.com/marketing/core-concepts-of-marketing/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B3%D9%84%D9%88%D9%83-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D9%87%D9%84%D9%83-r481/" rel="">مدخل إلى سلوك المستهلك</a>).
</p>

<p>
	لا يتوقف الأمر عند ذلك فحسب بل إن خوارزميات <a href="https://academy.hsoub.com/files/17-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A-%D9%88%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A2%D9%84%D8%A9/" rel="">الذكاء الاصطناعي Artificial Intelligence وتعلم الآلة Machine Learning</a> تستخلص وتحلل وتستنج معلومات أكبر من حجم البيانات أحيانًا، ويمكن أن تتنبأ الخوارزميات بالوقت الذي يكون فيه العميل جاهزًا للشراء، أو عندما يحتاج محرك السيارة الذكية إلى الصيانة أو عندما يكون الشخص معرضًا لخطر الإصابة بمرض ما عندما تشير ساعته الذكية إلى اضطراب في دقات القلب، ولكن لنعود قليلًا للوراء لنرى الصورة الكبيرة للأمر ونفهم كيف حدث ذلك، وهنا لا بدّ لنا من طرح بعض الأسئلة:
</p>

<ul>
	<li>
		كيف صُممت قواعد البيانات لتتحمل هذه الكميات الكبيرة من البيانات؟
	</li>
	<li>
		ما هي الطرق المستخدمة في التصميم؟
	</li>
	<li>
		هل تصميم قاعدة بيانات لشركة سيارات مثلًا يختلف عن تصميم قاعدة بيانات لمحل تجاري؟
	</li>
	<li>
		هل يجب تعهيد عملية تصميم قواعد البيانات للمختصين؟
	</li>
	<li>
		ما هي الاستثمارات المرتبطة بقاعدة البيانات؟
	</li>
	<li>
		كيف تؤثر قواعد البيانات بقرارات الشركات؟
	</li>
	<li>
		من هم الموظفون الذين يمكن أن نوظفهم لتحقيق أكبر استثمار لقواعد البيانات الخاصة بنا؟
	</li>
	<li>
		هل ستحقق قواعد البيانات العائد على الاستثمار الذي وضعناه بها؟
	</li>
</ul>

<p>
	شكلت هذه الأسئلة وغيرها عقبة في وجه الشركات الناشئة ووضعتها في موقف صعب لأن تصميم قاعدة بيانات تعمّر في هذا الزمن المتسارع يتطلب جهدًا كبيرًا ودراسة مفصلة ولكن لحسن الحظ أن الدليل بين أيدينا ويمكن تطبيقه. هيا بنا لنتعرف على خطوات تصميم وبناء قاعدة بيانات بالتفصيل.
</p>

<h2>
	ما هو تصميم قواعد البيانات؟
</h2>

<p>
	في أي نظام تراه أعيننا (سواء موقع أو متجر إلكتروني أو أي نظام إلكتروني) يوجد مرحلة أولية تشترك بها جميع الأنظمة وهي تصميم قواعد البيانات في هذه المرحلة نخطط لما ستكون عليه الجداول والأعمدة التي تحتويها وأنواع البيانات فيها والعلاقات بين الجداول والقيود المحددة لها وهكذا، ولذلك تحتل مرحلة تصميم قاعدة بيانات أهمية كبيرة في أي نظام ولا بدّ من إجراء تصميم متين ومناسب لكي نستطيع تطويره في المستقبل.
</p>

<p>
	تعد قواعد البيانات Database جزءًا من منظومة معلوماتية أكبر تدعى <strong>نظام المعلومات Information System</strong> والتي هي مجموعة متكاملة من المكونات لجمع البيانات وتخزينها ومعالجتها ولتوفير المعلومات والمعرفة والمنتجات الرقمية. تعتمد الشركات على أنظمة المعلومات لتنفيذ عملياتها وإدارتها، والتفاعل مع عملائها ومورديها، والمنافسة في الأسواق، وتتكون أنظمة المعلومات من الأجهزة والبرمجيات والبيانات والأشخاص والعمليات. تتكامل أنظمة المعلومات مع قواعد البيانات لتشكل لدينا نظامًا معلوماتيًا متكامل الوظائف، تتشابه دورة حياة تطوير الأنظمة Systems Development Life Cycle (ويشار إليه اختصارًا SDLC) مع دورة تطوير قواعد البيانات Database Life Cycle (ويشار إليها اختصارا DBLC)، وهي عملية مستمرة لإنشاء وتصميم قواعد البيانات ونمذجتها وتحسينها وتطويرها وصيانتها.
</p>

<p>
	في الحقيقة هنالك العديد من الأطر المقترحة لدورة تطوير قواعد البيانات لن نناقش الفروقات بينها وإنما سنشرحُ أعم إطار مقترح والذي تكون خطواته على الشكل التالي:
</p>

<ol>
	<li>
		تحليل متطلبات البيانات Data Requirements Analysis
	</li>
	<li>
		تصميم قاعدة البيانات Database Design 3.نمذجة قاعدة بيانات Database Modeling
	</li>
	<li>
		تنفيذ قاعدة البيانات Database Implementation
	</li>
	<li>
		اختبار قاعدة البيانات Database Testing
	</li>
	<li>
		التشغيل وإدارة قاعدة البيانات Database Operation
	</li>
	<li>
		صيانة قاعدة البيانات Database Maintenance
	</li>
</ol>

<h3>
	1. تحليل متطلبات البيانات Data Requirements Analysis
</h3>

<p>
	تبدأ عملية تطوير قاعدة البيانات بتحليل عام لوظائف النظام الذي ستُبنى من أجله ومستخدمي هذا النظام، وطبيعة البيانات المطلوب تخزينها ومعالجتها، والتقارير المطلوب تسليمها في النظام أو المستندات الرسمية بين الأقسام الموجودة؛ لذلك من الضروري جمع الحقائق من خلال المقابلات والاستبيانات والملاحظات وفحص الوثائق المختلفة المعتمدة في الشركة أو أي نظام نحن بصدد تصميم قواعد بيانات له مثل النماذج والتقارير والمستندات الأخرى ذات الصلة، ويمكننا عندها تكوين نظرة أولية لما ستكون عليه قاعدة البيانات بصورة عامة.
</p>

<p>
	يجب تحديد الأهداف أو المشاكل التي نتوقع من النظام أو قاعدة البيانات حلها، ومن المرجح أن ينتج عن كل مشكلة قائمة مرتبطة بها من المشاكل. تتمثل مهمة المصمم في التأكد من أن أهداف نظام وقاعدة البيانات الخاصة به تتوافق مع تلك التي يتصورها صاحب الشركة والمستخدم (المستخدمون) النهائي، بالإضافة إلى ذلك يجب على المصمم الإجابة على الأسئلة التالية:
</p>

<ul>
	<li>
		هل سيشمل تصميم قاعدة البيانات الشركة بأكملها أو قسمًا واحدًا فقط؟
	</li>
	<li>
		هل سيخدم النظام وظيفة واحدة لكل قسم أم كل الوظائف؟
	</li>
	<li>
		هل ستتوسع قاعدة البيانات (أو النظام) ليضيف كل أقسام الشركة؟
	</li>
	<li>
		هل سيتفاعل النظام مع أنظمة أخرى حالية أو مستقبلية في الشركة؟
	</li>
	<li>
		هل سيشارك النظام البيانات مع أنظمة أو مستخدمين آخرين؟
	</li>
	<li>
		ما هو المدة الزمنية المقدرة للتسليم؟
	</li>
	<li>
		ما هي الميزانية المتاحة؟
	</li>
</ul>

<p>
	تساعد الإجابة على هذه الأسئلة في معرفة النطاق والحدود الخاصة بالمشروع إذ يحدد نطاق النظام مدى حجم التصميم المطلوب لكي يعرف المصمم حجم البيانات التقديري. تساعد معرفة النطاق في تحديد هياكل البيانات المطلوبة ونوع الكيانات وعددها والحجم المادي لقاعدة البيانات وما إلى ذلك. يخضع النظام المقترح أيضًا لحدود تُعرف بالحدود الخارجية للنظام، مثل الوقت المتاح للتصميم والميزانية المتاحة. تؤثر النقاط السابقة في كيفية تصميم النظام وقاعدة البيانات المطلوبة وتتمثل مهمة المصمم في تحديد الخيارات الأفضل للنظام ضمن هذه القيود.
</p>

<h3>
	2. تصميم قاعدة البيانات Database Design
</h3>

<p>
	هنالك عدة طرق لتصميم قواعد البيانات كل طريقة لها محاسنها ومساوئها يجب على المحلل النظام ومسؤول قواعد البيانات التحدث والعمل مع المستخدمين لتحديد ما هو مهم للمستخدمين ونتيجة لذلك تحديد البيانات التي يجب تخزينها في قاعدة البيانات. ما يفعله المحلل عادة هو إنشاء بعض النماذج الأولية من التقارير والواجهات الخاصة بالمستخدمين والنماذج لمساعدة المستخدمين على تصور الشكل الذي سيبدو عليه النظام وكيف سيعمل النظام، ومن أبرز طرق تصميم قواعد البيانات نذكر:
</p>

<ul>
	<li>
		تصميم قواعد البيانات من الأعلى إلى الأسفل Top-down Design
	</li>
	<li>
		تصميم قواعد البيانات من الأسفل إلى الأعلى Bottom-up design
	</li>
</ul>

<h4>
	تصميم قواعد البيانات من أعلى إلى أسفل Top-down Design
</h4>

<p>
	ويسمى أيضًا بنموذج التصميم التنازلي وتبدأ هذه الطريقة في التصميم من الأعم إلى الأخص. أي تبدأ بفكرة عامة عما هو مطلوب للنظام ثم تسأل المستخدمين النهائيين عن البيانات التي يحتاجون إلى تخزينها. سيعمل المحلل بعد ذلك مع المستخدمين لتحديد البيانات التي يجب الاحتفاظ بها في قاعدة البيانات، ويتطلب استخدام هذا الأسلوب أن يكون لدى المحلل فهمًا مفصلًا للنظام؛ لأنه في بعض الحالات يمكن أن يؤدي التصميم من أعلى إلى أسفل إلى نتائج غير مرضية لأن المحلل والمستخدمين النهائيين يمكن أن يفوتوا معلومات مهمةً وضرورية للنظام.
</p>

<h4>
	تصميم قواعد البيانات من الأسفل إلى الأعلى Bottom-up Design
</h4>

<p>
	ويسمى أيضًا بنموذج التصميم التصاعدي ويبدأ هذا النهج بالتفاصيل الدقيقة والمحددة للمشروع ويحاول أن يعمم الفكرة. يفحص محلل النظام في البداية جميع واجهات المستخدمين المطلوبة تنفيذها في النظام، بالإضافة إلى التقارير والمعلومات المطلوب عرضها وتخزينها ومعالجتها. سيعمل المحلل بطريقة عكسية من خلال التركيز على التفاصيل الدقيقة والانتقال تباعًا للتفاصيل الأكبر منها.
</p>

<p>
	لفهم الاختلافات بين هذين الأسلوبين لنأخذ بعض الأمثلة عنهما. فمثلًا في أنظمة التحليل الإحصائي يعكف المحللين على أخذ عينة بيانات صغيرة من المجتمع ومن ثم تعميم الفكرة على إجمالي عدد السكان المتبقي. كما يستخدم الأطباء أيضًا النهج التصاعدي إذ يفحصون أعراضًا معينة للمرض ثم يحددون المرض العام الذي تسببه هذه الأعراض، وبالمقابل من الأمثلة التي تتطلب نهجًا تنازليًا هي مهام إدارة المشاريع والمهام الهندسية عمومًا إذ يجب في البداية تحديد المتطلبات العامة قبل فهم التفاصيل الدقيقة فيجب على الشركات الهندسية المصنعة للسيارات اتباع نهج التنازلي لتحقيق المواصفات المطلوبة للسيارة. فمثلًا إذا كان المطلوب أن تبلغ تكلفة السيارة أقل من 17000 دولار أمريكي، وأن تقطع 29 ميلًا للغالون الواحد من البنزين، وتتسع لسبعة أشخاص، فهذه المتطلبات العامة يجب الاعتماد عليها أولًا لتلبية التصميم المتوافق معها والانتقال إلى التفاصيل الدقيقة لتصميم السيارة.
</p>

<p>
	يُنظر عادة للنهجان على أنهما متكاملان إذ كلاهما يوصف التفاعلات التي تحدث في النظام ولكن واحدة ستكون من المنظور الأعلى والأخرى من الأسفل وللمزيد من المعلومات حول كيفية تصميم قواعد البيانات ننصح بقراءة مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%B9%D9%86-%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r597/" rel="">أمثلة عملية عن كيفية تصميم قواعد البيانات</a>.
</p>

<h3>
	3. نمذجة قاعدة بيانات Database Modeling
</h3>

<p>
	هي عملية إنشاء نموذج بيانات للبيانات المراد تخزينها في قاعدة بيانات وتعد النماذج تمثيلًا مبسطًا لكائنات البيانات، والارتباطات والقواعد المختلفة الموجودة بينها، تعد نماذج البيانات تمثيلًا بسيطًا لوصف تراكيب البيانات المعقدة في الحياة العملية على شكل رسومات وأشكال دون التركيز على الجانب التقني وهي وسيلة لتوضيح الأفكار بين المصمم والمبرمج والمدير وجميع أعضاء الفريق.
</p>

<p>
	تساعد نماذج البيانات في تحديد الجداول العلائقية والمفاتيح الأولية والخارجية المطلوبة، كما توفر صورة واضحة للبيانات الأساسية ويمكن لمطوري قواعد البيانات استخدامها لإنشاء قاعدة بيانات فعلية، بالإضافة إلى ذلك تفيد نمذجة البيانات في تحديد البيانات المفقودة والمكررة مما يساعدنا على تقليل عمليات توحيد البيانات Normalization، ويساعد أيضًا على تطوير قاعدة البيانات وصيانتها وإصلاحها وسد الثغرات الموجودة فيها؛ لذلك يعد العمل على النماذج استثمارًا طويل الأمد بالنسبة للجهد والمال، ومن أشهر النماذج المستخدمة في تصميم قواعد البيانات والأنظمة نذكر:
</p>

<ul>
	<li>
		لغة النمذجة الموحدة Unified Modeling Language
	</li>
	<li>
		نموذج الكيان والعلاقة Entity-relationship Model
	</li>
</ul>

<h4>
	لغة النمذجة الموحدة Unified Modeling Language
</h4>

<p>
	ويشار لها اختصارًا UML‏، وهي لغة نمذجة رسومية تقدم صيغة لوصف العناصر الرئيسية للنظم البرمجية. تستخدم هذه اللغة لعمل رسوم تخطيطية لوصف برامج الحاسوب والأنظمة عمومًا وذلك من خلال توصيف العناصر المكونة لها أو خط سير العمليات الذي ينفذه البرنامج. تساعد هذه اللغة على إنشاء النماذج وتصميم نموذج متكامل لأي مشروع برمجي. يوجد نوعان رئيسيان من مخططات UML وهما:
</p>

<ol>
	<li>
		المخططات الهيكلية Structural Diagrams، والذي يحتوي بدوره على المخططات التالية:
		<ul>
			<li>
				مخطط الأصناف Class Diagram.
			</li>
			<li>
				مخطط الحزمة Package Diagram.
			</li>
			<li>
				مخطط الكائنات Object Diagram.
			</li>
			<li>
				مخطط المكونات Component Diagram.
			</li>
			<li>
				مخطط الهيكل المركب Composite Structure Diagram.
			</li>
			<li>
				مخطط النشر Deployment Diagram.
			</li>
		</ul>
	</li>
	<li>
		المخططات السلوكية Behavioral Diagrams، والذي يحتوي بدوره على المخططات التالية:
		<ul>
			<li>
				مخطط النشاط Activity Diagram.
			</li>
			<li>
				مخطط التسلسل Sequence Diagram.
			</li>
			<li>
				مخطط حالات الاستخدام Use Case Diagram.
			</li>
			<li>
				مخطط الحالة State Diagram.
			</li>
			<li>
				مخطط الاتصال Communication Diagram.
			</li>
			<li>
				المخطط التفاعلي العام Interaction Overview Diagram.
			</li>
			<li>
				المخطط الزمني Timing Diagram.
			</li>
		</ul>
	</li>
</ol>

<p>
	تهدف هذه المخططات المتنوعة على تمثيل أنواع عديدة من السيناريوهات والأنظمة وطرق التفاعل بين الكائنات. يمكن أن تكون بعض المخططات أقرب لمنهجية معينة من المخططات الأخرى مثل مخطط الكائنات أقرب للبرمجة كائنية التوجه إلا أنه عمومًا تهدف لغة النمذجة الموحدة إلى توصيف النظام بدون التطرق إلى طريقة تنفيذ البرمجيات.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="114079" href="https://academy.hsoub.com/uploads/monthly_2022_12/639ab70b16f7b_classdiagram.png.4c92842aae96d8f0f851bb79b6f01216.png" rel=""><img alt="تصميم قواعد البيانات لنظام صراف آلي يحتوي 7 أصناف" class="ipsImage ipsImage_thumbnailed" data-fileid="114079" data-unique="7671cnim1" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/639ab70c7e764_classdiagram.thumb.png.6de1654ff432eac18bc35d9dd34749ac.png"></a>
</p>

<p>
	في المثال السابق لدينا نظام صراف آلي يحتوي على 7 أصناف Classes وهي:
</p>

<ol>
	<li>
		البنك Bank
	</li>
	<li>
		الزبون Customer
	</li>
	<li>
		جهاز الصراف الآلي ATM
	</li>
	<li>
		الحساب المجرد Account
	</li>
	<li>
		حساب التوفير (الإدخار) Saving Account
	</li>
	<li>
		حساب جاري Current Account
	</li>
	<li>
		إجراءات الصراف الآلي ATM Transactions
	</li>
</ol>

<p>
	نلاحظ أن هنالك علاقات تربط بين جميع الأصناف لكل تحدد كل علاقة طريقة تفاعل الأصناف مع بعضها بعضًا ويشير كل رمز إلى مصطلح أو مفهوم في البرمجة كائنية التوجه مما يساعد المطور على فهم النظام وتحويله إلى شيفرة برمجية مناسبة، وللمزيد من المعلومات عن هذا المخطط والرموز الموجودة به ننصحك بقراءة مقال <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%AE%D8%B7%D8%B7%D8%A7%D8%AA-%D8%A7%D9%84%D9%81%D8%A6%D8%A7%D8%AA-class-diagram-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D9%88%D8%AD%D8%AF%D8%A9-uml-r307/" rel="">مخططات الفئات (Class Diagram) في لغة النمذجة الموحدة UML</a>.
</p>

<h4>
	نموذج الكيان والعلاقة Entity-relationship Model
</h4>

<p>
	وهو نموذج مجرد لوصف الأشياء المترابطة في مجال معين من المعرفة. يكثر استخدام هذا النموذج عند تمثيل قواعد البيانات وفي هندسة البرمجيات عند تمثيل متطلبات النظام الأولي، بالإضافة إلى ذلك يحتوي هذا النموذج على تفاصيل أقرب للمفاهيم المعلوماتية بالموازنة مع لغة التوصيف الموحدة، وعمومًا يتألف النموذج الكيان والعلاقة من المفاهيم الرئيسية التالية:
</p>

<ol>
	<li>
		الكيان Entity: وهي الجدول -أو الجداول- التي نحتاجها في قاعدة البيانات الخاصة بنا ويمكن أن تشير إلى جدول الطلاب، أو الدورات التعليمية، أو الكتب، أو الموظفين.
	</li>
	<li>
		السمات Attributes: وهي الحقائق أو الأوصاف الخاصة بالكيانات، وغالبًا ما تكون أسماء وتصبح أعمدة في الجدول. فمثلًا بالنسبة لكيان الطلاب يمكن أن تكون السمات هي الاسم الأول والاسم الأخير والبريد الإلكتروني والعنوان وأرقام الهواتف …إلخ. 3.العلاقات Relationship: وهي الارتباطات بين الكيانات وتوصف الأفعال العلاقات بين الكيانات. وهنالك خمسة أنواع من العلاقات وهي:
		<ul>
			<li>
				علاقة واحد إلى واحد One to one Relationship أو ‎1:1
			</li>
			<li>
				علاقة واحد إلى متعدد One to many Relationship أو ‎1:M
			</li>
			<li>
				علاقة متعدد إلى متعدد Many to many Relationship أو ‎M:M
			</li>
			<li>
				علاقة أحادية Unary Relationship
			</li>
			<li>
				علاقة ثلاثية n-ary
			</li>
		</ul>
	</li>
</ol>

<p>
	عند نمذجة نظام من خلال نموذج الكيان والعلاقة يكون لدينا ثلاثة مستويات من التجريد وهي:
</p>

<ol>
	<li>
		نموذج البيانات المفاهيمي Conceptual Data Model.
	</li>
	<li>
		نموذج البيانات المنطقي Logical Data Model.
	</li>
	<li>
		نموذج البيانات المادي Physical Data Model.
	</li>
</ol>

<p>
	في البداية يعمل المحللون والمصممون على بناء نموذج مفاهيمي للبيانات لقاعدة البيانات المطلوبة ومن ثم يحولون النموذج المفاهيمي إلى منطقي ومن ثم إلى مادي وسنستعرض الفروقات بين هذه النماذج لفهم المراحل النمذجة التي تمر بها قاعدة البيانات، وللاسزادة والاطلاع على نموذج الكيان والعلاقة ننصحك بالاطلاع على مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D8%A9-er-%D9%84%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r543/" rel="">نموذج الكيان والعلاقة ER لتمثيل البيانات وتخزينها في قاعدة البيانات</a> الذي يتناول بالتفصيل ويوضح كيفية بناءه. سنشرح سريعًا النماذج الثلاثة الخاصة بنموذج الكيان والعلاقة.
</p>

<h5>
	1. نموذج البيانات المفاهيمي Conceptual Data Model
</h5>

<p>
	تبدأ عملية النمذجة من خلال بناء نموذج بيانات مفاهيمي بعرض منظم لمفاهيم قواعد البيانات وعلاقاتها، ويهدف هذا النموذج إلى إنشاء الكيانات وخصائصها وعلاقاتها بصورة عامة لذلك لا نجد في هذا المستوى من النمذجة أي تفاصيل متاحة حول بنية قاعدة البيانات الفعلية.
</p>

<p>
	عادة ما يبني هذا النموذج أصحاب الشركات التجارية، ومن خصائص نموذج البيانات المفاهيمي نذكر:
</p>

<ul>
	<li>
		يشرح معلومات أساسية ورؤية عامة لقاعدة البيانات أو المشروع.
	</li>
	<li>
		صُمم هذا النوع للأشخاص غير التقنيين من رواد الأعمال وأصحاب الشركات.
	</li>
	<li>
		طوّر هذا النموذج بطريقة مستقلة عن مواصفات الدقيقة لقاعدة البيانات.
	</li>
</ul>

<p>
	لن يشرح هذا النموذج أبدًا التفاصيل التقنية الدقيقة مثل سعة تخزين البيانات أو نوعية قواعد البيانات أو لغات البرمجة أو أنظمة إدارة قواعد البيانات Database Management Systems، وينصبُ تركيزه على تمثيل البيانات كما يراها المستخدم في العالم الحقيقي بدون الدخول للتفاصيل الدقيقة، ويمكن تنفيذها النموذج لاحقًا على أي نظام وقاعدة بيانات نريدها، ويكون النموذج الناتج مشابه للشكل التالي:
</p>

<p style="text-align: center;">
	<img alt="نموذج البيانات المفاهيمي في تصميم قواعد البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="114080" data-unique="19a18bw0j" style="width: 350px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/conceptual-data-model.png.a55229b3ffb0d752d8c1ea99a67c57ba.png">
</p>

<h5>
	2. نموذج البيانات المنطقي Logical Data Model
</h5>

<p>
	يستخدم نموذج البيانات المنطقية لتحديد هيكل عناصر البيانات وتعيين العلاقات فيما بينها، ويضيف نموذج البيانات المنطقي مزيدًا من المعلومات إلى عناصر نموذج البيانات المفاهيمية.
</p>

<p>
	يوفر هذا النموذج الأساس الأولي لتشكيل قاعدة البيانات للنموذج المادي. ومع ذلك، تظل بنية النمذجة عامة نسبيًا، ولن يتحدد في هذا المستوى من النمذجة المفاتيح الأساسية أو الثانوية بين الجداول، ومن خصائص نموذج البيانات المنطقية نذكر:
</p>

<ul>
	<li>
		يصف احتياجات البيانات لمشروع واحد ولكن يمكن أن يتكامل مع نماذج البيانات المنطقية الأخرى بناءً على نطاق المشروع.
	</li>
	<li>
		يصمم هذا النموذج ويطور بطريقة مستقلة عن نظام إدارة قواعد البيانات DBMS.
	</li>
	<li>
		يحتوي التصميم على سمات الكينونات الموجودة كأسماء بدون ذكر السعة أو النوع.
	</li>
	<li>
		تطبق عمليات التوحيد على النموذج لضبط عمليات تكرار البيانات.
	</li>
</ul>

<p>
	يحرص هذا النموذج على تجنب تكرار البيانات من خلال إجراء عملية التوحيد للوصول إلى النموذج الثالث 3NF على الأقل مع العلم أنه يوجد خمسة مراحل لعملية التوحيد، ويكون النموذج الناتج مشابه للشكل التالي:
</p>

<p style="text-align: center;">
	<img alt="نموذج البيانات المنطقي Logical Data Model في تصميم قواعد البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="114086" data-unique="am36vndzi" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/logical-er-model.png.353bad130716322a807eb80582bcc820.png">
</p>

<h5>
	3. نموذج البيانات المادي Physical Data Model
</h5>

<p>
	نبني في هذه المرحلة الشكل النهائي للنموذج المقترح ويتطلب تصميم قاعدة البيانات المادية معرفة جميع التفاصيل الدقيقة ابتداءً من نظام إدارة قواعد البيانات DBMS وطريقة تنظيم السجلات وتنظيم الملفات واستخدام الفهارس …إلخ، يهدف هذا النموذج لتوفير تصميم قاعدة بيانات فعلي الذي يضمن أداءً مناسبًا، ومن خصائص نموذج البيانات المادية نذكر:
</p>

<ul>
	<li>
		يصف نموذج البيانات المادية الحاجة إلى البيانات لمشروع أو تطبيق واحد بالرغم من أنه يتكامل مع نماذج البيانات المادية الأخرى بناءً على نطاق المشروع.
	</li>
	<li>
		يحتوي نموذج البيانات على العلاقات بين الكيانات والتي ستصبح جداول.
	</li>
	<li>
		طوّر هذا النموذج لنسخة محددة من نظام إدارة قواعد البيانات أو طبقًا لتكنولوجيا محددة ما في المشروع.
	</li>
	<li>
		يجب أن تحتوي الأعمدة على أنواع بيانات دقيقة والقيم الافتراضية لبعض البيانات بحسب المطلوب.
	</li>
	<li>
		يحدد هذا النموذج المفاتيح الأساسية والثانوية والخارجية، والفهارس وملفات تعريف الوصول والتراخيص وما إلى ذلك.
	</li>
</ul>

<p style="text-align: center;">
	<img alt="نموذج البيانات المادي Physical Data Model في تصميم قواعد البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="114087" data-unique="n0s1suyd9" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/physical-er-model.png.2d6c22e5e9d2fba2908c0fee08f7a5f0.png">
</p>

<p>
	الهدف الرئيسي لتصميم نموذج المادي هو التأكد من أن كائنات البيانات التي يقدمها المصمم يمكن تمثيلها بدقة في نظام قاعدة البيانات المطلوب. ولمزيد من المعلومات حول طريقة نمذجة البيانات ننصح بقراءة مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r521/" rel="">نمذجة البيانات وأنواعها في عملية تصميم قواعد البيانات</a>.
</p>

<h3>
	4. تنفيذ قاعدة البيانات Database Implementation
</h3>

<p style="text-align: center;">
	<img alt="تنفيذ قاعدة البيانات Database Implementation" class="ipsImage ipsImage_thumbnailed" data-fileid="114085" data-unique="zsyr2xe69" style="width: 550px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/Data_Transfermision.png.f4ed546e16817c8db4790d03c2ac3877.png">
</p>

<p>
	بعد اعتمادنا على التصميم المادي النهائي لقاعدة البيانات وتوضيح جميع أنواع البيانات المطلوبة في هذه المرحلة ننتقل إلى الخطوة التالية وهي تثبيت أنظمة إدارة قواعد البيانات المطلوبة على الخوادم ، وإنشاء قاعدة البيانات ونقل البيانات إليها، ويمكن أن تكون البيانات الأولية إما بيانات جديدة أو بيانات مستوردة من قاعدة بيانات قديمة، وعمومًا تتضمن هذه المرحلة النشاطات التالية:
</p>

<ul>
	<li>
		<strong>تثبيت نظام إدارة قواعد البيانات DBMS</strong>: مثل نظام MySQL أو MongoDB (تحدثنا في مقال مفصل عن <a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-mysql-%D9%88-mongodb-r627/" rel="">الفرق بين MySQL و MongoDB</a> ننصح بالاطلاع عليه) يمكن <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-mysql-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r433/" rel="">تثبيت النظام على خادم محلي</a> أو استخدام خدمة قاعدة بيانات سحابية مثل Microsoft Azure SQL Database Service أو Amazon Relational Database Service (Amazon RDS)‎ أو Google Cloud SQL، يتيح هذا الجيل الجديد من الخدمات السحابية إنشاء قواعد بيانات يمكن إدارتها واختبارها وترقيتها بسهولة حسب الحاجة.
	</li>
	<li>
		<strong>ضبط الإعدادات</strong>: ضبط متغيرات الإعداد وفقًا للأجهزة والبرامج وظروف الاستخدام.
	</li>
	<li>
		<strong>إنشاء قاعدة البيانات والجداول</strong>: يمكن إنشاء قاعدة بيانات باستخدام لغة قاعدة البيانات القياسية، مثل <a href="https://wiki.hsoub.com/SQL" rel="external">لغة الاستعلام المهيكلة SQL</a> الموجودة في نظام إدارة قواعد البيانات MySQL. بالإضافة إلى ذلك قدمت العديد من أنظمة إدارة قواعد البيانات DBMS ميزة الرسم التخطيطي لإنشاء قاعدة البيانات دون الحاجة إلى كتابة تعليمات يدوية، مثل أنظمة Microsoft SQL Server و Microsoft Access و Oracle وغيرها. أو يمكن استخدام حلول خارجية مثل الأداة Erwin وهي (Entity Relationship for Windows) و Embarcadero ER/Studio و SQL Power Architect وغيرها.
	</li>
	<li>
		<strong>تحميل البيانات إلى قاعدة البيانات الجديدة</strong>: يمكن أن نحتاج في بعض الأحيان إلى ترحيل البيانات أو نقلها من قواعد البيانات القديمة إلى الجديدة، وتتطلب هذه الخطوة دراسة وتخطيط دقيقين لتجنب خسارة البيانات. عندما تكون جميع البيانات من نفس النوعية مثل قاعدة البيانات العلائقية فيمكن أن تكون عملية نقل البيانات سريعة وفي حال كانت الأنواع مختلفة عندها سنحتاج إلى عملية تحويل البيانات قبل إدخالها إلى قاعدة البيانات الجديدة.
	</li>
	<li>
		<strong>تطبيق السياسات الأمنية على قاعدة البيانات</strong>: تجهيز وإعداد المستخدمين لبدء العمل وشرح المفاهيم الأمنية والخطوات اللازمة لتطبيقها (مثل الحرص على تسجيل الخروج من نظام قاعدة البيانات عند الانتهاء من العمل) بالإضافة إلى منح المستخدمين المختلفين الذين حددتهم حق الوصول المناسبة بناء على متطلباتهم.
	</li>
	<li>
		<strong>تنفيذ نظام النسخ الاحتياطي</strong>: يفضل أن يكون <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%86%D8%B3%D8%AE-%D8%A7%D9%84%D8%A7%D8%AD%D8%AA%D9%8A%D8%A7%D8%B7%D9%8A-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-r477/" rel="">النسخة الاحتياطية</a> في مخدم آخر وتجنب وضعها على نفس المخدم لأنه في حال حدوث إختراق فعندها سنخسر جميع البيانات.
	</li>
</ul>

<p>
	تهيئ هذه المرحلة قاعدة البيانات لعملية الاختبار النهائي قبل النشر.
</p>

<h3>
	5. اختبار قاعدة البيانات Database Testing
</h3>

<p>
	اختبار قاعدة البيانات هو نوع من اختبار البرامج الذي يتحقق من المخطط والجداول والقوادح Triggers وسلامة البيانات واتساقها وجميع الأمور المتعلقة بها علمًا بأن القوادح هي إجراءات تُنفَّذ في الخلفية آليًا بعد كل عملية إضافة أو تعديل أو حذف على جدول ما، ويمكن أن يتضمن الاختبار إنشاء استعلامات معقدة لقياس كيفية استجابة قاعدة البيانات وقدرتها على معالجة الاستعلامات والتحقق من صحة استجابتها.
</p>

<p>
	يعد اختبار قاعدة البيانات مهمًا لأنه يضمن صحة قيم البيانات والمعلومات المخزنة فيها، ويساعد على تجنب فقدان البيانات وعدم الوصول غير المصرح به إلى المعلومات. يجب أن يكون لدى المختبرين معرفة جيدة بلغة الاستعلام SQL، ويمكن أن تتضمن أنشطة الاختبار ما يلي:
</p>

<ul>
	<li>
		اختبار صحة مخطط قاعدة البيانات.
	</li>
	<li>
		صحة تخزين البيانات في جداول قاعدة البيانات.
	</li>
	<li>
		أنواع الأعمدة وسعتها.
	</li>
	<li>
		المفاتيح الأساسية والثانوية والفهارس.
	</li>
	<li>
		صحة طريقة تنفيذ الإجراءات المرتبطة بالقوادح.
	</li>
	<li>
		التحقق من تكرار البيانات.
	</li>
</ul>

<p>
	كما يمكن إجراء اختبار الحمل Load Testing واختبار الإجهاد Stress Testing واختبار الأمان Security Testing واختبار سهولة الاستخدام Usability Testing واختبار التوافق Compatibility Testing وما إلى ذلك، إذ يساعد اختباري الحمل والإجهاد (يُعرف اختبار إجهاد البيانات أيضًا باسم اختبار التعذيب Torturous Testing أو اختبار التعب Fatigue Testing) على معرفة أداء قاعدة البيانات فمثلًا عندما يكون هنالك ضغطًا كبيرًا على قاعدة البيانات عندها يجب أن تتحمل قاعدة البيانات الكثير من الطلبات ويحب علينا أن نعرف فيما إذا كان هنالك نقطة ما ستنهار قاعدة البيانات عندها، إذ يساعد تحديد نقطة انهيار نظام قاعدة البيانات على معرفة محدودية النظام وإمكانياته وبالتالي جدولة التحديث اللازم له في المستقبل. كما يجب تكثيف الجهود لتجنب الإفراط في استخدام الموارد الموجودة في قاعدة البيانات.
</p>

<h3>
	6. التشغيل وإدارة قاعدة البيانات Database Operation
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="114084" href="https://academy.hsoub.com/uploads/monthly_2022_12/639ab7118fe39_DatabaseOperation.png.dddee6041717eb7aa366f650f7f6a8b8.png" rel=""><img alt="التشغيل وإدارة قاعدة البيانات Database Operation" class="ipsImage ipsImage_thumbnailed" data-fileid="114084" data-unique="lf8tgouu5" style="width: 550px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/639ab713801e7_DatabaseOperation.thumb.png.a024fbb86412e0977ad48b2c47febb5e.png"></a>
</p>

<p>
	تحدث مرحلة التشغيل عند اكتمال الاختبار والاستعداد النهائي لنشر قاعدة البيانات للاستخدام اليومي. يبدأ مستخدمو النظام في تشغيل النظام وتحميل البيانات وقراءة التقارير وما إلى ذلك، ومن الطبيعي جدًا أن تظهر المشاكل في هذه المرحلة، إذ يحتاج المسؤولون في هذه المرحلة إلى الإسراع في صيانة قاعدة البيانات،
</p>

<p>
	يذكر أن هناك العديد من الاستراتيجيات لنشر قاعدة البيانات وغالبًا ما يستخدم نهج النشر المحدود والذي يخفض عدد المستخدمين نسبيًا ولتكون عملية إصلاح الأخطاء سهلة نسبيًا، وبالرغم من كثرة عمليات الاختبار إلى أن المستخدمين غالبًا ما يجدون أخطاء لا تخطر على البال أثناء التطوير كما أن بعض الشركات أيضًا تنشر تطبيقًا تجريبيًا لكي يتجهز المستخدم لمواجهة الأخطاء بدون التأثير على علاقته بالعلامة التجارية هذا الأمر يساعد على حفاظ الشركة على سمعتها ومكانتها في الأسواق، وفي حال استقرار النظام وقاعدة البيانات ينشر التطبيق إلى بقية المستخدمين.
</p>

<p>
	ويمكن أن تتضمن هذه المرحلة ما يلي:
</p>

<ul>
	<li>
		مراقبة عملية تطبيق السياسات الأمنية على قاعدة البيانات والاطلاع على فهم الموظفين لحجم الخطورة الخاصة بالبيانات.
	</li>
	<li>
		مراقبة تنفيذ عمليات النسخ الاحتياطي والتحقق من صحة عملية النسخ الاحتياطي دوريًا.
	</li>
	<li>
		إحصائيات الوصول إلى قاعدة البيانات لتحسين الكفاءة وسهولة استخدام عمليات تدقيق النظام ومراقبة أداء النظام.
	</li>
	<li>
		تلخيص استخدام النظام الشهري أو ربع السنوي أو السنوي لأغراض إعداد الفواتير الداخلية أو الميزانية.
	</li>
</ul>

<p>
	في حال ظهور خطأ ما في قاعدة البيانات ننتقل عندها إلى عملية الصيانة.
</p>

<h3>
	7. صيانة قاعدة البيانات Database Maintenance
</h3>

<p>
	تعد صيانة قاعدة البيانات جزءًا أساسيًا من عمليات تطوير قاعدة البيانات ولها أثر كبير على ديمومة النظام ككل لأن الصيانة الأولية لقاعدة البيانات تقينا من شر إعادة بناء القاعدة من جديد، تتضمن أنشطة الصيانة العديد من المهام المتنوعة، بالإضافة إلى ذلك عند تشغيل قاعدة البيانات وبدء الاعتماد عليها يراقب المسؤول عنها الأداء والسرعة والمشاكل التي يمكن أن تظهر في البداية لمعرفة فيما إذا حققت المعايير المطلوبة الجودة والسلامة.
</p>

<p>
	يجري مسؤولو قاعدة البيانات عمليات صيانة روتينية وتتضمن بعض أنشطة الصيانة الدورية المطلوبة ما يلي:
</p>

<ul>
	<li>
		الصيانة الوقائية (مثل عمليات النسخ الاحتياطي وتغيير كلمات المرور دوريًا).
	</li>
	<li>
		الصيانة التصحيحية (مثل تصحيح الأخطاء المكتشفة عند التشغيل وصيانة أنواع البيانات والفهارس).
	</li>
	<li>
		الصيانة التكيفية (مثل العمل على تحسين الأداء وإضافة الكيانات والسمات وما إلى ذلك).
	</li>
	<li>
		تخصيص أذونات الوصول وصيانتها للمستخدمين الجدد والقدامى (مثل إضافة صلاحيات مخصصة ودقيقة للمستخدمين وإزالة الصلاحيات العامة).
	</li>
	<li>
		عمليات تدقيق أمنية دورية بناءً على الإحصائيات التي ينشئها النظام.
	</li>
</ul>

<p>
	يمكن تكون هناك حاجة إلى تعديلات أخرى لقواعد البيانات مع تغير احتياجات الشركة والمستخدمين، وبالتالي ستستمر دورة الحياة بالمراقبة وإعادة التصميم والتحسين. والآن يمكن أن
</p>

<p>
	إلى هنا نكون فهمنا بالفعل معظم أساسيات تطوير وتصميم قواعد البيانات التي سنحتاج إليها، ولكن ماذا عن أسواق العمل وما الذي يمكن أن يضيفه طلاب التخصصات المرتبطة بقواعد البيانات إلى الشركات القديمة أو الناشئة؟ في الحقيقة هنالك الكثير من التخصصات المرتبطة بقواعد البيانات وكل تخصص يضيف قيمة مختلفة إلى الشركة، وعندما يدرس الطلاب عادة تخصص علوم الحاسوب أو التخصصات التقنية في الجامعة عمومًا لا يتخصص الطالب في مجال معين وإنما تكون التخصصات اختيارية سواء مع أو بعد دراسة علوم الحاسوب، يختار الطالب تخصصًا واحدًا أو اثنين على الأكثر، ثم يدرسونه دراسة معمقة، لذلك سننتقل تاليًا إلى شرح التخصصات المرتبطة بقواعد البيانات التي يمكن لمهندس الحاسوب أو دارس تخصص علم الحاسوب أو أي مجال قريب إليها أن يعمل ويتخصص فيها. كما ستوضح الفقرات التالية أهمية هذه التخصصات لأصحاب شركات المستقبل.
</p>

<h2>
	التخصصات المرتبطة بقواعد البيانات
</h2>

<p>
	لا تكاد توجد شركة في وقتنا الحالي إلا ولديها موظف على الأقل من التخصصات المرتبطة بقواعد البيانات ولا نقصد بذلك الشركات التقنية فقط وإنما جميع الشركات التجارية وهذه فرصة للطلاب لكي يتعلموا الوظائف المتاحة لهم من خلال تأسيس أنفسهم بها لإكمال دراستهم لهذه المجالات سواء كان مع دراستهم الجامعية أو حتى بعد التخرج.
</p>

<p>
	يتزايد اهتمام أصحاب الشركات بتوظيف الأشخاص الذين يساعدون الشركة في بناء وتصميم قاعدة بيانات قوية لأنهم يرون تزايد أهمية تقنيات الذكاء الصنعي وتعلم الآلة في تطوير الشركات وهذه التقنيات تعتمد بالدرجة الأولى على قواعد البيانات وطريقة جمع بيانات العملاء والمستخدمين.
</p>

<p>
	تتنوع تخصصات قواعد البيانات ابتدءًا من مدير قواعد البيانات مرورًا بمحلل أمن المعلومات وانتهاء بمهندس البيانات الضخمة وكل تخصص من هذه التخصصات لديه واجباته ومهامه المتنوعة يمكن أن يتخصص الدراس لتصميم قواعد البيانات في إحدى هذه التخصصات ويعمل بها بعد التخرج، ومن أهم تخصصات قواعد البيانات الوظيفية نذكر:
</p>

<ol>
	<li>
		مدير قواعد البيانات Database Administrator
	</li>
	<li>
		مُنمذج البيانات Data Modeler
	</li>
	<li>
		مطورو ومهندسو البرمجيات Software Developer and Engineer
	</li>
	<li>
		محلل أمن المعلومات Information Security Analyst
	</li>
	<li>
		محلل البيانات Data Analyst
	</li>
	<li>
		عالم البيانات Data Scientist
	</li>
	<li>
		مهندس البيانات الضخمة Big Data Engineer
	</li>
</ol>

<h3>
	1. مدير قواعد البيانات Database Administrator
</h3>

<p>
	يركز مدير قواعد البيانات على إدارة وصيانة كل قواعد بيانات الخاصة بالشركة. يحتاج المرشحون لدور إدارة قاعدة البيانات إلى أسس تقنية قوية لفهم بنية وتكوين قاعدة البيانات وطريقة صيانتها، ويبحث غالبية أصحاب العمل عن أفراد لديهم معرفة وخبرة في لغات وتطبيقات قواعد البيانات العلائقية الرئيسية مثل Microsoft SQL Server وأوراكل Oracle و IBM DB2، ومن المهام مسؤول قاعدة البيانات نذكر:
</p>

<ul>
	<li>
		إدارة ومراقبة وصيانة قواعد بيانات الشركة.
	</li>
	<li>
		إجراء التغييرات والتحديثات والتعديلات المطلوبة للبيانات ولهيكل قاعدة البيانات أيضًا.
	</li>
	<li>
		ضمان أمان قاعدة البيانات وتكاملها واستقرارها وتوفرها عند الطلب.
	</li>
	<li>
		الحفاظ على البنية التحتية للنسخ الاحتياطي والاستعادة لقاعدة البيانات.
	</li>
</ul>

<p>
	يتشابه عمل مدير قواعد البيانات مع مطور قواعد البيانات Database Developer وغالبًا ما يؤدي المهمتين شخص واحد وتكون مهام مطور قواعد البيانات على الشكل التالي:
</p>

<ul>
	<li>
		تصميم قواعد بيانات مستقرة وموثوقة وفعالة.
	</li>
	<li>
		تحسين وصيانة الأنظمة القديمة.
	</li>
	<li>
		تعديل قواعد البيانات حسب الطلبات وإجراء الاختبارات.
	</li>
	<li>
		حل مشكلات استخدام قاعدة البيانات والأعطال.
	</li>
	<li>
		الاتصال بالمطورين لتحسين التطبيقات وإنشاء أفضل الممارسات.
	</li>
	<li>
		جمع متطلبات المستخدم وتحديد الميزات الجديدة.
	</li>
	<li>
		تطوير كتيبات فنية وتدريبية.
	</li>
	<li>
		توفير دعم إدارة البيانات للمستخدمين.
	</li>
	<li>
		التأكد من أن جميع برامج قواعد البيانات تلبي متطلبات الشركة والأداء.
	</li>
	<li>
		البحث واقتراح منتجات وخدمات وبروتوكولات قواعد البيانات الجديدة.
	</li>
</ul>

<p>
	تتشابه وظيفة مديرو قواعد البيانات مع مطوروها إلا أن المدير يشرف عادةً على قواعد البيانات والمستخدمين أيضًا للتأكد من أن المنظومة آمنة ومنظمة وتعمل بكفاءة وسلاسة. ويطور مديرو قواعد البيانات الأنظمة وإجراءات السلامة وإجراءات الإدارة الجيدة للبيانات، ويحللون الأجهزة والبرمجيات لضمان أمن البيانات، والتأكد من أن سياسات الأمان تتوافق مع اللوائح القانونية للشركة أو الحكومات الموجودة بها هذه الشركة. بالإضافة إلى ذلك يدرب مديرو قواعد البيانات زملائهم الموظفين على كيفية استخدام قواعد البيانات والالتزام بإرشادات الأمان وتحديث الأنظمة حسب الحاجة.
</p>

<h3>
	2. منمذج البيانات Data Modeler
</h3>

<p>
	مُنمذج البيانات هو الشخص المسؤول عن تصميم قواعد البيانات وتجهيزها لنشرها للاستخدام وتحديثها وإصلاحها ومراجعتها. عادةً ما يُحلل منمذجو البيانات هياكل أو أنظمة البيانات الموجودة مسبقًا والتعامل مع مشكلات تكرار البيانات وحركة البيانات داخل النظام بصورة عامة، ويسعون لتسهيل عملية استرداد البيانات ضمن نماذج بيانات خاصة بهم، ويتعاونون مع بقية الفريق لإنشاء نماذج وقواعد بيانات لتبقى فترات طويلة ونماذج البيانات المفاهيمية والمنطقية والمادية لجميع أقسام الشركة وذلك لسهولة التحديثات والتطوير في المستقبل.
</p>

<p>
	ويعمل منمذج البيانات مع مهندسي ومحللي البيانات لتنفيذ حلول نمذجة البيانات من أجل تبسيط ودعم إدارة معلومات الشركة، ولضمان نجاحك كمنمذج للبيانات يجب أن يكون لديك معرفة عميقة بطريقة تخزين البيانات في قواعد البيانات، فضلًا عن مهارات التواصل لجمع المعلومات من الموظفين، وعمومًا من مسؤوليات منمذج البيانات نذكر:
</p>

<ul>
	<li>
		تحليل وترجمة احتياجات العمل إلى نماذج قواعد بيانات لبناء حلول طويلة الأمد.
	</li>
	<li>
		تقييم أنظمة البيانات الموجودة.
	</li>
	<li>
		العمل مع فريق التطوير لإنشاء نماذج بيانات وطريقة تدفق البيانات.
	</li>
	<li>
		تطوير أفضل الممارسات لترميز البيانات لضمان الاتساق داخل النظام.
	</li>
	<li>
		مراجعة تعديلات الأنظمة الموجودة للتوافق المتبادل بين قواعد بيانات الشركة.
	</li>
	<li>
		تنفيذ استراتيجيات البيانات وتطوير نماذج البيانات المادية.
	</li>
	<li>
		تحديث النماذج المحلية والبيانات الوصفية وتحسينها.
	</li>
	<li>
		تقييم أنظمة البيانات المنفذة للفروق والتناقضات والكفاءة.
	</li>
	<li>
		استكشاف الأخطاء وإصلاحها وتحسين أنظمة البيانات.
	</li>
</ul>

<h3>
	3. مهندسو ومطورو البرمجيات Software Developer and Engineer
</h3>

<p>
	وهم الأشخاص المتخصصون في تطوير البرمجيات وتطبيقات الأعمال وأنظمة التحكم في الشبكة وأنظمة التشغيل للشركات والمؤسسات. يلتقي مهندسو البرمجيات المحترفون مع العملاء لتحديد احتياجاتهم من البرامج والأنظمة ويعملون على بناء النماذج التصميمية المناسبة للمشروع حسب الطلب سواء مخططات باستخدام لغة النمذجة الموحدة UML أو أي طريقة أخرى، كما يصمم مهندسو البرمجيات مخططات لنظام البرمجي وقاعدة البيانات وينتقلون من التصميم الأولي أو المفاهيمي إلى المنطقي ومن ثم المادي في إطار عملهم على إنتاج البرمجيات، كما يعمل مهندسو البرمجيات على صيانة برمجيات وأنظمة الشركات وإجراء إصلاحات أو تحديثات أو تغييرات أخرى حسب الحاجة، ويساعدوا موظفي الشركة على تعلم كيفية استخدام هذه الأنظمة أو يطرحوا دليل نظري لتعلمها.
</p>

<p>
	يتكامل عمل مهندسي البرمجيات مع مطوري البرمجيات فالأول يخطط لما ستكون عليه البرمجية والثاني ينفذها بالطريقة المناسبة ويتعاونان خلال هذه الرحلة لضمان سيرها وفقًا للمطلوب ومن مسؤوليات مهندسي مطوري البرمجيات نذكر:
</p>

<ul>
	<li>
		تعاون مع الفريق لتصميم الخوارزميات والمخططات الانسيابية.
	</li>
	<li>
		إنتاج شيفرة برمجية نظيفة وفعالة بناءً على المتطلبات.
	</li>
	<li>
		دمج مكونات مختلف برمجيات الشركة مع واجهات برمجة التطبيقات الخارجية.
	</li>
	<li>
		العمل على تصميم برمجيات تتكامل مع قواعد البيانات القديمة.
	</li>
	<li>
		تصميم وتطوير برمجيات قابلة لجمع بيانات المستخدمين وتخزينها بطريقة منظمة في قواعد البيانات.
	</li>
	<li>
		تطوير خطط التحقق من البرمجيات وإجراءات ضمان الجودة.
	</li>
	<li>
		استكشاف أخطاء البرامج الحالية وتصحيحها.
	</li>
	<li>
		جمع وتقييم ملاحظات المستخدم وتنفيذ تحسينات بناء عليها.
	</li>
</ul>

<h3>
	4. محلل أمن المعلومات Information Security Analyst
</h3>

<p style="text-align: center;">
	<img alt="محلل أمن المعلومات  في تصميم قواعد البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="114081" data-unique="mw1haojc7" style="width: 550px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/639ab70f03c87_datasecurity.png.c4c380d49d7f8b9730f1c68400e81829.png">
</p>

<p>
	وهو الشخص المسؤول عن حماية المعلومات من المتسللين والمخترقين والهجمات الإلكترونية عمومًا وتكون الحماية من خلال تحليل قواعد بيانات الشركة ومعرفة هيكلتها وصلاحيات المستخدمين وإذا كان هنالك أي خطأ أو مشكلة ما.
</p>

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

<p>
	كما يجري المحلل في بعض الأحيان عمليات التحاليل الجنائية الحاسوبية لاكتشاف المخترق من خلال تتبع آثار المخترق وجمع البيانات وتحليلها ليبلغ عنها في نهاية المطاف. ويجرب المحلل أيضًا عمليات الهندسة العكسية على البرمجيات؛ لذلك من الطبيعي أن تتطلب وظيفة محلل أمن المعلومات خبرة عالية، وعمومًا من أهم مسؤوليات محلل أمن المعلومات نذكر:
</p>

<ul>
	<li>
		مراقبة الوصول الأمني للموارد.
	</li>
	<li>
		إجراء تقييمات الأمان من خلال اختبار الثغرات الأمنية وتحليل المخاطر.
	</li>
	<li>
		إجراء عمليات التدقيق الأمني الداخلي والخارجي.
	</li>
	<li>
		تحليل الخروقات الأمنية لتحديد السبب الجذري للثغرات.
	</li>
	<li>
		التحديث المستمر لخطط الشركة للاستجابة للحوادث والتعافي من الكوارث.
	</li>
	<li>
		التحقق من أمان موردي برمجيات الجهات الخارجية والتعاون معهم لتلبية متطلبات الأمان.
	</li>
</ul>

<h3>
	5. محلل بيانات Data Analyst
</h3>

<p>
	تعتمد هذه الوظيفة على جمع البيانات لتحديد الاتجاهات التي تساعد قادة الأعمال على اتخاذ قرارات استراتيجية. يركز الانضباط على إجراء التحليلات الإحصائية للمساعدة في الإجابة على الأسئلة وحل المشكلات. يستخدم محلل البيانات لغات الاستعلام مثل <a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D9%82%D8%AF%D9%85-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-sql-r961/" rel="">SQL</a> لعمل استعلامات لقواعد البيانات العلائقية. كما ينظف محلل البيانات البيانات ويضعها في تنسيق قابل للاستخدام، أو التخلص من المعلومات غير ذات الصلة أو غير القابلة للاستخدام أو اكتشاف كيفية التعامل مع البيانات المفقودة.
</p>

<p>
	يعمل محلل البيانات عادةً كجزء من فريق متعدد التخصصات لتحديد أهداف المؤسسة ثم إدارة عملية التنقيب عن البيانات وتنظيفها وتحليلها، وتشمل مسؤوليات محلل البيانات الرئيسية ما يلي:
</p>

<ul>
	<li>
		الاستعلام عن البيانات باستخدام SQL أو Excel.
	</li>
	<li>
		تحليل البيانات والتنبؤ باستخدام الأساليب الإحصائية وتقديم التقارير.
	</li>
	<li>
		إنشاء لوحات معلومات باستخدام برنامج ذكاء الأعمال.
	</li>
	<li>
		إجراء أنواع مختلفة من التحليلات بما في ذلك التحليلات الوصفية أو التشخيصية أو التنبؤية أو الوصفية.
	</li>
	<li>
		تطوير وتنفيذ قواعد البيانات وأنظمة جمع البيانات.
	</li>
	<li>
		الحصول على البيانات من المصادر الأولية والثانوية والحفاظ على أنظمة البيانات.
	</li>
	<li>
		تحديد وتحليل وتفسير الاتجاهات أو الأنماط في مجموعات البيانات المعقدة.
	</li>
	<li>
		العمل مع الإدارة لتحديد أولويات الأعمال واحتياجات المعلومات.
	</li>
	<li>
		تحديد وتعريف فرص تحسين العمليات الجديدة.
	</li>
</ul>

<p>
	يسعى محلل البيانات إلى فهم الأسئلة التي تحتاج الشركة الإجابة عليها ويحدد فيما إذا كانت البيانات تستطيع الإجابة على هذه الأسئلة. يجب أن يفهم المشكلات الفنية المرتبطة بجمع البيانات وتحليل البيانات وإعداد التقارير وأن يكون قادرًا على التعرف على اتجاهات السوق وأنماط البيانات.
</p>

<p>
	يعمل محلل البيانات في الغالب مع البيانات المنظمة Structured Data للشركة مثل البيانات المتوفرة في قواعد البيانات، وينشئ التقارير ولوحات معلومات وتصورات أخرى حول البيانات المرتبطة بالعملاء والعمليات التجارية ويقدم هذه الرؤى للإدارة العليا وقادة الأعمال لدعم صانعي القرار. ومن بعض الأمثلة على البيانات التي يعمل هي احصائيات المخزون وتكاليف النقل والإمداد وأبحاث السوق وهوامش الربح والتكاليف وأرقام المبيعات وما إلى ذلك يمكن استخدام هذه البيانات لمساعدة الشركة في تقدير حصتها في السوق وطبيعة الزبائن والمبيعات وتحسين تكاليف النقل وما شابه.
</p>

<h3>
	6. عالم البيانات Data Scientist
</h3>

<p>
	من أكثر الاختصاصات المرغوبة في وقتنا الحالي ويُعرف عالم البيانات بأنَّه الشخص الذي يستخدم الحواسيب ومعداتها وأنظمة البرمجة والخوارزميات بهدف تحليل البيانات الأولية وتحويلها إلى مجموعة بيانات سهلة القراءة والفهم كما يساهم في حل المشاكل وتفسير الظواهر الفعلية من خلال الاستعانة بنظريات من علوم أخرى مثل الرياضيات ونظم المعلومات والإحصاء وعلوم الحاسوب.
</p>

<p>
	يعود تاريخ نشأة هذا التخصص إلى ما يزيد على ثلاثين عامًا تقريبًا، وأكثر ما يميز عالم البيانات هو قدرته الاكتشاف أثناء سباحته في البيانات. ويجب أن يكون قادرًا على توفير هيكل لكميات كبيرة من البيانات غير النموذجية وجعل التحليل ممكنًا. كما يجب أن يستطيع تحديد مصادر البيانات الثريّة ويضموها إلى مصادر البيانات الأخرى التي يحتمل أن تكون غير مكتملة.
</p>

<p>
	يختلط على البعض مهام محلل البيانات مع عالم البيانات وبالرغم من أهدافهما المشتركة إلا أنه عادةً ما يكون عالم البيانات أكثر انخراطًا في تصميم عمليات نمذجة البيانات، وإنشاء الخوارزميات والنماذج التنبؤية لذلك يمكن أن يمضي علماء البيانات وقتًا أطول في تصميم الأدوات وأنظمة التشغيل الآلية وأطر البيانات. بالإضافة إلى ذلك يكون عالم البيانات أكثر تركيزًا على تطوير أدوات وطرق جديدة لاستخراج المعلومات التي تتطلبها الشركة لحل المشكلات المعقدة.
</p>

<p>
	يتطلب كلا المسارين درجة البكالوريوس -على الأقل- في مجالات متعلقة بالرياضيات مثل الرياضيات أو <a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">علوم الحاسوب</a> أو الإحصاء. يمكن أن يقضي محلل البيانات الكثير من الوقت في التحليل الروتيني، وتقديم التقارير بانتظام. بينما عالم البيانات بتصميم طريقة تخزين البيانات ومعالجتها وتحليلها. ببساطة يستنتج المحلل المعلومات المنطقية من البيانات الموجودة بينما يعمل عالم البيانات على طرق جديدة لالتقاط وتحليل البيانات وتسليم هذه الطرق للمحللين.
</p>

<p>
	يستخدم علماء البيانات عادةً لغات البرمجة مثل <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون Python</a> و<a href="https://academy.hsoub.com/programming/r-language/%D9%84%D8%BA%D8%A9-r-%D9%88%D8%A7%D9%84%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%A5%D8%AD%D8%B5%D8%A7%D8%A6%D9%8A-r80/" rel="">لغة R</a>، بينما يستخدم محلل البيانات لغة SQL أو <a href="https://academy.hsoub.com/apps/productivity/office/microsoft-excel/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-microsoft-excel-%D9%88%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%85%D8%B5%D9%86%D9%81-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r25/" rel="">برنامج Excel</a> للاستعلام عن البيانات أو تنظيفها أو فهمها. كما تختلف التقنيات والأدوات التي يستخدمونها لنمذجة البيانات، ومن المهم ملاحظة أنه يمكن أن يستخدم بعض المحللين المحترفين لغات البرمجة أو يدخلون إلى مجال عالم البيانات أو مجال مهندس البيانات الضخمة.
</p>

<p>
	يُنشئ علماء البيانات المحترفون نماذج التعلم الإحصائي لتقنيات البحث الخاصة بهم، والبحث عن أحدث اتجاهات التكنولوجيا والبيانات في السوق، وتعلم وسائل جديدة لتحليل البيانات لسهولة المراجعة والتواصل والتعاون مع الأقسام الأخرى داخل شركاتهم لمساعدتهم في إيجاد الحلول، مراجعة البيانات الأخرى أو تعليمهم كيفية قراءة البيانات. لذلك <a href="https://hbr.org/2012/10/data-scientist-the-sexiest-job-of-the-21st-century" rel="external nofollow">اعتبرت</a> مجلة هارفارد بزنس ريفيو أن وظيفة عالم البيانات هي الوظيفة الأكثر إثارة وجاذبية في القرن الحادي والعشرين.
</p>

<p>
	أصبح قسم البيانات جزءًا أساسيات للعديد من الشركات كما يتضمن هذا القسم الأنشطة الأساسية مثل بناء قواعد البيانات المستدامة وإدارتها واستثمارها …إلخ، لأن القيمة التي تقدمها البيانات تصلح لأن تكون استثمارًا طويل الأمد هذا الأمر أدى ذلك إلى زيادة الطلب على علماء البيانات المهرة في مختلف الصناعات والمهن، وعمومًا من مهام عالم البيانات نذكر:
</p>

<ul>
	<li>
		تحديد مصادر البيانات ذات الصلة باحتياجات العمل.
	</li>
	<li>
		جمع البيانات المهيكلة وغير المهيكلة والبحث عن البيانات المفقودة وتعزيز عملية جمع البيانات.
	</li>
	<li>
		تنظيم البيانات في تنسيقات سهلة للاستخدام.
	</li>
	<li>
		بناء النماذج التنبؤية وخوارزميات التعلم الآلي.
	</li>
	<li>
		معالجة البيانات وتنقيتها والتحقق منها لإيجاد الأخطاء والمشاكل وحذفها باستخدام لغات البرمجة (مثل Python أو R).
	</li>
	<li>
		تحليل البيانات عن الاتجاهات والأنماط وإيجاد إجابات لأسئلة محددة.
	</li>
	<li>
		إنشاء البنية التحتية للبيانات.
	</li>
	<li>
		تطوير وتنفيذ وصيانة قواعد البيانات.
	</li>
	<li>
		تقييم جودة البيانات وإزالة البيانات أو تنظيفها.
	</li>
	<li>
		توليد المعلومات والأفكار من مجموعات البيانات وتحديد الاتجاهات والأنماط.
	</li>
	<li>
		إعداد التقارير للفرق التنفيذية وفرق المشروع.
	</li>
	<li>
		إنشاء تصورات للبيانات.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/r-language/%D9%84%D8%BA%D8%A9-r-%D9%88%D8%A7%D9%84%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%A5%D8%AD%D8%B5%D8%A7%D8%A6%D9%8A-r80/" rel="">التحليل الإحصائي</a> باستخدام خوارزميات التعلم الآلي مثل معالجة اللغة الطبيعية أو الانحدار اللوجستي أو kNN أو Random Forest أو تعزيز التدرج.
	</li>
</ul>

<p style="text-align: center;">
	<img alt="عالم البيانات Data Scientist" class="ipsImage ipsImage_thumbnailed" data-fileid="114083" data-unique="5rua880s4" style="width: 550px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/data1.png.30b280e5a048bfe9f48b5e522facfadc.png">
</p>

<p>
	يواجه المدراء تحديًا حقيقيًا في معرفة كيفية تحديد تلك موهبة عالم البيانات، وكيفية جذبها إلى الشركة وجعلها منتجة. وبالرغم من أننا ذكرنا المهام الرئيسية لعالم البيانات إلا أنه يوجد ضبابية في معرفة كيفية أداء عالم البيانات وكيف يمكنه إضافة أكبر قدر من القيمة بالموازنة مع الأدوار الوظيفية الأخرى القديمة مثل المبيعات، بالإضافة إلى ذلك لا يوجد الكثير من الجامعات التي تقدم هذه الاختصاص الدقيق الأمر الذي يجعل عملية العثور على الشخص المناسب أكثر صعوبة؛ في الحقيقة يمكن تفسير هذه الصعوبات في أنها السبب المنطقي لارتفاع راتب عالم البيانات!
</p>

<h3>
	7. مهندس البيانات الضخمة Big Data Engineer
</h3>

<p>
	يعد وظيفة محلل أو مهندس البيانات الضخمة من أرقى الوظائف التي تتعلق بقواعد البيانات ولفهم <a href="https://academy.hsoub.com/questions/17056-%D9%83%D9%8A%D9%81-%D8%A3%D8%B5%D8%A8%D8%AD-%D8%B9%D8%A7%D9%84%D9%85-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%83%D8%A8%D9%8A%D8%B1%D8%A9%D8%9F/" rel="">كيف يمكن أن تصبح مهندس بيانات ضخمة</a>، دعنا نفهم في البداية معنى "البيانات الضخمة" Big Data. في أوائل العقد الأول من القرن الحادي والعشرين كان توليد البيانات محدودًا ولكن مع ظهور العديد من منصات الشبكات الاجتماعية والشركات العملاقة مثل فيسبوك وأمازون زادت ازديادًا كبيرًا <a href="https://www.statista.com/statistics/871513/worldwide-data-created/" rel="external nofollow">فوفقًا</a> لموقع Statista من المتوقع أن يصل الحجم الإجمالي للبيانات العالمية إلى 97 زيتابايت (أي 10<sup>21</sup> بايت) في عام 2022 وسيصل في عام 2025 إلى 181 زيتابايت. وهذا بالفعل قدر كبير من البيانات.
</p>

<p style="text-align: center;">
	<img alt="مهندس البيانات الضخمة Big Data Engineer في تصميم قواعد البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="114088" data-unique="7hg759vpu" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_12/639ab716b33a5_Totaldatavolumeworldwide2010-2025Statista.png.05f1c05cec5c70a4f7f5b57e1a8d5345.png">
</p>

<p>
	تتطلب البيانات الضخمة نهجًا هندسيًا مختلفًا عن البيانات العادية (مثل البيانات المهيكلة في قواعد البيانات) لأنها عبارة عن أطنان من المعلومات المختلطة وغير المهيكلة التي تتراكم باستمرار وبسرعة عالية، ولهذا السبب لا تستطيع طرق نقل البيانات التقليدية إدارة تدفق البيانات الضخمة بكفاءة. تعزز البيانات الضخمة تطوير أدوات جديدة لنقل وتخزين وتحليل كميات هائلة من البيانات غير المهيكلة. تعمل الشركات البارزة في العديد من القطاعات بما في ذلك المبيعات والتسويق والبحث والرعاية الصحية على جمع البيانات الضخمة بنشاط. كما يواجهون نقصًا في الخبرة اللازمة لإدارتها. لذلك شهدنا نموًا كبيرًا في الفترة الماضية لوظائف هندسة البيانات الضخمة وهي في الحقيقة تتطلب مهارات ضخمة أيضًا!
</p>

<p>
	يعكف مهندس البيانات الضخمة على استخراج البيانات من مصادر مختلفة وتحويلها وتحميلها على مستودع مركزي يُعرف أيضًا باسم مستودع البيانات Data Warehouse، تُخزن البيانات في هذه المستودعات لتكون جاهزة للاستخدام من فريق البيانات سواء محللين أو علماء …إلخ. غالبًا ما تكون وظيفة مهندس البيانات الضخمة خلف الكواليس وهم فعليًا الأشخاص الذين يبنون الطرق والجسور، لأنهم يجهزون البنية التحتية للبيانات الضخمة. ومن بعض مسؤولياتهم نذكر:
</p>

<ul>
	<li>
		تصميم بنية منصة البيانات الضخمة.
	</li>
	<li>
		الحفاظ على خط أنابيب البيانات.
	</li>
	<li>
		تخصيص وإدارة أدوات التكامل وقواعد البيانات والمستودعات والأنظمة التحليلية.
	</li>
	<li>
		إدارة وتنظيم البيانات.
	</li>
	<li>
		إعداد أدوات الوصول إلى البيانات لعلماء البيانات.
	</li>
	<li>
		الاجتماع مع المديرين لتحديد احتياجات البيانات الضخمة للشركة.
	</li>
	<li>
		تحميل مجموعات البيانات المتباينة وإجراء خدمات المعالجة المسبقة باستخدام Hive أو Pig.
	</li>
	<li>
		إنهاء نطاق النظام وتقديم حلول البيانات الضخمة.
	</li>
	<li>
		إدارة الاتصالات بين النظام الداخلي وبائعي البيانات (مثل بائعي الاستبيانات أو المقابلات …إلخ).
	</li>
	<li>
		التعاون مع فرق البحث والتطوير الخاصة بالبرمجيات.
	</li>
	<li>
		بناء منصات سحابية لتطوير تطبيقات الشركة.
	</li>
	<li>
		تدريب الموظفين على إدارة موارد البيانات.
	</li>
</ul>

<p>
	يجب أن يكون مهندس البيانات الضخمة ماهرًا جدًا في العديد من المجالات ومن أبرز هذه المجالات نذكر:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">البرمجة Programming</a>: تعد مهارة البرمجة بديهية في قطاعات التكنولوجيا لأن البرمجة هي الطريقة المثلى لفهم كيفية التعامل مع البيانات فجميع الأجهزة والأنظمة التي حولنا ما هي إلا برمجيات وخوارزميات مختلفة صنعت لتعمل بطريقة معيّنة. يحتاج مهندس البيانات الضخمة إلى خبرة عملية في أي لغة برمجة مشهورة مثل لغة <a href="https://academy.hsoub.com/tags/%D9%85%D8%AF%D8%AE%D9%84%20%D8%A5%D9%84%D9%89%20%D8%AC%D8%A7%D9%81%D8%A7/" rel="">جافا Java</a> أو <a href="https://academy.hsoub.com/programming/cpp/" rel="">C++‎</a> أو <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون Python</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">التعامل مع قواعد البيانات ولغات SQL</a>: بعد البرمجة تأتي المعرفة العميقة بمفاهيم قواعد البيانات وأنظمة إدارة قواعد البيانات DBMS و<a href="https://academy.hsoub.com/programming/sql/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-sql-r844/" rel="">لغة SQL</a>. تعد مهارة التعامل مع قواعد البيانات أساسية ساعد هذا في فهم كيفية إدارة البيانات والحفاظ عليها في قاعدة بيانات. تحتاج إلى معرفة كيفية كتابة استعلامات SQL لأي نظام إدارة قواعد بيانات علائقية مثل MySQL و Oracle Database و Microsoft SQL Server.
	</li>
	<li>
		التعامل مع مستودعات البيانات وعمليات تكامل البيانات ETL: تتمثل إحدى المسؤوليات الأساسية لمهندس البيانات الضخمة في تنفيذ عمليات ETL وهي عمليات استخراج وتحويل وتحميل Extract-Transform-Load البيانات إلى مستودع البيانات. لهذا، ستحتاج إلى معرفة كيفية إنشاء مستودع بيانات وكذلك استخدامه. ستستخرجُ البيانات من مصادر مختلفة، وتحول إلى معلومات ذات مغزى، وتحمل إلى مخازن بيانات أخرى. بعض الأدوات المستخدمة لهذا الغرض هي Talend و IBM Datastage و Pentaho و Informatica.
	</li>
	<li>
		<a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">التعامل مع أنظمة التشغيل Operating Systems</a>: المهارة الرابعة التي تحتاجها هي معرفة أنظمة التشغيل. أدوات التشغيل هي الأساس لتشغيل أدوات البيانات الضخمة. ومن ثم فإن الفهم القوي لأنظمة Unix و Linux و Windows و Solaris أمر إلزامي.
	</li>
	<li>
		التعامل مع أدوات وأطر المخصصة للبيانات الضخمة: يجب أن يكون لديك خبرة في التحليلات المستندة إلى Hadoop والتي تعد واحدةً من أكثر أدوات هندسة البيانات الضخمة استخدامًا، لذلك من المفهوم أنك بحاجة إلى خبرة في التقنيات القائمة على Apache Hadoop مثل HDFS و MapReduce و Apache Pig و Hive و Apache HBase.
	</li>
	<li>
		التعامل مع أطر العمل أطر معالجة في الزمن الفعلي Real-time: يجب أن يكتسب مهندس البيانات الضخمة طريقة العمل مع أطر المعالجة في الوقت الفعلي مثل Apache Spark والتي تتعامل مع كميات هائلة من البيانات في الزمن الحقيقي إذ يمكنها معالجة البيانات التي تأتي من البث المباشر من عدة مصادر مثل Twitter و Instagram و Facebook وما إلى ذلك.
	</li>
	<li>
		التنقيب عن البيانات والنمذجة Data Mining and Modeling: إن مهارة التنقيب عن البيانات ومناقشة البيانات وتقنيات نمذجتها هي أساسية في مجال هندسة البيانات الضخمة. تتضمن عمليات التنقيب عن البيانات والجدل في البيانات خطوات للمعالجة المسبقة وتنظيف البيانات باستخدام طرق مختلفة والعثور على الاتجاهات والأنماط غير المرئية في البيانات وجعلها جاهزة للتحليل.
	</li>
</ul>

<p>
	والآن بعد أن تعرفنا على أهم الاختصاصات المتعلقة بقواعد البيانات لنستكشف كيف يمكننا الدخول في هذا العالم الشيّق.
</p>

<h2>
	من أين أبدأ بتعلم تصميم قواعد البيانات؟
</h2>

<p>
	غالبًا ما تتضمن التخصصات الجامعية مثل علوم الحاسب وهندسة البرمجيات أو ما يشابهها من التخصصات على مواد تتعلق بقواعد البيانات يتعلم الطالب من خلالها أساسيات تصميم قواعد البيانات، وفي حال ليس لديك اطلاع على هذه أساسيات سنستعرض في هذه الفقرة المواضيع اللازمة لكل مرحلة تعليمية كما سننصحُ ببعض المقالات أو الكتب أو المساقات الدراسية.
</p>

<h3>
	المفاهيم الأساسية في قواعد البيانات
</h3>

<p>
	في البداية لا بد من التعرف على أساسيات تصميم قواعد البيانات والتي سيكون المواضيع على الشكل التالي:
</p>

<ol>
	<li>
		مفاهيم أساسية في قواعد البيانات:
		<ul>
			<li>
				أنظمة الملفات التقليدية وعيوبها.
			</li>
			<li>
				تعريف قاعدة البيانات خصائصها ومميزاتها.
			</li>
			<li>
				الفرق بين البيانات Data والمعلومات Information والمعرفة Knowledge.
			</li>
			<li>
				أنواع قواعد البيانات.
			</li>
			<li>
				أدوات قواعد البيانات
			</li>
			<li>
				لغات قواعد البيانات.
			</li>
			<li>
				أنواع أنظمة إدارة قواعد البيانات Database Management Systems.
			</li>
		</ul>
	</li>
	<li>
		مفاهيم نظام قواعد البيانات والهندسة المعمارية
		<ul>
			<li>
				دورة حياة نظام المعلومات Systems Development Life Cycle.
			</li>
			<li>
				تطوير دورة حياة نظام قاعدة البيانات Database Life Cycle.
			</li>
		</ul>
	</li>
	<li>
		- مفهوم نمذجة تصميم قاعدة البيانات.
		<ul>
			<li>
				النمذجة باستخدام لغة النمذجة الموحدة Unified Modeling Language.
			</li>
			<li>
				النمذجة باستخدام الكيان والعلاقة Entity-Relationship.
			</li>
			<li>
				النموذج الكيان والعلاقة المحسّن Enhanced Entity-Relationship.
			</li>
			<li>
				المفاهيم المتقدمة في نموذج الكيان والعلاقة المحسّن (التعميم والتخصيص والتصنيف والميراث).
			</li>
		</ul>
	</li>
	<li>
		مفاهيم أساسية لتحسين التصميم:
		<ul>
			<li>
				الاعتماديات الوظيفية Functional Dependency.
			</li>
			<li>
				قواعد الاستدلال Inference Rules.
			</li>
			<li>
				عمليات التوحيد Normalization (النموذج الأول 1NF والثاني 2NF ..إلخ).
			</li>
			<li>
				مفهوم الجبر العلائقي Relational Algebra نشأته وأهميته.
			</li>
			<li>
				عمليات الجبر العلائقي.
			</li>
		</ul>
	</li>
</ol>

<p>
	بعض المصادر المناسبة العربية:
</p>

<ul>
	<li>
		كتاب <a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تصميم قواعد البيانات</a>.
	</li>
	<li>
		كتاب <a href="https://academy.hsoub.com/files/16-%D9%85%D9%84%D8%A7%D8%AD%D8%B8%D8%A7%D8%AA-%D9%84%D9%84%D8%B9%D8%A7%D9%85%D9%84%D9%8A%D9%86-%D8%A8%D9%84%D8%BA%D8%A9-sql/" rel="">ملاحظات للعاملين بلغة SQL 1.0.0</a>
	</li>
	<li>
		كتاب <a href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL</a>.
	</li>
	<li>
		توثيق <a href="https://wiki.hsoub.com/SQL" rel="external">لغة SQL</a>.
	</li>
</ul>

<h3>
	المفاهيم المتقدمة في قواعد البيانات
</h3>

<p>
	بعد أن تعرفنا على المفاهيم الأساسية سننتقل لاستعراض المواضيع المتقدمة المتعلقة بتصميم قواعد البيانات:
</p>

<ol>
	<li>
		إدارة الإجراءات أو المعامَلَات Transaction Management والتحكم في التزامن Concurrency Control
		<ul>
			<li>
				ماهية الإجراء وتعريفه وخصائصه وحالاته.
			</li>
			<li>
				إدارة الإجراءات من خلال لغة SQL وسجل الإجراءات وطرق استردادها.
			</li>
			<li>
				مفاهيم التحكم في التزامن (التحديثات المفقودة Lost Updates - البيانات غير المثبتة Uncommitted Data - عمليات الاسترجاع غير المتسقة Inconsistent Retrievals).
			</li>
			<li>
				المجدول The Scheduler.
			</li>
			<li>
				التحكم في التزامن بطرق القفل Concurrency Control with Locking Methods
			</li>
			<li>
				التحكم في التزامن مع خلال Time Stamping.
			</li>
			<li>
				التحكم في التزامن بأساليب متفائلة.
			</li>
			<li>
				مستويات ANSI لعزل الإجراءات.
			</li>
			<li>
				إدارة عملية استعادة قاعدة البيانات.
			</li>
		</ul>
	</li>
	<li>
		ضبط أداء قاعدة البيانات وتحسين الاستعلام
		<ul>
			<li>
				مفاهيم ضبط أداء قاعدة البيانات
			</li>
			<li>
				هيكلية أنظمة إدارة قواعد البيانات
			</li>
			<li>
				أوضاع تحسين استعلام قاعدة البيانات
			</li>
			<li>
				إحصائيات قاعدة البيانات
			</li>
			<li>
				معالجة الاستعلام (طريقة تحليل استعلام SQL وتنفيذه وجلبه).
			</li>
			<li>
				مشاكل الاستعلام (اختناقات معالجة الاستعلام - الفهارس وتحسين الاستعلام).
			</li>
			<li>
				خيارات المحسن (استخدام التلميحات للتأثير على اختيارات المحسن).
			</li>
			<li>
				ضبط أداء SQL (انتقائية المؤشر - التعبيرات الشرطية).
			</li>
			<li>
				صياغة الاستعلام
			</li>
			<li>
				ضبط أداء DBMS
			</li>
		</ul>
	</li>
	<li>
		أنظمة إدارة قواعد البيانات الموزعة Distributed Database Management Systems:
		<ul>
			<li>
				تطور نظم إدارة قواعد البيانات الموزعة.
			</li>
			<li>
				خصائص أنظمة إدارة قواعد البيانات الموزعة ومكونات ومزاياها وعيوبها.
			</li>
			<li>
				المعالجة الموزعة وقواعد البيانات الموزعة.
			</li>
			<li>
				مستويات البيانات وتوزيع العمليات.
			</li>
			<li>
				الأداء وشفافية قاعدة البيانات الموزعة (شفافية التوزيع - شفافية المعاملات - شفافية الفشل).
			</li>
			<li>
				الطلبات الموزعة والإجراءات الموزعة (التحكم في التزامن الموزع - بروتوكول الالتزام ثنائي الطور).
			</li>
			<li>
				تصميم قاعدة البيانات الموزعة.
			</li>
			<li>
				مفاهيم أساسية عند تصميم قاعدة البيانات الموزعة (تجزئة البيانات Data Allocation - تكرار البيانات Data Replication - تخصيص البيانات Data Fragmentation).
			</li>
		</ul>
	</li>
	<li>
		إدارة وأمن قواعد البيانات Database Administration and Security:
		<ul>
			<li>
				مفاهيم متقدمة في أمن قواعد البيانات (نُهج الأمن Security Policies - ترقيع ثغرات أمنية).
			</li>
			<li>
				عناصر أمن قواعد البيانات ودورها (الأشخاص People - محطات العمل والمخدمات Workstation and servers - أنظمة التشغيل Operating system - التطبيقات Applications - الشبكة Network - البيانات Data).
			</li>
			<li>
				الفرق بين الحماية الأمنية في الأنظمة المجانية والمدفوعة.
			</li>
			<li>
				أدوات إدارة قواعد البيانات.
			</li>
			<li>
				الفرق بين إدارة قواعد العادية والسحابية.
			</li>
			<li>
				أهمية قاموس البيانات Data Dictionary في نهج الإدارة.
			</li>
			<li>
				تطوير إستراتيجية إدارة البيانات.
			</li>
		</ul>
	</li>
</ol>

<p>
	أحد المصادر الجيدة التي تفيدك باللغة الإنكليزية كتاب Database Systems: Design, Implementation, &amp; Management الطبعة الثالثة عشر لصاحبيه Steven Morris و Carlos Coronel.
</p>

<h2>
	التخصص في قطاعات البيانات
</h2>

<p>
	سنستعرض في هذا القسم المفاهيم الأساسية المشتركة في التخصصات المرتبطة بالبيانات وهي على الشكل التالي:
</p>

<ol>
	<li>
		ذكاء الأعمال ومستودعات البيانات Business Intelligence and Data Warehouses:
		<ul>
			<li>
				الحاجة إلى تحليل البيانات.
			</li>
			<li>
				مفاهيم أساسية في ذكاء الأعمال (هندستها ومزاياها وتطورها ومستقبلها).
			</li>
			<li>
				مفاهيم أساسية بيانات دعم القرار (البيانات التشغيلية - بيانات دعم القرار).
			</li>
			<li>
				الفرق بين قواعد البيانات Database ومستودعات البيانات Data Warehouse وبحيرة البيانات Data Lake ومتاجر البيانات Data Mart.
			</li>
			<li>
				متطلبات قاعدة بيانات دعم القرار.
			</li>
			<li>
				مخطط النجمة Star Schemas (حقائق Facts - الأبعاد Dimensions - السمات Attributes).
			</li>
			<li>
				معالجة وتحليل البيانات عبر الإنترنت Online Analytical Processing.
			</li>
			<li>
				تقنيات تحليل البيانات متعددة الأبعاد.
			</li>
			<li>
				الفرق بين (تحليل البيانات Data Analytics - التنقيب في البيانات Data Mining - التحليلات التنبؤية Predictive Analytics).
			</li>
			<li>
				البيانات المرئية Data Visualization (أهمتيها - علم تصور البيانات The Science of Data Visualization).
			</li>
		</ul>
	</li>
	<li>
		البيانات الضخمة و NoSQL:
		<ul>
			<li>
				مفاهيم أساسية حول البيانات الضخمة (الحجم Volume - السرعة Velocity - التنوع Variety).
			</li>
			<li>
				قواعد البيانات المخصصة للبيانات الكبيرة (مثل NoSQL).
			</li>
		</ul>
	</li>
	<li>
		قواعد البيانات السحابية Cloud Database:
		<ul>
			<li>
				مفاهيم أساسية في اتصال قواعد البيانات وتقنيات الويب.
			</li>
			<li>
				اتصال قاعدة البيانات (ODBC و DAO و RDO).
			</li>
			<li>
				خدمات الحوسبة السحابية (خصائصها وأنواعها والفروقات بينها).
			</li>
			<li>
				أنواع قواعد البيانات السحابية.
			</li>
			<li>
				كيفية الانتقال إلى السحابة.
			</li>
			<li>
				الفرق بين قواعد البيانات القابلة للإدارة Self-Managed وقواعد البيانات المُدارة آليًا Managed Databases.
			</li>
			<li>
				كيف تتغير مهام مدير قواعد البيانات في السحابة.
			</li>
			<li>
				أمان البيانات والتطبيقات في السحابة.
			</li>
			<li>
				نقل قواعد البيانات الخاصة بك إلى السحابة (التخطيط Planning - نقل البيانات Data Movement - التحسين Optimization).
			</li>
		</ul>
	</li>
</ol>

<p>
	بعض المصادر باللغة العربية:
</p>

<ul>
	<li>
		كتاب <a href="https://academy.hsoub.com/files/17-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A-%D9%88%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A2%D9%84%D8%A9/" rel="">مدخل إلى الذكاء الصنعي وتعلم الآلة</a>.
	</li>
	<li>
		كتاب الحوسبة السحابية أساسيات ومبادئ وتطبيقات للدكتور خالد بن ناصر آل حيان.
	</li>
</ul>

<h2>
	التوظيف وفرص العمل في تخصصات البيانات
</h2>

<p>
	يعد برنامج البكالوريوس أو المرحلة الجامعية الأولى الوسيلة التقليدية والشائعة للدخول في مجال البيانات ويمكن أن يختار بعض الطلاب إكمال دراستهم الجامعية والحصول على درجة الماجستير في المعلوماتية وعلوم البيانات في سعيهم للدخول في هذا المجال إلى أن هذا الطريق ليس الوحيد لدخول مجال البيانات، ولكن ظهرت في الآونة الأخيرة دورات تدريبية مركزة وتسمى أيضًا معسكرات تدريبية BootCamps وهي عبارة عن منهج دراسي مكثف قصير الأمد يركز على المهارات المركزة والمستندة إلى السوق بدلًا من أخذ مقدمات في مختلف التخصصات كما يحدث في برامج البكالوريوس، وبالرغم من أن المعسكرات التدريبية في بدايتها كانت تحتاج للتواجد الفيزيائي للطلاب مع الاساتذة إلى أن المشهد اليوم اختلف وأصبحت بالإمكان إجراء المعسكرات عبر الإنترنت عن بعد.
</p>

<p>
	في <a href="https://www.indeed.com/lead/what-employers-think-about-coding-bootcamp" rel="external nofollow">دراسة</a> أجراها موقع إنديد Indeed جاء فيها أن 72% من أرباب العمل الذين شملهم الاستطلاع يعتقدون بأن خريجي معسكرات التدريب المستجدين مستعدين تمامًا ليكونوا ذوي أداء عالٍ مثل المرشحين الحاصلين على درجات علمية في علوم الحاسوب، كما يعتقد 12% من مدراء التوظيف بأن خريجي المعسكرات التدريبية أكثر استعدادًا من أقرانهم المدربين في الجامعات.
</p>

<p>
	علاوة على ذلك، يعتقد العديد من أصحاب العمل أن حضور المعسكر التدريبي يمنح المتعلمين ميزة تنافسية. ففي <a href="https://info.hackerrank.com/rs/487-WAY-049/images/HackerRank-2020-Developer-Skills-Report.pdf" rel="external nofollow">استطلاع</a> أجراه موقع هكر رانك HackerRank عام 2020 على مدراء التوظيف جاء فيه أنه ما يقرب من ثلاثة أرباع مديري التوظيف الذين شملهم الاستطلاع قالوا بأن معسكرات التدريب يمكن أن تُعلم الطلاب تقنيات ولغات جديدة بسرعة، واستشهد 61% من المدراء الذين شملهم الاستطلاع بالخبرة العملية لطلاب المعسكرات التدريبية، وقال 52% بأن خريجي المعسكرات التدريبية متحمسون لتحمل مسؤوليات جديدة.
</p>

<p>
	يمكن للطلاب الراغبين في الدخول إلى مجال البيانات ولا يريدون هدر وقتهم في الجامعات أن يبدأوا بتعلم <a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">علوم الحاسب</a> والتي يأخذ فيها الطالب نظرة شاملة، عملت أكاديمية حسوب على توفير دورة متكاملة عن أساسيات علوم الحاسوب هي <a href="https://academy.hsoub.com/learn/computer-science/" rel="">دورة علوم الحاسوب</a> وهي دورة شاملة مدتها أكثر من 53 ساعة تشرح هذه الدورة مختلف المفاهيم بدءًا من أبسط الأساسيات أساسيات الحاسوب وعلومه والتفكير المنطقي وما هي الخوارزميات وكيف تفيد في البرمجة وتشرح الدورة أيضًا:
</p>

<ul>
	<li>
		الخوارزميات وهياكل البيانات: والتي ستساعدنا على فهم الطريقة الصحيحة لتنظيم البيانات.
	</li>
	<li>
		البرمجة: التي ستساعدنا على كيفية التلاعب بالبيانات ومحتواها من خلال كتابة الشيفرات البرمجية بلغة بايثون Python لتعديل محتويات البيانات.
	</li>
	<li>
		تصميم وبناء قواعد البيانات: والتي تفيدنا في التأسيس إلى مجال البيانات مع شرح تفصيلي للغة SQL للتعامل معها ونظرة على قواعد بيانات NoSQL.
	</li>
	<li>
		تطوير الويب: والتي على فهم المفاهيم الأساسية التي تبنى فيها صفحات الويب.
	</li>
	<li>
		إدارة الخوادم: والتي ستساعدنا في فهم ماهية المعلومات التي يمكن أن نجمها
	</li>
</ul>

<p>
	بالإضافة إلى ذلك مفاهيم متقدمة مثل البرمجة الكائنية ومفاهيمها المختلفة الأساسية والمتقدمة عبر لغة بايثون كما ستتعلم أيضًا أنماط التصميم Design Patterns، كما أنها في تحديث وتوسعة مستمرة، ومن أبرز ميزاتها أن هناك من يتابع سَيْرَك ويجيبُ على أسئلتك على امتداد الدورة وليس فقط مجرد فيديوهات تسلسلة ولذلك فهي دورة يُبنى عليها.
</p>

<p style="text-align: center;">
	<iframe allowfullscreen="" frameborder="0" height="450" src="https://player.vimeo.com/video/409436178" width="650"></iframe>
</p>

<p>
	أضف إلى ذلك أنه يمكنك العمل كعامل <a href="https://mostaql.com/" rel="external">مستقل</a> على حسب الاختصاص الذي تجيده من اختصاصات البيانات؛ فلو كنت مدير أو مطور قواعد بيانات فيمكنك استعراض الفرص المتاحة عبر مواقع العمل الحر مثل <a href="https://mostaql.com/projects?skills=database-programming" rel="external">مستقل</a>، ففي العمل الحر لن يسألك أحد بتاتًا عن شهادتك الجامعية وكل ما سيسألونك عنه هو خبراتك ونماذج لأعمالك السابقة نفذتها لا أكثر.
</p>

<p>
	أما عن فرص العمل المتوفرة في الشركات فهي تختلف باختلاف البلدان والشركات التي تريد العمل فيها، ولكنها تنضوي جميعًا تحت قسم التخصصات الذي تحدثنا فيه بصورة موسعة عن تخصصات قواعد البيانات انظر مثلًا إلى موقع <a href="https://baaeed.com/" rel="external nofollow">بعيد</a>، ستجدُ فيه طلبات توظيف من شركات مختلفة حول العالم العربي، وستجد أن معظم الوظائف لا تشترط أي نوع من أنواع الشهادات، بل تشترط معرض أعمال وخبرة سابقة فقط.
</p>

<p>
	وتكون رواتب المتخصصين في البيانات متعلقة بعدة عوامل منها التخصص والخبرة والأعمال المنجزة ويدخل في الحساب أيضًا اختلاف الشركات والأماكن والدول، لكن يمكننا القول بصورة عامة أن رواتبهم أعلى من المهندسين الآخرين، ويمكنك البحث عن المواقع التي تَعرِض لك متوسط الرواتب التي يتلقاها الموظفون حسب المهنة في بلدك ثم البحث فيها عن التخصصات السابقة لرؤية مُعدّل الرواتب في بلدك.
</p>

<h2>
	اقتصاد البيانات Data Economy
</h2>

<p>
	لا يخفَ على أحد الكميات الكبيرة التي تولدها الأجهزة الذكية وشبكات التواصل الاجتماعي وجميع أنشطة مستخدمي الإنترنت ولم تشكل هذه البيانات الضخمة أداة مساعدة لعمل الشركة فقط وإنما أصبحت أصلًا Asset من أصول الشركة مثلها مثل أجهزة الحواسيب والمكاتب …إلخ، إذ فرضت هذه الأصول -غير الملموسة- نفسها كحقيقة لا مفر منها في تقييم الشركات، فمثلًا إذا اطلعنا على <a href="https://www.cnbc.com/2021/06/28/facebook-hits-trillion-dollar-market-cap-for-first-time.html" rel="external nofollow">القيمة السوقية</a> لشركة فيسبوك (غيرت الشركة اسمها لتصبح ميتا Meta) في عام 2021 سنجد بأنها وصلت إلى تريليون دولار، بينما <a href="https://www.macroaxis.com/invest/ratio/FB/Book-Value-Per-Share" rel="external nofollow">بلغت</a> قيمة أصولها الملموسة مثل المباني والعقارات والأجهزة والحواسيب …إلخ، نحو 150.7 مليار دولار، نلاحظ أن الفرق بين القيمتين يصل إلى 849.3 مليار دولار أمريكي، إلا أنه لا يمكننا قياس قيمة البيانات الحقيقية نظرًا لأن الشركة لها العديد من المنتجات الرقمية غير الملموسة مثل نظام الإعلان المؤتمت ونظام المتاجر الإلكترونية وغيرها، ولكن هذا الأمر يضعنا بطريقة غير مباشرة أمام سؤال مهم وجوهري وهو <strong>كيف نحدد قيمة البيانات؟</strong>
</p>

<p>
	هل يمكننا اعتبار كمية البيانات كمصدر لقيمتها؟ أم أن تنوع البيانات له أهمية أكبر؟ ولكن ماذا عن جودة البيانات هل لها أهمية تُذكر؟ إذا أردنا الحصول على أجوبة دقيقة لا بدّ لنا من فهم دقيق لماهيّة <strong>اقتصاد البيانات Data Economy</strong>: والذي هو القيمة المالية والاقتصادية التي ينتجها تخزين كميات ضخمة من البيانات التجارية والحكومية وتحليلها واسترجاعها بسرعة كبيرة من خلال برمجيات معقدة وأدوات أخرى. سيساعدنا هذا التعريف في الانطلاق في فهم هذا الاقتصاد الجديد، وبالتأكيد لا يمكننا شرح كيفية تقييم سعر البيانات من خلال فقرة بسيطة لأن الأمر يحتاج إلى مقالات بل كتب!
</p>

<p>
	ازدادت النقاشات بين أوساط الاقتصاديين حول كيفية حساب قيمة البيانات والمعلومات كأصول غير ملموسة في الميزانيات، لا توجد حتى اليوم طريقة معتمدة عالميًا توفر حلًا واضحًا لتقدير قيمة البيانات والمعلومات وكل الحلول المطروحة هي اجتهاد من المستثمرين أو الباحثين، وبالرغم من أن بعض الأصول غير الملموسة الأخرى مثل براءات الاختراع وحقوق النشر وقوائم العملاء والعلامات التجارية وحقوق البث وغيرها، قابلة للإدراج في الميزانيات ولها طريقة في حساب قيمتها.
</p>

<p>
	في الحقيقة لا يقتصر جهلنا على قيمة البيانات فقط وإنما حتى القوانين الناظمة لها من جمع البيانات أو تنظيمها أو تداولها كل هذه الأمور ماتزال غير واضحة في بعض البلدان ويعود سبب البطء في سن القوانين هو لتجنب إعاقة الابتكار والذي بدوره يبطئ من دوران عجلة الاقتصاد. ولكن مما لا شك فيه أن الدول والشركات ستستفيد من من هذه الأصول وستُشكل بيانات المواطنين في يوم من الأيام إيرادات مستقلة تعزز من خزينة الدولة. يذكر أن قيمة سوق البيانات الضخمة <a href="https://www.researchandmarkets.com/reports/2228010/big_data_global_market_trajectory_and_analytics" rel="external nofollow">قدرت</a> بحسب موقع Research And Markets بنحو 70 مليار دولار أمريكي لعام 2020 كما توقع يصل قيمة السوق في عام 2027 إلى 243.4 مليار دولار أمريكي أي بمعدل نمو سنوي مركب قدره 10.2٪.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تعرفنا في المقال على أهمية البيانات في عصرنا الحالي ومن هذه الأهمية جاءت <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%87%D9%85%D9%8A%D8%A9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">أهمية قواعد البيانات</a> التي تحتوي البيانات وتنظمها وكيف انبثق فروع جديدة من فروع علوم الحاسب وهو علوم البيانات وتصميم قواعد البيانات وإدارة قواعد البيانات …إلخ، كما اطلعنا في هذا المقال على خطوات تصميم قاعدة بيانات واستعرضنا بعدها التخصصات المرتبطة بالبيانات لننتهي بفهم كيف ستُنشئ البيانات الضخمة أسواقًا جديدة وختامًا بالرغم من أن منطقتنا العربية لا يوجد بها الكثير من الاستثمارات في البيانات إلا أن هذا الحال سيتغير في المستقبل القريب ولذلك استثمر الفرصة وكن من السباقين إلى هذا المجال.
</p>

<h2>
	المصادر
</h2>

<ul>
	<li>
		كتاب Database Systems: Design, Implementation, &amp; Management الطبعة الثالثة عشر لصاحبيه Steven Morris و Carlos Coronel.
	</li>
	<li>
		مقال <a href="https://online.visual-paradigm.com/knowledge/visual-modeling/conceptual-vs-logical-vs-physical-data-model" rel="external nofollow">Data Modeling: Conceptual vs Logical vs Physical Data Model</a>.
	</li>
	<li>
		مقال <a href="https://www.guru99.com/data-modelling-conceptual-logical.html" rel="external nofollow">Data Modelling: Conceptual, Logical, Physical Data Model Types</a> لصاحبه David Taylor.
	</li>
	<li>
		تقرير <a href="https://www.seagate.com/files/www-content/our-story/trends/files/idc-seagate-dataage-whitepaper.pdf" rel="external nofollow">The Digitization of the World From Edge to Core</a>.
	</li>
	<li>
		تقرير <a href="https://www.statista.com/statistics/871513/worldwide-data-created/" rel="external nofollow">Volume of data/information created, captured, copied, and consumed worldwide from 2010 to 2025</a>.
	</li>
	<li>
		مقال <a href="https://www.geeksforgeeks.org/top-10-high-paying-jobs-that-demand-sql/" rel="external nofollow">Top 10 High Paying Jobs That Demand SQL - GeeksforGeeks</a> لمحرري الموقع.
	</li>
	<li>
		مقال <a href="https://learnsql.com/blog/types-of-database-jobs/" rel="external nofollow">Types of Database Jobs: Choose One of Them and Start Being Awesome</a> لصاحبه Jakub Romanowski.
	</li>
	<li>
		مقال <a href="https://www.guru99.com/data-testing.html" rel="external nofollow">Database (Data) Testing Tutorial with Sample Test Cases</a> لصاحبه Thomas Hamilton.
	</li>
	<li>
		مقال <a href="https://www.softwaretestinghelp.com/database-testing-process/" rel="external nofollow">Database Testing Complete Guide (Why, What, and How to Test Data)</a> لمحرري الموقع.
	</li>
</ul>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">دليلك الشامل إلى قواعد البيانات DataBase</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%B9%D9%86-%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r597/" rel="">أمثلة عملية عن كيفية تصميم قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r521/" rel="">نمذجة البيانات وأنواعها في عملية تصميم قواعد البيانات</a>
	</li>
	<li>
		النسخة العربية الكاملة من كتاب <a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تصميم قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">أنواع قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">665</guid><pubDate>Sat, 17 Dec 2022 17:05:00 +0000</pubDate></item><item><title>&#x625;&#x62C;&#x631;&#x627;&#x621; &#x639;&#x645;&#x644;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x647;&#x62C;&#x64A;&#x631; &#x648;&#x625;&#x646;&#x634;&#x627;&#x621; &#x639;&#x644;&#x627;&#x642;&#x629; &#x645;&#x62A;&#x639;&#x62F;&#x62F;-&#x625;&#x644;&#x649;-&#x645;&#x62A;&#x639;&#x62F;&#x62F; &#x628;&#x64A;&#x646; &#x627;&#x644;&#x62C;&#x62F;&#x627;&#x648;&#x644; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Sequelize</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%A5%D8%AC%D8%B1%D8%A7%D8%A1-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%87%D8%AC%D9%8A%D8%B1-%D9%88%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B9%D9%84%D8%A7%D9%82%D8%A9-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF-%D8%A5%D9%84%D9%89-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-sequelize-r657/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/636378918b467_-------.png.d4ec1348cc2368d4b774d832a0c01497.png" /></p>

<p>
	نلقي نظرةً في هذا المقال على الطرق المتبعة في نقل التغييرات التي تجري أثناء جلسة العمل إلى قاعدة البيانات العلاقية وتخزينها، إضافةً إلى ربط الجداول ببعضها من خلال المفاتيح الخارجية foreign keys.
</p>

<h2>
	ملفات التهجير Migrations
</h2>

<p>
	لنتابع في توسعة تطبيق الملاحظات الذي عملنا عليه في كل من مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%B9%D9%84%D8%A7%D9%82%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-sequelize-r655/" rel="">العمل مع قواعد بيانات علاقية باستخدام Sequelize</a> و<a href="https://academy.hsoub.com/devops/servers/databases/%D8%B6%D9%85-%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B4%D8%AA%D8%B1%D9%83%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-sequelize-r656/" rel="">المقال السابق</a>، إذ سننجز آليةً تمكّن بعض المستخدمين الذي يمتلكون ميزةً إدارية admin status من إيقاف نشاط مستخدمين آخرين ومنعهم من تسجيل الدخول أو إنشاء ملاحظات جديدة. نحتاج لإنجاز الأمر إلى حقل يأخذ قيمًا منطقيةً في جدول <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة البيانات</a> يشير إلى المستخدمين ذوي الامتيازات الإدارية وأخرى تدل على حالة المستخدم إن كان نشاطه معلقًا أم لا.
</p>

<p>
	يمكننا العمل وفق الآلية السابقة بتعديل النموذج الذي يعرّف الجدول والاعتماد على مكتبة Sequelize في مزامنة التغييرات مع قاعدة البيانات من خلال أسطر الشيفرة التالية في الملف "models/index.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_10" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./note'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./user'</span><span class="pun">)</span><span class="pln">

</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">belongsTo</span><span class="pun">(</span><span class="typ">User</span><span class="pun">)</span><span class="pln">
</span><span class="typ">User</span><span class="pun">.</span><span class="pln">hasMany</span><span class="pun">(</span><span class="typ">Note</span><span class="pun">)</span><span class="pln">

</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">sync</span><span class="pun">({</span><span class="pln"> alter</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
</span><span class="typ">User</span><span class="pun">.</span><span class="pln">sync</span><span class="pun">({</span><span class="pln"> alter</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Note</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ولكن يُعد هذا الأسلوب (تغيير النموذج كلما أردنا توسعة التطبيق) غير منطقي على المدى الطويل، لهذا سنزيل الأسطر التي تدعم مزامنة التغييرات ونستخدم أسلوبًا أكثر قوةً وهو ملفات التهجير <a href="https://sequelize.org/master/manual/migrations.html" rel="external nofollow">migrations</a> التي تقدمها Sequelize وغيرها من المكتبات.
</p>

<p>
	ملف التهجير migration عمليًا هو ملف <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">جافاسكربت JavaScript</a> وحيد يصف التعديلات التي تطرأ على قاعدة البيانات، وينشأ عن تغير وحيد أو مجموعة تغيرات معًا. تحتفظ Sequelize بسجلات عن التهجيرات التي أجريت، أي التغيرات التي طرأت وجرى نقلها ومزامنتها مع قاعدة البيانات، إذ تبقى Sequelize مطلّعةً على التغيرات التي طرأت على مخطط قاعدة البيانات ولم تُطبّق بعد عند إنشاء تهجير جديد، ويمكن بهذه الطريقة التحكم بطريقة تطبيق التغييرات من خلال شيفرة البرنامج المخزنة في منظومة التحكم بالإصدار version control.
</p>

<p>
	لننشئ أولًا ملف تهجير يهيئ قاعدة البيانات. إليك شيفرة هذا الملف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_13" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  up</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">createTable</span><span class="pun">(</span><span class="str">'notes'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      content</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">TEXT</span><span class="pun">,</span><span class="pln">
        allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">BOOLEAN
      </span><span class="pun">},</span><span class="pln">
      date</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">DATE
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">createTable</span><span class="pun">(</span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      username</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">STRING</span><span class="pun">,</span><span class="pln">
        unique</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">STRING</span><span class="pun">,</span><span class="pln">
        allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">addColumn</span><span class="pun">(</span><span class="str">'notes'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'user_id'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
      allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  down</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">dropTable</span><span class="pun">(</span><span class="str">'notes'</span><span class="pun">)</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">dropTable</span><span class="pun">(</span><span class="str">'users'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<a href="https://sequelize.org/docs/v6/other-topics/migrations/#migration-skeleton" rel="external nofollow">يعرِّف</a> الملف الدالتين <code>up</code> و <code>down</code>؛ إذ تحدّد الأولى كيفية تعديل قاعدة البيانات عندما يجري تهجير؛ وتحدد الثانية آلية التراجع إن كان هناك مبررٌ لذلك.
</p>

<p>
	يتضمن ملف التهجير ثلاثة خيارات؛ إذ يُنشئ الخيار الأول الجدول <code>notes</code>؛ بينما ينشئ الثاني الجدول <code>users</code>؛ ويضيف الخيار الثالث مفتاحًا خارجيًا إلى الجدول <code>notes</code> يشير إلى مُنشئ الملاحظة، وتُحدَّد التغيرات في المخطط باستدعاء توابع الكائن <a href="https://sequelize.org/master/manual/query-interface.html" rel="external nofollow"><code>queryInterface</code></a>.
</p>

<p>
	و على نقيض النماذج، من الضروري أن تتذكر دائمًا كتابة أسماء الأعمدة والجداول بأسلوب الأفعى snake case عند تعريف ملف تهجير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_15" style="">
<span class="pln">await queryInterface</span><span class="pun">.</span><span class="pln">addColumn</span><span class="pun">(</span><span class="str">'notes'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'user_id'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
  allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	أي ستكتب أسماء الجداول والأعمدة كما تظهر تمامًا في قاعدة البيانات، بينما تُكتب في النماذج بالأسلوب التقليدي للمكتبة Sequelize وذلك عبر استخدام أسلوب سنام الجمل camel Case. خزّن شيفرة ملف التهجير في ملف يحمل الاسم "migrations/20211209_00_initialize_notes_and_users.js". لا بُد أن تُسمى ملفات التهجير أبجديًا عند إنشائها كي تكون التغيرات القديمة قبل الجديدة، وقد تبدأ اسم الملف بتاريخ وتسلسل هذا الملف وهذه طريقةٌ جيدة.
</p>

<p>
	يمكننا تشغيل ملف التهجير انطلاقًا من سطر الأوامر باستخدام <a href="https://github.com/sequelize/cli" rel="external nofollow">أداة سطر الأوامر الخاصة بالمكتبة Sequelize</a>، لكننا قررنا تنفيذ التهجيرات يديويًا انطلاقًا من شيفرة البرنامج باستخدام المكتبة <a href="https://github.com/sequelize/umzug" rel="external nofollow">Umzug</a>، لهذا سنثبت هذه المكتبة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_17" style="">
<span class="pln">npm install umzug</span></pre>

<p>
	لنعدّل الملف "util/db.js" الذي يتكفل بمعالجة الاتصال مع قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_19" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> DATABASE_URL </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./config'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Umzug</span><span class="pun">,</span><span class="pln"> </span><span class="typ">SequelizeStorage</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'umzug'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> sequelize </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">(</span><span class="pln">DATABASE_URL</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dialectOptions</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      require</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      rejectUnauthorized</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> runMigrations </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> migrator </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Umzug</span><span class="pun">({</span><span class="pln">
    migrations</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      glob</span><span class="pun">:</span><span class="pln"> </span><span class="str">'migrations/*.js'</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    storage</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">SequelizeStorage</span><span class="pun">({</span><span class="pln"> sequelize</span><span class="pun">,</span><span class="pln"> tableName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'migrations'</span><span class="pln"> </span><span class="pun">}),</span><span class="pln">
    context</span><span class="pun">:</span><span class="pln"> sequelize</span><span class="pun">.</span><span class="pln">getQueryInterface</span><span class="pun">(),</span><span class="pln">
    logger</span><span class="pun">:</span><span class="pln"> console</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

 </span><span class="kwd">const</span><span class="pln"> migrations </span><span class="pun">=</span><span class="pln"> await migrator</span><span class="pun">.</span><span class="pln">up</span><span class="pun">()</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Migrations up to date'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    files</span><span class="pun">:</span><span class="pln"> migrations</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">mig</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> mig</span><span class="pun">.</span><span class="pln">name</span><span class="pun">),</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> connectToDatabase </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await sequelize</span><span class="pun">.</span><span class="pln">authenticate</span><span class="pun">()</span><span class="pln">
    </span><span class="com">// highlight-start</span><span class="pln">
    await runMigrations</span><span class="pun">()</span><span class="pln">
    </span><span class="com">// highlight-end</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'connected to the database'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'failed to connect to the database'</span><span class="pun">)</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> connectToDatabase</span><span class="pun">,</span><span class="pln"> sequelize </span><span class="pun">}</span></pre>

<p>
	تُنفّذ الدالة <code>runMigrations</code> ملف التهجير في كل مرة يؤسِّس فيها التطبيق اتصالًا مع قاعدة بيانات عند تشغيله، كما تراقب مكتبة Sequelize التهجيرات المُكتملة، فإذا لم يكن هناك تهجيرات جديدة، فلن ينفع تشغيل الدالة <code>runMigrations</code> في أي شيء.
</p>

<p>
	لنبدأ كل شيء من جديد، ونزيل كل الجداول الموجودة من التطبيق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_21" style="">
<span class="pln">username </span><span class="pun">=&gt;</span><span class="pln"> drop table notes</span><span class="pun">;</span><span class="pln">
username </span><span class="pun">=&gt;</span><span class="pln"> drop table users</span><span class="pun">;</span><span class="pln">
username </span><span class="pun">=&gt;</span><span class="pln"> \d
</span><span class="typ">Did</span><span class="pln"> not find any relations</span><span class="pun">.</span></pre>

<p>
	عند تشغيل التطبيق، تظهر رسالةً على الطرفية تحيطك علمًا بوضع التهجيرات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_24" style="">
<span class="pln">INSERT INTO </span><span class="str">"migrations"</span><span class="pln"> </span><span class="pun">(</span><span class="str">"name"</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="pln">$1</span><span class="pun">)</span><span class="pln"> RETURNING </span><span class="str">"name"</span><span class="pun">;</span><span class="pln">
</span><span class="typ">Migrations</span><span class="pln"> up to date </span><span class="pun">{</span><span class="pln"> files</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="str">'20211209_00_initialize_notes_and_users.js'</span><span class="pln"> </span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
database connected</span></pre>

<p>
	إذا أعدنا تشغيل التطبيق، سيُظهر السجل أن التهجير لم يتكرر، وسيبدو مخطط قاعدة بيانات التطبيق على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_26" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> \d
                 </span><span class="typ">List</span><span class="pln"> of relations
 </span><span class="typ">Schema</span><span class="pln"> </span><span class="pun">|</span><span class="pln">     </span><span class="typ">Name</span><span class="pln">     </span><span class="pun">|</span><span class="pln">   </span><span class="typ">Type</span><span class="pln">   </span><span class="pun">|</span><span class="pln">     </span><span class="typ">Owner</span><span class="pln">
</span><span class="pun">--------+--------------+----------+----------------</span><span class="pln">
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> migrations   </span><span class="pun">|</span><span class="pln"> table    </span><span class="pun">|</span><span class="pln"> username
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> notes        </span><span class="pun">|</span><span class="pln"> table    </span><span class="pun">|</span><span class="pln"> username
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> notes_id_seq </span><span class="pun">|</span><span class="pln"> sequence </span><span class="pun">|</span><span class="pln"> username
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> users        </span><span class="pun">|</span><span class="pln"> table    </span><span class="pun">|</span><span class="pln"> username
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> users_id_seq </span><span class="pun">|</span><span class="pln"> sequence </span><span class="pun">|</span><span class="pln"> username</span></pre>

<p>
	وهكذا نرى أن Sequelize قد أنشأت جدولًا للتهجيرات يسمح بتتبع ما نُفِّذ منها، ويبدو هذا الجدول على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_28" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> select </span><span class="pun">*</span><span class="pln"> from migrations</span><span class="pun">;</span><span class="pln">
                   name
</span><span class="pun">-------------------------------------------</span><span class="pln">
 </span><span class="lit">20211209</span><span class="pln">_00_initialize_notes_and_users</span><span class="pun">.</span><span class="pln">js</span></pre>

<p>
	دعونا نضيف الآن بعض المستخدمين إلى قاعدة البيانات، إضافةً إلى مجموعة من الملاحظات، وبعدها نكون جاهزين لتوسعة التطبيق.
</p>

<p>
	يمكنك الحصول على شيفرة التطبيق بوضعه الحالي من <a href="https://github.com/fullstack-hy/part13-notes/tree/part13-6" rel="external nofollow">المستودع المخصص له على GitHub</a> ضمن الفرع part13-6.
</p>

<h2>
	مستخدم بصلاحيات مدير وتعطيل مستخدم آخر
</h2>

<p>
	علينا بدايةً إضافة حقلين يقبلان قيمًا منطقية إلى الجدول <code>users</code>، هما:
</p>

<ul>
<li>
		<code>admin</code>: ويحدد فيما لو كان المستخدم مديرًا أم لا.
	</li>
	<li>
		<code>disabled</code>: ويحدد فيما لو أُوقف نشاط هذا المستخدم أم لا.
	</li>
</ul>
<p>
	لننشئ أيضًا ملف تهجير يُعدّل قاعدة بيانات في الملف "migrations/20211209_01_admin_and_disabled_to_users.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_30" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  up</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">addColumn</span><span class="pun">(</span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'admin'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">BOOLEAN</span><span class="pun">,</span><span class="pln">
      </span><span class="kwd">default</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">addColumn</span><span class="pun">(</span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'disabled'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">BOOLEAN</span><span class="pun">,</span><span class="pln">
      </span><span class="kwd">default</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  down</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">removeColumn</span><span class="pun">(</span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'admin'</span><span class="pun">)</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">removeColumn</span><span class="pun">(</span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'disabled'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عدّل النموذج بما يتوافق مع الجدول "users":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_32" style="">
<span class="typ">User</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  username</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">STRING</span><span class="pun">,</span><span class="pln">
    unique</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">STRING</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  admin</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">BOOLEAN</span><span class="pun">,</span><span class="pln">
    defaultValue</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">  </span><span class="pun">},</span><span class="pln">  disabled</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">BOOLEAN</span><span class="pun">,</span><span class="pln">
    defaultValue</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'user'</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يتغير المخطط كما نريد، عندما تُنفَّذ شيفرة ملف التهجير عند إعادة تشغيل التطبيق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_34" style="">
<span class="pln">username</span><span class="pun">-&gt;</span><span class="pln"> \d users
                                     </span><span class="typ">Table</span><span class="pln"> </span><span class="str">"public.users"</span><span class="pln">
  </span><span class="typ">Column</span><span class="pln">  </span><span class="pun">|</span><span class="pln">          </span><span class="typ">Type</span><span class="pln">          </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Collation</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Nullable</span><span class="pln"> </span><span class="pun">|</span><span class="pln">              </span><span class="typ">Default</span><span class="pln">
</span><span class="pun">----------+------------------------+-----------+----------+-----------------------------------</span><span class="pln">
 id       </span><span class="pun">|</span><span class="pln"> integer                </span><span class="pun">|</span><span class="pln">           </span><span class="pun">|</span><span class="pln"> not </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> nextval</span><span class="pun">(</span><span class="str">'users_id_seq'</span><span class="pun">::</span><span class="pln">regclass</span><span class="pun">)</span><span class="pln">
 username </span><span class="pun">|</span><span class="pln"> character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">           </span><span class="pun">|</span><span class="pln"> not </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
 name     </span><span class="pun">|</span><span class="pln"> character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">           </span><span class="pun">|</span><span class="pln"> not </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
 admin    </span><span class="pun">|</span><span class="pln"> boolean                </span><span class="pun">|</span><span class="pln">           </span><span class="pun">|</span><span class="pln">          </span><span class="pun">|</span><span class="pln">
 disabled </span><span class="pun">|</span><span class="pln"> boolean                </span><span class="pun">|</span><span class="pln">           </span><span class="pun">|</span><span class="pln">          </span><span class="pun">|</span><span class="pln">
</span><span class="typ">Indexes</span><span class="pun">:</span><span class="pln">
    </span><span class="str">"users_pkey"</span><span class="pln"> PRIMARY KEY</span><span class="pun">,</span><span class="pln"> btree </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
    </span><span class="str">"users_username_key"</span><span class="pln"> UNIQUE CONSTRAINT</span><span class="pun">,</span><span class="pln"> btree </span><span class="pun">(</span><span class="pln">username</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Referenced</span><span class="pln"> by</span><span class="pun">:</span><span class="pln">
    TABLE </span><span class="str">"notes"</span><span class="pln"> CONSTRAINT </span><span class="str">"notes_user_id_fkey"</span><span class="pln"> FOREIGN KEY </span><span class="pun">(</span><span class="pln">user_id</span><span class="pun">)</span><span class="pln"> REFERENCES users</span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span></pre>

<p>
	لنوسّع الآن المتحكمات على النحو التالي، بحيث نمنع المستخدم من تسجيل الدخول في حال كانت قيمة الحقل <code>disabled</code> هي <code>true</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_36" style="">
<span class="pln">loginRouter</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> body </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">body

  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findOne</span><span class="pun">({</span><span class="pln">
    where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      username</span><span class="pun">:</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">username
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> passwordCorrect </span><span class="pun">=</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">password </span><span class="pun">===</span><span class="pln"> </span><span class="str">'secret'</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!(</span><span class="pln">user </span><span class="pun">&amp;&amp;</span><span class="pln"> passwordCorrect</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">401</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln">
      error</span><span class="pun">:</span><span class="pln"> </span><span class="str">'invalid username or password'</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">disabled</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">401</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln">
      error</span><span class="pun">:</span><span class="pln"> </span><span class="str">'account disabled, please contact admin'</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> userForToken </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    username</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">username</span><span class="pun">,</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> token </span><span class="pun">=</span><span class="pln"> jwt</span><span class="pun">.</span><span class="pln">sign</span><span class="pun">(</span><span class="pln">userForToken</span><span class="pun">,</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">SECRET</span><span class="pun">)</span><span class="pln">

  response
    </span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">200</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">send</span><span class="pun">({</span><span class="pln"> token</span><span class="pun">,</span><span class="pln"> username</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">username</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">name </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	دعونا نوقف نشاط المستخدم "jakousa" بالاستعانة بمعرّفه الفريد ID:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_38" style="">
<span class="pln">username </span><span class="pun">=&gt;</span><span class="pln"> update users </span><span class="kwd">set</span><span class="pln"> disabled</span><span class="pun">=</span><span class="kwd">true</span><span class="pln"> where id</span><span class="pun">=</span><span class="lit">3</span><span class="pun">;</span><span class="pln">
UPDATE </span><span class="lit">1</span><span class="pln">
username </span><span class="pun">=&gt;</span><span class="pln"> update users </span><span class="kwd">set</span><span class="pln"> admin</span><span class="pun">=</span><span class="kwd">true</span><span class="pln"> where id</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
UPDATE </span><span class="lit">1</span><span class="pln">
username </span><span class="pun">=&gt;</span><span class="pln"> select </span><span class="pun">*</span><span class="pln"> from users</span><span class="pun">;</span><span class="pln">
 id </span><span class="pun">|</span><span class="pln"> username </span><span class="pun">|</span><span class="pln">       name       </span><span class="pun">|</span><span class="pln"> admin </span><span class="pun">|</span><span class="pln"> disabled
</span><span class="pun">----+----------+------------------+-------+----------</span><span class="pln">
  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> lynx     </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Kalle</span><span class="pln"> </span><span class="typ">Ilves</span><span class="pln">      </span><span class="pun">|</span><span class="pln">       </span><span class="pun">|</span><span class="pln">
  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> jakousa  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Jami</span><span class="pln"> </span><span class="typ">Kousa</span><span class="pln">       </span><span class="pun">|</span><span class="pln"> f     </span><span class="pun">|</span><span class="pln"> t
  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> mluukkai </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Matti</span><span class="pln"> </span><span class="typ">Luukkainen</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> t     </span><span class="pun">|</span></pre>

<p>
	تأكد من نجاح الأمر بفشل تسجيل دخوله:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111209" href="https://academy.hsoub.com/uploads/monthly_2022_11/01_login_prevented.png.aeb4c18d8903a034fef07c0052c33649.png" rel=""><img alt="التأكد من نجاح الأمر بفشل تسجيل الدخول" class="ipsImage ipsImage_thumbnailed" data-fileid="111209" data-unique="mig0636bw" src="https://academy.hsoub.com/uploads/monthly_2022_11/01_login_prevented.thumb.png.bcfd2c720e92fee7a4127317c6739ccd.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	لننشئ تاليًا وجهةً تسمح للمدير بتغيير حالة حساب مستخدم آخر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_42" style="">
<span class="kwd">const</span><span class="pln"> isAdmin </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">,</span><span class="pln"> next</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">decodedToken</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">user</span><span class="pun">.</span><span class="pln">admin</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">401</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error</span><span class="pun">:</span><span class="pln"> </span><span class="str">'operation not allowed'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  next</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="str">'/:username'</span><span class="pun">,</span><span class="pln"> tokenExtractor</span><span class="pun">,</span><span class="pln"> isAdmin</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findOne</span><span class="pun">({</span><span class="pln">
    where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      username</span><span class="pun">:</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">username
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    user</span><span class="pun">.</span><span class="pln">disabled </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">disabled
    await user</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تُستخدم في هذه الشيفرة أداتان وسطيتان، تُدعى الأولى <code>tokenExtractor</code> وتماثل الأداة التي استخدمناها لإنشاء الوجهة route الخاصة بإنشاء ملاحظة، إذ تضع مفتاح الاستيثاق الذي فُكّ تشفيره في الحقل <code>decodedToken</code> من كائن الطلب؛ بينما تتحقق الأداة الثانية <code>isAdmin</code> فيما لوكان المستخدم ذا صلاحيات إدارية، فإن لم يكن كذلك يُضبط رمز حالة الطلب على القيمة <code>401</code> وتُعاد رسالة خطأ مناسبة.
</p>

<p>
	لاحظ كيف رُبطت الأداتين إلى الوجهة، إذ تُنفَّذ كلٌ منهما قبل تنفيذ معالج الوجهة الفعلي، ويمكنك ربط العدد الذي تريده من الأدوات الوسيطة إلى طلبٍ ما.
</p>

<p>
	تُنقل الأداة الوسطية <code>tokenExtractor</code> إلى الملف "util/middleware.js" كونها تُستخدم في عدّة مواضع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_44" style="">
<span class="kwd">const</span><span class="pln"> jwt </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'jsonwebtoken'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> SECRET </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./config.js'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> tokenExtractor </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">,</span><span class="pln"> next</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> authorization </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'authorization'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">authorization </span><span class="pun">&amp;&amp;</span><span class="pln"> authorization</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">().</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">'bearer '</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      req</span><span class="pun">.</span><span class="pln">decodedToken </span><span class="pun">=</span><span class="pln"> jwt</span><span class="pun">.</span><span class="pln">verify</span><span class="pun">(</span><span class="pln">authorization</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">(</span><span class="lit">7</span><span class="pun">),</span><span class="pln"> SECRET</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">401</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error</span><span class="pun">:</span><span class="pln"> </span><span class="str">'token invalid'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">401</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error</span><span class="pun">:</span><span class="pln"> </span><span class="str">'token missing'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  next</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> tokenExtractor </span><span class="pun">}</span></pre>

<p>
	يمكن للمدير الآن السماح للمستخدم "jakousa" بمعاودة نشاطه عن طريق إرسال طلب من النوع PUT إلى الوجهة "api/users/jakousa/" إذ يأتي الطلب مع البيانات التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_46" style="">
<span class="pun">{</span><span class="pln">
    </span><span class="str">"disabled"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وكما رأينا في نهاية <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%87%D9%8A%D9%83%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-unit-tests-r1132/" rel="">القسم 4</a>، تحمل هذه الطريقة في إيقاف نشاط المستخدمين بعض المشاكل، إذ يجري التحقق من وضع المستخدم عند تسجيل الدخول، وإن امتلك المستخدم مفتاح استيثاق صحيح في لحظة إيقاف نشاطه، فقد يتمكن من متابعة استخدام مفتاحه لعدم وجود فترة زمنية لصلاحيته، ولن يجري التحقق من حالته عند إضافة ملاحظة جديدة.
</p>

<p>
	قبل أن نتابع، سنكتب سكربت npm يسمح لنا بالتراجع عن آخر تهجير، فقد لا ينجح كل شيء في المرة الأولى بالضرورة عند تطوير ملفات التهجير.
</p>

<p>
	لنعدّل الملف "util/db.js" على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_49" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> DATABASE_URL </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./config'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Umzug</span><span class="pun">,</span><span class="pln"> </span><span class="typ">SequelizeStorage</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'umzug'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> sequelize </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">(</span><span class="pln">DATABASE_URL</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dialectOptions</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      require</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      rejectUnauthorized</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> connectToDatabase </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await sequelize</span><span class="pun">.</span><span class="pln">authenticate</span><span class="pun">()</span><span class="pln">
    await runMigrations</span><span class="pun">()</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'connected to the database'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'failed to connect to the database'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> migrationConf </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  migrations</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    glob</span><span class="pun">:</span><span class="pln"> </span><span class="str">'migrations/*.js'</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  storage</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">SequelizeStorage</span><span class="pun">({</span><span class="pln"> sequelize</span><span class="pun">,</span><span class="pln"> tableName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'migrations'</span><span class="pln"> </span><span class="pun">}),</span><span class="pln">
  context</span><span class="pun">:</span><span class="pln"> sequelize</span><span class="pun">.</span><span class="pln">getQueryInterface</span><span class="pun">(),</span><span class="pln">
  logger</span><span class="pun">:</span><span class="pln"> console</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> runMigrations </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> migrator </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Umzug</span><span class="pun">(</span><span class="pln">migrationConf</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> migrations </span><span class="pun">=</span><span class="pln"> await migrator</span><span class="pun">.</span><span class="pln">up</span><span class="pun">()</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Migrations up to date'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    files</span><span class="pun">:</span><span class="pln"> migrations</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">mig</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> mig</span><span class="pun">.</span><span class="pln">name</span><span class="pun">),</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> rollbackMigration </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  await sequelize</span><span class="pun">.</span><span class="pln">authenticate</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> migrator </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Umzug</span><span class="pun">(</span><span class="pln">migrationConf</span><span class="pun">)</span><span class="pln">
  await migrator</span><span class="pun">.</span><span class="pln">down</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> connectToDatabase</span><span class="pun">,</span><span class="pln"> sequelize</span><span class="pun">,</span><span class="pln"> rollbackMigration </span><span class="pun">}</span><span class="pln"> </span><span class="com">// highlight-line</span></pre>

<p>
	لننشئ الملف "util/rollback.js" الذي يتيح لسكربت npm تنفيذ دالة التراجع عن التهجير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_51" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> rollbackMigration </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./db'</span><span class="pun">)</span><span class="pln">

rollbackMigration</span><span class="pun">()</span></pre>

<p>
	وسيكون السكربت على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_53" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"dev"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"nodemon index.js"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"migration:down"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"node util/rollback.js"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا سنتمكن من التراجع عن آخر تهجير بتنفيذ الأمر <code>npm run migration:down</code> من خلال سطر الأوامر.
</p>

<p>
	تُنفّذ ملفات التهجير تلقائيًا عندما يُشغَّل البرنامج، لكن قد يكون من الأنسب في مرحلة التطوير تعطيل التنفيذ التلقائي للتهجير وتنفيذه يدويًا من خلال <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a>.
</p>

<p>
	يمكنك الحصول على شيفرة التطبيق بوضعه الحالي من <a href="https://github.com/fullstack-hy/part13-notes/tree/part13-7" rel="external nofollow">المستودع المخصص له على GitHub</a> ضمن الفرع part13-7.
</p>

<h2>
	التمرينان 13.7 و 13.8
</h2>

<p>
	حاول إنجاز التمارين التالية:
</p>

<h3>
	التمرين 13.7
</h3>

<p>
	احذف كل الجداول من قاعدة بيانات تطبيقك ثم أنشئ ملف تهجير ليهيئ قاعدة البيانات. أضف البصمتان الزمنيتان "created_at" و "updated_at" إلى كلا الجدولين، وتذكر أن عليك إضافتها في ملف التهجير بنفسك.
</p>

<p>
	<strong>ملاحظة</strong>: تأكد من إزالة التعليمتين <code>()User.sync</code> و <code>()Blog.sync</code> اللتين تزامنان مخطط النموذج من شيفرتك وإلا سيخفق التهجير.
</p>

<p>
	<strong>ملاحظة</strong>: إذا كان عليك حذف الجداول باستخدام سطر الأوامر، أي إذا لم تكن تنوي التراجع عن الحذف بالتراجع عن آخر عملية تهجير، فلا بُد حينها من حذف محتوى جدول التهجير <code>migrations</code> إذا أردت من برنامجك تنفيذ التهجير مجددًا.
</p>

<h3>
	التمرين 13.18
</h3>

<p>
	وسّع تطبيقك (مستخدمًا ملف تهجير) لكي يكون للمدونة سمةً تدل على سنة كتابتها، أي حقلٌ بالاسم يأخذ قيمًا صحيحة تبدأ من 1991 ولا يزيد عن العام الحالي. تأكد من ظهور رسالة خطأ مناسبة إن أُدخلت قيمة غير صحيحة للسنة.
</p>

<h2>
	علاقات متعدد-إلى-متعدد many-to-many بين الجداول
</h2>

<p>
	سنتابع توسعة التطبيق كي يُضاف كل مستخدم إلى فريقٍ أو أكثر، وطالما يمكن لأي عدد من المستخدمين الانضمام إلى فريق وكذلك يمكن لأي مستخدم الانضمام إلى أي عدد من الفرقاء، فإننا أمام علاقة متعدد-إلى-متعدد many-to-many والتي تنُفّذ تقليديًا في قواعد البيانات من خلال جدول الاتصال connection table.
</p>

<p>
	لنكتب الآن الشيفرة التي يحتاجها الجدول <code>teams</code> إضافةً إلى جدول الاتصال. سيبدو ملف التهجير أولًا على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_56" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  up</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">createTable</span><span class="pun">(</span><span class="str">'teams'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">TEXT</span><span class="pun">,</span><span class="pln">
        allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
        unique</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">createTable</span><span class="pun">(</span><span class="str">'memberships'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      user_id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
        references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      team_id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
        references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'teams'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  down</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">dropTable</span><span class="pun">(</span><span class="str">'teams'</span><span class="pun">)</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">dropTable</span><span class="pun">(</span><span class="str">'memberships'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تتضمن النماذج نفس شيفرة ملفات التهجير تقريبًا، وإليك شيفرة نموذج الجدول <code>team</code> في الملف "models/team.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_58" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Model</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> sequelize </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../util/db'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Team</span><span class="pln"> extends </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

</span><span class="typ">Team</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">TEXT</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    unique</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'team'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Team</span></pre>

<p>
	وهذه هي شيفرة نموذج جدول الاتصال الموجودة في الملف "models/membership.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_60" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Model</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> sequelize </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../util/db'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> extends </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

</span><span class="typ">Membership</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  user_id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  team_id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'teams'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'membership'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Membership</span></pre>

<p>
	منحنا جدول الاتصال اسمًا يصف طبيعة محتوياته <code>membership</code>، لكن قد لا تجد بالضرورة اسمًا يصف هذا الجدول، ولهذا يمكنك تسميته بأسماء الجداول التي يربطها تفصل بينها شرطة سفلية، مثل "user_teams" الذي يصلح أيضًا لحالتنا هذه.
</p>

<p>
	أجرينا إضافةً صغيرةً على الملف "models/index.js" لربط الفرقاء والمستخدمين على مستوى الشيفرة باستخدام التابع <a href="https://sequelize.org/master/manual/assocs.html#implementation-3" rel="external nofollow">belongsToMany</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_62" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./note'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./user'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Team</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./team'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./membership'</span><span class="pun">)</span><span class="pln">

</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">belongsTo</span><span class="pun">(</span><span class="typ">User</span><span class="pun">)</span><span class="pln">
</span><span class="typ">User</span><span class="pun">.</span><span class="pln">hasMany</span><span class="pun">(</span><span class="typ">Note</span><span class="pun">)</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">Team</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> through</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
</span><span class="typ">Team</span><span class="pun">.</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">User</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> through</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> </span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Note</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Team</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ الفَرق بين ملف التهجير لجدول الاتصال ونموذجه عند تعريف مفتاح خارجي، إذ تُعرَّف الحقول باستخدام أسلوب الأفعى في ملف التهجير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_64" style="">
<span class="pln">await queryInterface</span><span class="pun">.</span><span class="pln">createTable</span><span class="pun">(</span><span class="str">'memberships'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  user_id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  team_id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'teams'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	بينما تُعرَّف نفس الحقول في النموذج باستخدام أسلوب سنام الجمل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_66" style="">
<span class="typ">Membership</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  userId</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  teamId</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'teams'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لننشئ الآن بعض الفُرقاء وبعض الأعضاء باستخدام الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_68" style="">
<span class="pln">insert into teams </span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="str">'toska'</span><span class="pun">);</span><span class="pln">
insert into teams </span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="str">'mosa climbers'</span><span class="pun">);</span><span class="pln">
insert into memberships </span><span class="pun">(</span><span class="pln">user_id</span><span class="pun">,</span><span class="pln"> team_id</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
insert into memberships </span><span class="pun">(</span><span class="pln">user_id</span><span class="pun">,</span><span class="pln"> team_id</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">
insert into memberships </span><span class="pun">(</span><span class="pln">user_id</span><span class="pun">,</span><span class="pln"> team_id</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
insert into memberships </span><span class="pun">(</span><span class="pln">user_id</span><span class="pun">,</span><span class="pln"> team_id</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span></pre>

<p>
	تُضاف معلومات أعضاء الفرقاء بعد ذلك إلى الوجهة التي تعيد كل المستخدمين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_70" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> users </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Team</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'id'</span><span class="pun">],</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">users</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لاحظ أن الاستعلام الذي طُبع على شاشة الطرفية يجمع ثلاثة جداول. هذا الحل جيدٌ فعلًا، لكن ما تزال هنالك ثغرة، إذ تأتي نتيجة الاستعلام مع جميع سمات الصف المطلوب من جدول الاتصال، علمًا أننا لا نحتاجها كلها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111210" href="https://academy.hsoub.com/uploads/monthly_2022_11/02_jointless_flow_tab.png.4a8f626bbdba605142a07a8d56161f22.png" rel=""><img alt="شكل الاستعلام الذي يطبع على شاشة الطرفية" class="ipsImage ipsImage_thumbnailed" data-fileid="111210" data-unique="jltj97q2n" src="https://academy.hsoub.com/uploads/monthly_2022_11/02_jointless_flow_tab.thumb.png.bfac920bb9a23f775dd252fc76334a65.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	وبقراءة توثيق Sequelize جيدًا ستجد <a href="https://sequelize.org/master/manual/advanced-many-to-many.html#specifying-attributes-from-the-through-table" rel="external nofollow">الحل</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_76" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> users </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Team</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'id'</span><span class="pun">],</span><span class="pln">
        through</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">users</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يمكنك الحصول على شيفرة التطبيق بوضعه الحالي من <a href="https://github.com/fullstack-hy/part13-notes/tree/part13-8" rel="external nofollow">المستودع المخصص له على GitHub</a> ضمن الفرع part13-8.
</p>

<h2>
	فكرة عن خاصيات كائن نموذج Sequelize
</h2>

<p>
	تظهر خاصيات نموذجنا من خلال الأسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_78" style="">
<span class="typ">User</span><span class="pun">.</span><span class="pln">hasMany</span><span class="pun">(</span><span class="typ">Note</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">belongsTo</span><span class="pun">(</span><span class="typ">User</span><span class="pun">)</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">Team</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> through</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
</span><span class="typ">Team</span><span class="pun">.</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">User</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> through</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> </span><span class="pun">})</span></pre>

<p>
	يمكّن ذلك Sequelize من إنشاء استعلامات تستخلص مثلًا كل ملاحظات المستخدمين أو كل أعضاء فريق، وبفضل تلك التعريفات نستطيع أيضًا الوصول مباشرةً إلى ملاحظات مستخدم مثلًا من خلال الشيفرة؛ ففي الشيفرة التالية مثلًا نحاول البحث عن مستخدم معرّفه المميز <code>id=1</code>، ثم نطبع الملاحظات المرتبطة به:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_80" style="">
<span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

user</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يربط التعريف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_82" style="">
<span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">hasMany</span><span class="pun">(</span><span class="typ">Note</span><span class="pun">)</span></pre>

<p>
	الخاصية <code>notes</code> إلى الكائن <code>user</code> الذي يمنح وصولًا إلى الملاحظات التي أنشأها المستخدم، ويربط التعريف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_84" style="">
<span class="typ">User</span><span class="pun">.</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">Team</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> through</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> </span><span class="pun">})</span></pre>

<p>
	الخاصية <code>teams</code> إلى الكائن <code>user</code>، الذي يمكن استخدامه في الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_86" style="">
<span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    model</span><span class="pun">:</span><span class="pln"> team
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

user</span><span class="pun">.</span><span class="pln">teams</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">team </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">team</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لنفترض أننا نريد إعادة كائن<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel=""> JSON</a> من وجهة route تقود إلى مستخدم واحد يتضمن اسم المستخدم وعدد الملاحظات التي أنشأها. يمكننا تجربة الطريقة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_89" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    user</span><span class="pun">.</span><span class="pln">note_count </span><span class="pun">=</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">length
    </span><span class="kwd">delete</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">notes
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">

  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	حاولنا إضافة الحقل <code>noteCount</code> في الكائن الذي أعادته Sequelize وإزالة الحقل <code>notes</code> منه، لكن ما يحدث أن هذه الطريقة لن تنفع لأن الكائن الذي تعيده Sequelize ليس كائنًا عاديًا تعمل فيه الحقول الإضافية كما نريد؛ ولذلك فإن الحل الأفضل لحالتنا هو إنشاء كائن جديد كليًا بناءً على البيانات المستخلصة من قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_91" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">({</span><span class="pln">
      username</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">username</span><span class="pun">,</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">,</span><span class="pln">
      note_count</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">length
    </span><span class="pun">})</span><span class="pln">

  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<h2>
	نظرة ثانية إلى العلاقات متعدد-إلى-متعدد many-to-many
</h2>

<p>
	سنختبر علاقة متعدد-إلى-متعدد أخرى في التطبيق؛ إذ ترتبط كل ملاحظة بالمستخدم الذي أنشأها من خلال مفتاح خارجي، ونريد الآن أن يدعم التطبيق ربط الملاحظة بمستخدمين آخرين، وربط المستخدم بعدد غير محدد من الملاحظات التي أنشأها آخرون، والفكرة هنا أن هذه الملاحظات هي تلك التي أشار المستخدم على أنها تهمّه.
</p>

<p>
	لننشئ جدول الاتصال <code>user_notes</code> في هذه الحالة، وسيكون ملف التهجير بسيطًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_94" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  up</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">createTable</span><span class="pun">(</span><span class="str">'user_notes'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      user_id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
        references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      note_id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
        references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'notes'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  down</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">dropTable</span><span class="pun">(</span><span class="str">'user_notes'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما لن تجد أفكارًا جديدةً أيضًا في شيفرة النموذج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_96" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Model</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> sequelize </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../util/db'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">UserNotes</span><span class="pln"> extends </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

</span><span class="typ">UserNotes</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  userId</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  noteId</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'notes'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'user_notes'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="typ">UserNotes</span></pre>

<p>
	يضم الملف "models/index.js" بعض التغيرات ليصبح على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_98" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./note'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./user'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Team</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./team'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./membership'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">UserNotes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./user_notes'</span><span class="pun">)</span><span class="pln">

</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">belongsTo</span><span class="pun">(</span><span class="typ">User</span><span class="pun">)</span><span class="pln">
</span><span class="typ">User</span><span class="pun">.</span><span class="pln">hasMany</span><span class="pun">(</span><span class="typ">Note</span><span class="pun">)</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">Team</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> through</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
</span><span class="typ">Team</span><span class="pun">.</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">User</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> through</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Membership</span><span class="pln"> </span><span class="pun">})</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">Note</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> through</span><span class="pun">:</span><span class="pln"> </span><span class="typ">UserNotes</span><span class="pun">,</span><span class="pln"> as</span><span class="pun">:</span><span class="pln"> </span><span class="str">'marked_notes'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">belongsToMany</span><span class="pun">(</span><span class="typ">User</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> through</span><span class="pun">:</span><span class="pln"> </span><span class="typ">UserNotes</span><span class="pun">,</span><span class="pln"> as</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users_marked'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Note</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Team</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Membership</span><span class="pun">,</span><span class="pln"> </span><span class="typ">UserNotes</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُستخدم التعريف <code>belongsToMany</code> مجددًا، إذ يربط الآن المستخدمين إلى الملاحظات عن طريق النموذج <code>UserNotes</code> المتعلق بجدول الاتصال، لكننا سنستخدم هذه المرة اسمًا بديلًا alias للسمات المُنشأة باستخدام الكلمة المحجوزة <a href="https://sequelize.org/master/manual/advanced-many-to-many.html#aliases-and-custom-key-names" rel="external nofollow"><code>as</code></a>، إذ سيتداخل overlap الاسم الافتراضي ("notes" المستخدم) مع معناه السابق وهو الملاحظات المُضافة من قِبل المستخدم.
</p>

<p>
	سنوسِّع الوجهة التي تقود إلى مستخدم وحيد لتعيد الفُرقاء التي ينتمي إليها المستخدم، وملاحظاتهم، والملاحظات الأخرى التي حددها المستخدم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_100" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">''</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">,</span><span class="pln">
    include</span><span class="pun">:[{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">,</span><span class="pln">
        as</span><span class="pun">:</span><span class="pln"> </span><span class="str">'marked_notes'</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]},</span><span class="pln">
        through</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Team</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'id'</span><span class="pun">],</span><span class="pln">
        through</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لا بُد من استخدام الاسم البديل الذي عرّفناه من خلال السمة <code>as</code> خلال السياق. سننشئ بعض البيانات الاختبارية في قاعدة البيانات لاختبار الميزة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_102" style="">
<span class="pln">insert into user_notes </span><span class="pun">(</span><span class="pln">user_id</span><span class="pun">,</span><span class="pln"> note_id</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">);</span><span class="pln">
insert into user_notes </span><span class="pun">(</span><span class="pln">user_id</span><span class="pun">,</span><span class="pln"> note_id</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">);</span></pre>

<p>
	ستكون النتيجة النهائية على النحو التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111211" href="https://academy.hsoub.com/uploads/monthly_2022_11/03_test_data_result.png.3037a143273fc96374cb244fb355f09b.png" rel=""><img alt="نتائج البيانات الاختبارية في قواعد البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="111211" data-unique="6jzgy8ia8" src="https://academy.hsoub.com/uploads/monthly_2022_11/03_test_data_result.png.3037a143273fc96374cb244fb355f09b.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	لكن ماذا لو أردنا أن نضمّن معلومات تتعلق بمؤلف الملاحظة إلى الملاحظات التي يحددها مستخدم؟ يُنفَّذ الأمر بإضافة التعليمة <code>include</code> إلى الملاحظات المحدّدة من قبل المستخدم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_106" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">''</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">,</span><span class="pln">
    include</span><span class="pun">:[{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">,</span><span class="pln">
        as</span><span class="pun">:</span><span class="pln"> </span><span class="str">'marked_notes'</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]},</span><span class="pln">
        through</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">User</span><span class="pun">,</span><span class="pln">
          attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Team</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'id'</span><span class="pun">],</span><span class="pln">
        through</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	ها هي النتيجة النهائية كما نتوقع:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111212" href="https://academy.hsoub.com/uploads/monthly_2022_11/04_final_result_expected.png.e56a208ece6a76e56d2a4d2d3df13254.png" rel=""><img alt="النتيجة النهائية في البيانات الاختبارية في قاعدة البيانات" class="ipsImage ipsImage_thumbnailed" data-fileid="111212" data-unique="vt16kzsrx" src="https://academy.hsoub.com/uploads/monthly_2022_11/04_final_result_expected.thumb.png.610ad6a3fb6ca449879b00c854ca9aef.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	يمكنك الحصول على شيفرة التطبيق بوضعه الحالي من <a href="https://github.com/fullstack-hy/part13-notes/tree/part13-9" rel="external nofollow">المستودع المخصص له على GitHub</a> ضمن الفرع part13-9.
</p>

<h2>
	التمرينات 13.19 - 13.23
</h2>

<p>
	حاول إنجاز التمرينات التالية.
</p>

<h3>
	التمرين 13.19
</h3>

<p>
	اِمنح المستخدمين القدرة على إضافة مدوّنات إلى قائمة قراءة reading list. وعند إضافتها إلى القائمة يجب أن تكون حالتها "غير مقروءة unreaded"، ويمكن لاحقًا تعليم المدوّنة على أنها "مقروءة". نفّذ فكرة قائمة القراءة مستخدمًا جدول اتصال، وعدّل قاعدة البيانات من خلال ملف تهجير.
</p>

<p>
	لا يهم في هذا التمرين إضافة مدونات إلى القائمة وعرضها بنجاح أكثر من استخدام فكرة الولوج المباشر إلى قاعدة البيانات.
</p>

<h3>
	التمرين 13.20
</h3>

<p>
	أضف الآن طريقةً كي يدعم التطبيق قوائم القراءة.
</p>

<p>
	تُضاف المدوّنة إلى قائمة القراءة من خلال الطلب HTTP POST إلى الوجهة "api/readinglists/"، ويُرفق مع الطلب المدوّنة ومعرّف المستخدم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_111" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"blogId"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"userId"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عدّل الوجهة "GET /api/users/:id" لإعادة قائمة المدوّنات إضافة إلى معلومات المستخدم بالتنسيق التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_113" style="">
<span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Matti Luukkainen"</span><span class="pun">,</span><span class="pln">
  username</span><span class="pun">:</span><span class="pln"> </span><span class="str">"mluukkai@iki.fi"</span><span class="pun">,</span><span class="pln">
  readings</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
      url</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://google.com"</span><span class="pun">,</span><span class="pln">
      title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Clean React"</span><span class="pun">,</span><span class="pln">
      author</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Dan Abramov"</span><span class="pun">,</span><span class="pln">
      likes</span><span class="pun">:</span><span class="pln"> </span><span class="lit">34</span><span class="pun">,</span><span class="pln">
      year</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
      url</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://google.com"</span><span class="pun">,</span><span class="pln">
      title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Clean Code"</span><span class="pun">,</span><span class="pln">
      author</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Bob Martin"</span><span class="pun">,</span><span class="pln">
      likes</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln">
      year</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	حتى هذه اللحظة، لا حاجة لإظهار إن كانت المدوّنة مقروءةً أم لا.
</p>

<h3>
	التمرين 13.21
</h3>

<p>
	عدّل الوجهة التي تصل إلى مستخدم وحيد لكي تعرض فيما إذا كانت كل مدوّنة في قائمة القراءة مقروءةً أم لا، إضافةً إلى المُعرَّف المميز "id" للصف المقابل في جدول الاتصال.
</p>

<p>
	يمكن عرض المعلومات وفق التنسيق الآتي مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_115" style="">
<span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Matti Luukkainen"</span><span class="pun">,</span><span class="pln">
  username</span><span class="pun">:</span><span class="pln"> </span><span class="str">"mluukkai@iki.fi"</span><span class="pun">,</span><span class="pln">
  readings</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
      url</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://google.com"</span><span class="pun">,</span><span class="pln">
      title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Clean React"</span><span class="pun">,</span><span class="pln">
      author</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Dan Abramov"</span><span class="pun">,</span><span class="pln">
      likes</span><span class="pun">:</span><span class="pln"> </span><span class="lit">34</span><span class="pun">,</span><span class="pln">
      year</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
      readinglists</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          read</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
          id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">]</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
      url</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://google.com"</span><span class="pun">,</span><span class="pln">
      title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Clean Code"</span><span class="pun">,</span><span class="pln">
      author</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Bob Martin"</span><span class="pun">,</span><span class="pln">
      likes</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln">
      year</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
      readinglists</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          read</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
          id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">]</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	التمرين 13.22
</h3>

<p>
	قدّم طريقةً يستطيع من خلالها التطبيق تعليم مدوّنة ضمن قائمة القراءة على أنها مقروءة، إذ يُنفَّذ الأمر بإجراء طلب PUT إلى الوجهة "api/readinglists/:id/" وإرساله مع القيمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_117" style="">
<span class="pun">{</span><span class="pln"> </span><span class="str">"read"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	يمكن للمستخدم أن يعلّم مدوّنة على أنها مقروءةً إذا كانت فقط ضمن قائمة القراءة الخاصة به. يستوثق من المستخدم عادةً من خلال مفتاح الاستيثاق الذي يُرفق مع الطلب.
</p>

<h3>
	التمرين 13.23
</h3>

<p>
	عدّل الوجهة التي تعيد معلومات مستخدم وحيد لكي يتحكم الطلب بالمدوّنة التي ينبغي إحضارها من قائمة القراءة:
</p>

<ul>
<li>
		"GET /api/users/:id": يعيد كامل قائمة القراءة.
	</li>
	<li>
		"GET /api/users/:id?read=true": يعيد المدوّنات المقروءة.
	</li>
	<li>
		"GET /api/users/:id?read=false": يعيد المدوّنات غير المقروءة.
	</li>
</ul>
<h2>
	ملاحظات عامة
</h2>

<p>
	يمكننا عدّ حالة تطبيقنا الآن مقبولة، لكن لا بُدّ من إلقاء نظرةٍ على بعض الأفكار قبل أن نختم هذا القسم.
</p>

<h3>
	إحضار البيانات الكسول lazy والمتلهف eager
</h3>

<p>
	عندما ننشئ استعلامًا مستخدمين السمة <code>include</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_119" style="">
<span class="typ">User</span><span class="pun">.</span><span class="pln">findOne</span><span class="pun">({</span><span class="pln">
  include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    model</span><span class="pun">:</span><span class="pln"> note
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يحدُث ما يُسمى <a href="https://sequelize.org/master/manual/assocs.html#basics-of-queries-involving-associations" rel="external nofollow">الإحضار المُتلهِّف eager fetch للبيانات</a>، إذ تُجلب جميع الصفوف في كل الجداول المرتبطة بالمستخدم بواسطة الاستعلام <code>join</code> بنفس الوقت في مثال الملاحظات التي يُنشئها مستخدم. هذا السلوك هو ما نحتاجه عادةً، لكن ستجد في المقابل حالات تحتاج فيها إلى ما يُدعى بالإحضار الكسول أو المحدود lazy fetch مثل البحث عن فُرقاء مرتبطةٍ بمستخدم إذا لزم الأمر.
</p>

<p>
	لنعدّل وجهة إحضار مستخدم واحد كي تُحضر الفُرقاء التي ينتمي إليها مستخدم إذا احتوى الاستعلام على المعامل <code>teams</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_121" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">''</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">,</span><span class="pln">
    include</span><span class="pun">:[{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> note</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">,</span><span class="pln">
        as</span><span class="pun">:</span><span class="pln"> </span><span class="str">'marked_notes'</span><span class="pun">,</span><span class="pln">
        attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]},</span><span class="pln">
        through</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          model</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">,</span><span class="pln">
          attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  let teams </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">teams</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    teams </span><span class="pun">=</span><span class="pln"> await user</span><span class="pun">.</span><span class="pln">getTeams</span><span class="pun">({</span><span class="pln">
      attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">],</span><span class="pln">
      joinTableAttributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> </span><span class="pun">...</span><span class="pln">user</span><span class="pun">.</span><span class="pln">toJSON</span><span class="pun">(),</span><span class="pln"> teams </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وهكذا لن يحضر الاستعلام <code>User.findByPk</code> الفُرقاء، لكنها ستُجلب عند الحاجة باستخدام التابع <code>user.getTeams</code> الذي تولِّده Sequelize تلقائيًا لكائن النموذج. تولَّد Sequelize تلقائيًا توابع <code>-get</code> مماثلة وتوابع أخرى مفيدة عندما تٌعرّف ارتباطات associations بين الجداول على مستوى قاعدة بيانات.
</p>

<h3>
	ميزات النموذج
</h3>

<p>
	قد تصادفنا حالات لا نريد فيها معالجة كل أسطر جدول محدد افتراضيًا، إذ من الممكن مثلًا ألا نرغب في عرض المستخدمين الذين أوقفت نشاطاتهم في التطبيق، ويمكننا في هذه الحالة تعريف مجالات الرؤية الافتراضية للنموذج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_123" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> extends </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  </span><span class="com">// field definition</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'user'</span><span class="pun">,</span><span class="pln">
  defaultScope</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      disabled</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  scopes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    admin</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        admin</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    disabled</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        disabled</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span></pre>

<p>
	سيضم الاستعلام الناتج عن التابع <code>()User.findAll</code> عبارة <code>WHERE</code> التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_125" style="">
<span class="pln">WHERE </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"disabled"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span></pre>

<p>
	يمكن أن نعرّف أيضًا مجالات رؤية أخرى للنماذج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_127" style="">
<span class="typ">User</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  </span><span class="com">// field definition</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'user'</span><span class="pun">,</span><span class="pln">
  defaultScope</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      disabled</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  scopes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    admin</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        admin</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    disabled</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        disabled</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    name</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="pun">[</span><span class="typ">Op</span><span class="pun">.</span><span class="pln">iLike</span><span class="pun">]:</span><span class="pln"> value
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تُستخدم مجالات الرؤية على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_129" style="">
<span class="com">// جميع المدراء</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> adminUsers </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">scope</span><span class="pun">(</span><span class="str">'admin'</span><span class="pun">).</span><span class="pln">findAll</span><span class="pun">()</span><span class="pln">

</span><span class="com">// جميع المستخدمين غير النشطين</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> disabledUsers </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">scope</span><span class="pun">(</span><span class="str">'disabled'</span><span class="pun">).</span><span class="pln">findAll</span><span class="pun">()</span><span class="pln">

</span><span class="com">// في أسمائهم jami المستخدمون الذين لديهم سلسلة نصية</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> jamiUsers </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">scope</span><span class="pun">({</span><span class="pln"> method</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'%jami%'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}).</span><span class="pln">findAll</span><span class="pun">()</span></pre>

<p>
	كما يمكن سلسلة مجالات الرؤية (ربطها ببعضها):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_131" style="">
<span class="com">// في أسمائهم jami المدراء الذين لديهم سلسلة نصية</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> jamiUsers </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">scope</span><span class="pun">(</span><span class="str">'admin'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> method</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'%jami%'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}).</span><span class="pln">findAll</span><span class="pun">()</span></pre>

<p>
	وطالما أن نماذج هي <a href="https://sequelize.org/master/manual/model-basics.html#taking-advantage-of-models-being-classes" rel="external nofollow">أصناف جافا سكربت JavaScript</a>، من الممكن إضافة توابع جديدة إليها، وإليك مثالين عن ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_133" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Model</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Op</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./note'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> sequelize </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../util/db'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> extends </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  async number_of_notes</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">await </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">getNotes</span><span class="pun">()).</span><span class="pln">length
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">static</span><span class="pln"> async with_notes</span><span class="pun">(</span><span class="pln">limit</span><span class="pun">){</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
      attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[[</span><span class="pln"> sequelize</span><span class="pun">.</span><span class="pln">fn</span><span class="pun">(</span><span class="str">"COUNT"</span><span class="pun">,</span><span class="pln"> sequelize</span><span class="pun">.</span><span class="pln">col</span><span class="pun">(</span><span class="str">"notes.id"</span><span class="pun">)),</span><span class="pln"> </span><span class="str">"note_count"</span><span class="pln"> </span><span class="pun">]]</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">,</span><span class="pln">
          attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">],</span><span class="pln">
      group</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'user.id'</span><span class="pun">],</span><span class="pln">
      having</span><span class="pun">:</span><span class="pln"> sequelize</span><span class="pun">.</span><span class="pln">literal</span><span class="pun">(`</span><span class="pln">COUNT</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">limit</span><span class="pun">}`)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span></pre>

<p>
	التابع الأول <code>numberOfNotes</code> هو تابع نسخة instance method، أي أن استدعاءه ممكن من نسخٍ instances عن النموذج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_135" style="">
<span class="kwd">const</span><span class="pln"> jami </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findOne</span><span class="pun">({</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Jami Kousa'</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> cnt </span><span class="pun">=</span><span class="pln"> await jami</span><span class="pun">.</span><span class="pln">number_of_notes</span><span class="pun">()</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">Jami</span><span class="pln"> has created $</span><span class="pun">{</span><span class="pln">cnt</span><span class="pun">}</span><span class="pln"> notes</span><span class="pun">`)</span></pre>

<p>
	تشير الكلمة <code>this</code> في تابع النسخة إلى نسخة النموذج نفسها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_137" style="">
<span class="pln">async number_of_notes</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">await </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">getNotes</span><span class="pun">()).</span><span class="pln">length
</span><span class="pun">}</span></pre>

<p>
	أما التابع الثاني للنموذج، فيعيد هؤلاء المستخدمين الذين يملكون على الأقل "X" وهي القيمة التي يحملها المعامل وتدل على كمية الملاحظات في الصنف، أي التي تُستدعى مباشرةً عن طريق النموذج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_139" style="">
<span class="kwd">const</span><span class="pln"> users </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">with_notes</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">users</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">))</span><span class="pln">
users</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">u </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">u</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<h3>
	قابلية التكرار في النماذج وملفات التهجير
</h3>

<p>
	لقد رأينا أن الشيفرة في النموذج أو ملف التهجير تتكرر كثيرًا، فلو أخذنا نموذج الفُرقاء teams:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_141" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Team</span><span class="pln"> extends </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

</span><span class="typ">Team</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">TEXT</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    unique</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'team'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Team</span></pre>

<p>
	وملف التهجير فإنهما يضمان كمًّا كبيرًا من نفس الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_608_143" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  up</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">createTable</span><span class="pun">(</span><span class="str">'teams'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
        primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">TEXT</span><span class="pun">,</span><span class="pln">
        allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
        unique</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  down</span><span class="pun">:</span><span class="pln"> async </span><span class="pun">({</span><span class="pln"> context</span><span class="pun">:</span><span class="pln"> queryInterface </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await queryInterface</span><span class="pun">.</span><span class="pln">dropTable</span><span class="pun">(</span><span class="str">'teams'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هل يمكن تحسين الشيفرة كي يُصدّر النموذج مثلًا الأجزاء المشتركة التي يحتاجها ملف التهجير؟
</p>

<p>
	تكمن المشكلة في احتمال تغيُّر تعريف النموذج مع الوقت، فقد يتغير مثلًا الحقل أو يتغير نوع البيانات المُخزّنة فيه، وعلى ملف التهجير أن يُنفَّذ بنجاح في أي وقت من البداية إلى النهاية. إذا اعتمَدت ملفات التهجير على النموذج في الحصول على محتوى معين، فقد لا يكون هذا متاحًا خلال شهر أو سنة؛ لهذا ورغم وجود الكثير من الشيفرة للنسخ واللصق، لكن يُعد فصل ملف التهجير عن النموذج كاملًا أمرًا ضروريًا.
</p>

<p>
	قد يكون أحد الحلول هو استخدام <a href="https://sequelize.org/master/manual/migrations.html#creating-the-first-model--and-migration-" rel="external nofollow">أداة سطر أوامر Sequelize</a> الذي يولّد كلًا من النموذج وملف التهجير بناءً على الأوامر التي تُنفِّذها، إذ سيُنفِّذ الأمر التالي النموذج <code>User</code> الذي يمتلك السمات <code>name</code> و <code>username</code> و <code>admin</code>، إضافةً إلى ملف التهجير الذي يدير شؤون إنشاء جدول قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_608_147" style="">
<span class="pln">npx sequelize</span><span class="pun">-</span><span class="pln">cli model</span><span class="pun">:</span><span class="pln">generate </span><span class="pun">--</span><span class="pln">name </span><span class="typ">User</span><span class="pln"> </span><span class="pun">--</span><span class="pln">attributes name</span><span class="pun">:</span><span class="kwd">string</span><span class="pun">,</span><span class="pln">username</span><span class="pun">:</span><span class="kwd">string</span><span class="pun">,</span><span class="pln">admin</span><span class="pun">:</span><span class="kwd">boolean</span></pre>

<p>
	يمكننا أيضًا تنفيذ أمر التراجع عن التهجيرات انطلاقًا من سطر الأوامر.
</p>

<p>
	لم يكتمل بعد لسوء الحظ توثيق سطر الأوامر هذا، لهذا قررنا إنشاء النماذج وملفات التهجير يدويًا في المنهاج، وقد يكون أو لايكون ما أنجزناه من حلول جيدًا.
</p>

<h2>
	التمرين 13.24
</h2>

<p>
	نهاية عظيمة: أشرنا في نهاية <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%87%D9%8A%D9%83%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-unit-tests-r1132/" rel="">القسم 4</a> إلى مشكلة جدّية في مفتاح الاستيثاق، فلو قررنا إيقاف نشاط مستخدم بعد أن دخل إلى المنظومة، سيبقى هذا المستخدم قادرًا على استخدام مفتاح الاستيثاق الذي يمتلكه وبالتالي استخدام المنظومة.
</p>

<p>
	الحل الإعتيادي للمشكلة هو تخزين سجلات بكل مفتاح استيثاق مُنح إلى عميل في قاعدة بيانات الواجهة الخلفية، ثم التحقق من صلاحية كل طلب، ويمكن في هذه الحالة إزالة صلاحية هذا المفتاح مباشرةً عند الحاجة. يُشار إلى هذا الأسلوب عادةً بجلسة عمل على الخادم server-side session.
</p>

<p>
	لنوسّع الآن المنظومة كي يُمنع المستخدم الذي فقد قدرته على الوصول إليها من إجراء أي تفاعل يتطلب تسجيل دخول.
</p>

<p>
	قد تحتاج إلى ما يلي لإنجاز الأمر:
</p>

<ul>
<li>
		عمودٌ يضم قيمًا منطقية في جدول المستخدمين يشير إلى كون المستخدم نشطًا أم لا. يكفي في تمريننا أن توقف نشاط مستخدم أو تعيده من خلال قاعدة البيانات مباشرةً.
	</li>
	<li>
		جدولٌ يُخزّن جلسات العمل الجارية
	</li>
	<li>
		تُخزَّن الجلسة عند تسجيل الدخول (عند تنفيذ الطلب "POST /api/login").
	</li>
	<li>
		يجري التحقق من وجود جلسة أو صلاحيتها عندما يُنفِّذ المستخدم عمليةً تتطلب تسجيل دخول.
	</li>
	<li>
		وجهةٌ تسمح للمستخدم بتسجيل خروجه من المنظومة لإزالة الجلسة من قاعدة البيانات، وقد يكون للوجهة المسار التالي "DELETE /api/logout".
	</li>
</ul>
<p>
	تذكر أنه لا يسمح بنجاح أي عملية تتطلب تسجيل دخول إذا كان مفتاح الاستيثاق منتهي الصلاحية، مثل الحالة التي يسجل فيها المستخدم خروجه.
</p>

<p>
	قد ترغب أيضًا في استخدام مكتبة npm مخصصة للتعامل مع الجلسات، ولا تنسى استخدام ملف التهجير لتنفيذ التغييرات اللازمة على قاعدة البيانات.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part13/migrations_many_to_many_relationships" rel="external nofollow">migrations, many-to-many relationships</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/%D8%B6%D9%85-%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B4%D8%AA%D8%B1%D9%83%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-sequelize-r656/" rel="">ضم الجداول والاستعلامات المشتركة في قواعد البيانات باستخدام Sequelize</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">المفاهيم الأساسية في قواعد البيانات وتصميمها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/laravel/%d8%aa%d9%87%d8%ac%d9%8a%d8%b1-%d9%82%d9%88%d8%a7%d8%b9%d8%af-%d8%a7%d9%84%d8%a8%d9%8a%d8%a7%d9%86%d8%a7%d8%aa-%d9%81%d9%8a-laravel-5-r224/" rel="">تهجير قواعد البيانات في Laravel 5</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/laravel/%D8%AA%D8%AC%D8%B1%D9%8A%D8%AF-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%A7%D8%B1%D8%A7%D9%81%D9%8A%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%87%D8%AC%D9%8A%D8%B1-migration-%D9%88%D8%A7%D9%84%D8%A8%D8%B0%D8%B1-seeder-r1725/" rel="">تجريد إعداد قواعد البيانات في لارافيل باستعمال عملية التهجير Migration والبذر Seeder</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">657</guid><pubDate>Thu, 03 Nov 2022 09:01:22 +0000</pubDate></item><item><title>&#x636;&#x645; &#x627;&#x644;&#x62C;&#x62F;&#x627;&#x648;&#x644; &#x648;&#x627;&#x644;&#x627;&#x633;&#x62A;&#x639;&#x644;&#x627;&#x645;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x634;&#x62A;&#x631;&#x643;&#x629; &#x641;&#x64A; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Sequelize</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%B6%D9%85-%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B4%D8%AA%D8%B1%D9%83%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-sequelize-r656/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/636372e2b4163_---------Sequelize.png.c415b1b26797ea9e93dcd0501b7583e8.png" /></p>

<p>
	نستعرض في هذا المقال طريقة هيكلة التطبيق الذي عملنا عليه في <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%B9%D9%84%D8%A7%D9%82%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-sequelize-r655/" rel="">المقال السابق</a>، والاستعلام عن معلومات متنوعة تضمها قاعدة البيانات العلاقية.
</p>

<h2>
	هيكلية التطبيق
</h2>

<p>
	لقد كتبنا حتى اللحظة كامل الشيفرة في نفس الملف، لهذا سنحاول الآن إعطاء التطبيق هيكلًا أوضح. لننشئ إذًا المجلدات والملفات وفق الهيكلية التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_8" style="">
<span class="pln">index</span><span class="pun">.</span><span class="pln">js
util
  config</span><span class="pun">.</span><span class="pln">js
  db</span><span class="pun">.</span><span class="pln">js
models
  index</span><span class="pun">.</span><span class="pln">js
  note</span><span class="pun">.</span><span class="pln">js
controllers
  notes</span><span class="pun">.</span><span class="pln">js</span></pre>

<p>
	أما محتوى الملفات فستكون على النحو التالي:
</p>

<ul>
<li>
		الملف "util/config.js": يهتم بالتعامل مع متغيرات البيئة environment variables:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_10" style="">
<span class="pln">require</span><span class="pun">(</span><span class="str">'dotenv'</span><span class="pun">).</span><span class="pln">config</span><span class="pun">()</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  DATABASE_URL</span><span class="pun">:</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">DATABASE_URL</span><span class="pun">,</span><span class="pln">
  PORT</span><span class="pun">:</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">PORT </span><span class="pun">||</span><span class="pln"> </span><span class="lit">3001</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
<li>
		الملف "index.js": ويهتم بتهيئة وتشغيل التطبيق:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_12" style="">
<span class="kwd">const</span><span class="pln"> express </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'express'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> PORT </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./util/config'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> connectToDatabase </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./util/db'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> notesRouter </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./controllers/notes'</span><span class="pun">)</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="pln">express</span><span class="pun">.</span><span class="pln">json</span><span class="pun">())</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/notes'</span><span class="pun">,</span><span class="pln"> notesRouter</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> start </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  await connectToDatabase</span><span class="pun">()</span><span class="pln">
  app</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span class="pln">PORT</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">Server</span><span class="pln"> running on port $</span><span class="pun">{</span><span class="pln">PORT</span><span class="pun">}`)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

start</span><span class="pun">()</span></pre>

<p>
	يختلف تشغيل التطبيق قليلًا عما رأيناه سابقًا، لأننا نريد التأكُّد من نجاح الاتصال بقاعدة البيانات قبل أن يبدأ التطبيق العمل الفعلي.
</p>

<ul>
<li>
		الملف "util/d b.js": ويضم الشيفرة التي تُهيئ قاعدة البيانات:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_14" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> DATABASE_URL </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./config'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> sequelize </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">(</span><span class="pln">DATABASE_URL</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dialectOptions</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      require</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      rejectUnauthorized</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> connectToDatabase </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await sequelize</span><span class="pun">.</span><span class="pln">authenticate</span><span class="pun">()</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'connected to the database'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'failed to connect to the database'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> connectToDatabase</span><span class="pun">,</span><span class="pln"> sequelize </span><span class="pun">}</span></pre>

<ul>
<li>
		الملف "models/note.js": وتُخزّن فيه الملاحظات في النموذج المقابل للجدول الذي سيُحفظ.
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_16" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Model</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> sequelize </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../util/db'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> extends </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  content</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">TEXT</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">BOOLEAN
  </span><span class="pun">},</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">DATE
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'note'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Note</span></pre>

<ul>
<li>
		الملف "models/index.js": لا يُستخدم حاليًا تقريبًا بسبب وجود نموذج واحد فقط في التطبيق، لكنه سيصبح أكثر فائدةً عندما نبدأ إضافة نماذج جديدة، إذ سيلغي الحاجة إلى إدراج ملفات منفصلة تُعرِّف بقية النماذج:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_18" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./note'</span><span class="pun">)</span><span class="pln">

</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">sync</span><span class="pun">()</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Note</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
<li>
		الملف "controllers/notes.js": ويضم الوجهات المرتبطة بالملاحظات، أي مسار التوجيه إلى ملاحظة:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_20" style="">
<span class="kwd">const</span><span class="pln"> router </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'express'</span><span class="pun">).</span><span class="typ">Router</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../models'</span><span class="pun">)</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">()</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">)</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">400</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">delete</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await note</span><span class="pun">.</span><span class="pln">destroy</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">204</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">important
    await note</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> router</span></pre>

<p>
	هكذا يبدو هيكل التطبيق جيدًا الآن، لكننا نلاحظ أنّ معالجات التوجيه route handlers الذي يتعامل مع ملاحظة واحدة يضم قليلًا من الشيفرات المكررة، فجميعها تبدأ بالسطر الذي يبحث عن الملاحظة التي يتعامل معها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_22" style="">
<span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span></pre>

<p>
	لنعيد كتابة الشيفرة على شكل أداة وسطية middleware خاصةٍ بنا، ونطبّقها في معالجات التوجيه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_24" style="">
<span class="kwd">const</span><span class="pln"> noteFinder </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">,</span><span class="pln"> next</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  req</span><span class="pun">.</span><span class="pln">note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  next</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> noteFinder</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">delete</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> noteFinder</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await req</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">destroy</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">204</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> noteFinder</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    req</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">important
    await req</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تستقبل معالجات الوجهة ثلاثة معاملات: الأول نصي يُعرّف الوجهة، والثاني الأداة الوسطية <code>noteFinder</code> المُعرفة مُسبقًا والتي تستخلص الملاحظة من قاعدة البيانات وتضعها في الخاصية <code>note</code> للكائن <code>req</code>.
</p>

<p>
	بإمكانك إيجاد الشيفرة الحالية للتطبيق <a href="https://github.com/fullstack-hy/part13-notes/tree/part13-2" rel="external nofollow">كاملةً في المستودع المخصص على GitHub</a> ضمن الفرع part13-2.
</p>

<h2>
	التمرينات 13.5 إلى 13.7
</h2>

<p>
	حاول إنجاز التمارين التالية
</p>

<h3>
	التمرين 13.5
</h3>

<p>
	غيّر هيكل تطبيقك ليشابه المثال السابق أو اتبع هيكليةً أخرى واضحة وملائمة.
</p>

<h3>
	التمرين 13.6
</h3>

<p>
	قدِّم طريقةً تدعم تغيير عدد الإعجابات بمدوّنة في تطبيقك مستخدمًا العملية "PUT /api/blogs/:id"، إذ ينبغي أن يصل العدد الجديد للإعجابات مع الطلب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_26" style="">
<span class="pun">{</span><span class="pln">
  likes</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	التمرين 13.7
</h3>

<p>
	استخدم أداةً وسطيةً للتحكم المركزي بمعالجة الأخطاء كما فعلنا في <a href="https://academy.hsoub.com/programming/javascript/nodejs/express/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-nodejs-%D9%88express-r1099/" rel="">القسم 3</a> كما يمكنك استخدام الأداة الوسطية <a href="https://github.com/davidbanham/express-async-errors" rel="external nofollow">express-async-errors</a> كما فعلنا في <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%87%D9%8A%D9%83%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-unit-tests-r1132/" rel="">القسم 4</a>. لا تهتم للبيانات المُعادة في سياق رسالة الخطأ.
</p>

<p>
	حتى اللحظة لا تتطلب سوى حالتين في التطبيق معالجةً للأخطاء، هما: إضافة مدوّنة جديدة وتغيير عدد الإعجابات، لذلك تأكد من قدرة معالج الأخطاء على التعامل مع هاتين الحالتين بما يلائمهما.
</p>

<h2>
	إدارة المستخدمين
</h2>

<p>
	سنضيف تاليًا جدول قاعدة بيانات يُدعى "users" تُخزّن في فيه بيانات مستخدمي التطبيق، كما سنضيف أيضًا وظيفةً لإضافة مستخدمين جدد وآلية تسجيل دخول مبنية على مفاتيح الاستيثاق كما فعلنا في القسم 4، ولكي نبسط العمل، سنُعدِّل ما أنجزناه سابقًا كي يكون لجميع المستخدمين كلمة المرور ذاتها وهي "secret".
</p>

<p>
	محتوى الملف "models/user.js" الذي يُعرّف المستخدمين واضحٌ تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_28" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Model</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> sequelize </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../util/db'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> extends </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  username</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">STRING</span><span class="pun">,</span><span class="pln">
    unique</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">STRING</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'user'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span></pre>

<p>
	سيكون حقل اسم المستخدم "username" ذا قيم فريدة، لكن وعلى الرغم من إمكانية جعله المفتاح الرئيسي للجدول، إلا أننا قررنا أن ننشئ حقلًا field منفصلًا "id" ذا قيم صحيحة ليكون المفتاح الرئيسي.
</p>

<p>
	سيتوسع الملف "models/index.js" قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_30" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./note'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./user'</span><span class="pun">)</span><span class="pln">

</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">sync</span><span class="pun">()</span><span class="pln">
</span><span class="typ">User</span><span class="pun">.</span><span class="pln">sync</span><span class="pun">()</span><span class="pln">
module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Note</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا يضم الملف "controllers/users.js" الذي يحتوي معالجات الوجهة التي تهتم بإنشاء مستخدمين جدد أي شيء مهم حاليًا سوى عرض كل المستخدمين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_32" style="">
<span class="kwd">const</span><span class="pln"> router </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'express'</span><span class="pun">).</span><span class="typ">Router</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../models'</span><span class="pun">)</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> users </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">()</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">users</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">)</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">400</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> router</span></pre>

<p>
	أما معالج الوجهة الذي يتحكم بتسجيل الدخول (الملف "controllers/login.js") فسيكون على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_34" style="">
<span class="kwd">const</span><span class="pln"> jwt </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'jsonwebtoken'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> router </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'express'</span><span class="pun">).</span><span class="typ">Router</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> SECRET </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../util/config'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../models/user'</span><span class="pun">)</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> body </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">body

  </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findOne</span><span class="pun">({</span><span class="pln">
    where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      username</span><span class="pun">:</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">username
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> passwordCorrect </span><span class="pun">=</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">password </span><span class="pun">===</span><span class="pln"> </span><span class="str">'secret'</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!(</span><span class="pln">user </span><span class="pun">&amp;&amp;</span><span class="pln"> passwordCorrect</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">401</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln">
      error</span><span class="pun">:</span><span class="pln"> </span><span class="str">'invalid username or password'</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> userForToken </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    username</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">username</span><span class="pun">,</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> token </span><span class="pun">=</span><span class="pln"> jwt</span><span class="pun">.</span><span class="pln">sign</span><span class="pun">(</span><span class="pln">userForToken</span><span class="pun">,</span><span class="pln"> SECRET</span><span class="pun">)</span><span class="pln">

  response
    </span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">200</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">send</span><span class="pun">({</span><span class="pln"> token</span><span class="pun">,</span><span class="pln"> username</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">username</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">name </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> router</span></pre>

<p>
	سيُرفق اسم المستخدم وكلمة المرور مع <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-http-%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D8%AA%D8%AE%D8%A7%D8%B7%D8%A8-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-r74/" rel="">طلب POST</a>، ويُستخلص الكائن المتعلق باسم المستخدم أولًا من قاعدة البيانات باستخدام التابع <a href="https://sequelize.org/master/manual/model-querying-finders.html#-code-findone--code-" rel="external nofollow">findOne</a> العائد للنموذج <code>User</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_36" style="">
<span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findOne</span><span class="pun">({</span><span class="pln">
  where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    username</span><span class="pun">:</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">username
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يمكنك أن تلاحظ من خلال الطرفية أن <a href="https://academy.hsoub.com/programming/sql/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-sql-r844/" rel="">تعليمة SQL</a> المتعلقة باستدعاء التابع السابق هي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4804_38" style="">
<span class="pln">SELECT </span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"username"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"name"</span><span class="pln">
FROM </span><span class="str">"users"</span><span class="pln"> AS </span><span class="str">"User"</span><span class="pln">
WHERE </span><span class="str">"User"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"username"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'mluukkai'</span><span class="pun">;</span></pre>

<p>
	إن وُجد المستخدم وكانت كلمة المرور صحيحة (وهي "secret" لجميع المستخدمين)، يُعاد مفتاح الاستيثاق "jsonwebtoken" متضمنًا معلومات المستخدم مع الاستجابة. لهذا سنُثبّت الاعتمادية "jsonwebtoken":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_41" style="">
<span class="pln">npm install jsonwebtoken</span></pre>

<p>
	سيتوسع الملف "index.js" قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_43" style="">
<span class="kwd">const</span><span class="pln"> notesRouter </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./controllers/notes'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> usersRouter </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./controllers/users'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> loginRouter </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./controllers/login'</span><span class="pun">)</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="pln">express</span><span class="pun">.</span><span class="pln">json</span><span class="pun">())</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/notes'</span><span class="pun">,</span><span class="pln"> notesRouter</span><span class="pun">)</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/users'</span><span class="pun">,</span><span class="pln"> usersRouter</span><span class="pun">)</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/login'</span><span class="pun">,</span><span class="pln"> loginRouter</span><span class="pun">)</span></pre>

<p>
	يمكنك الحصول على شيفرة التطبيق بوضعها الحالي من <a href="https://github.com/fullstack-hy/part13-notes/tree/part13-3" rel="external nofollow">المستودع المخصص على GitHub</a> ضمن الفرع part13-3.
</p>

<h2>
	الاتصال بين الجداول
</h2>

<p>
	يمكن الآن إضافة مستخدمين إلى التطبيق، كما يمكن للمستخدمين تسجيل الدخول، لكنها ليست ميزات مفيدة جدًا في وضعها الحالي، لذلك سنضيف ميزات لا يمكن للمستخدم الاستفادة منها ما لم يُسجل دخوله مثل إضافة ملاحظة جديدة، إذ ترتبط هذه الملاحظة بالمستخدم الذي أنشأها، ولهذا لا بُدّ من إضافة مفتاح خارجي foreign key إلى جدول "notes".
</p>

<p>
	يمكن تعريف المفتاح الخارجي عند استخدام مكتبة Sequelize بتعديل الملف "models/index.js" على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_45" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./note'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./user'</span><span class="pun">)</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">hasMany</span><span class="pun">(</span><span class="typ">Note</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">belongsTo</span><span class="pun">(</span><span class="typ">User</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">sync</span><span class="pun">({</span><span class="pln"> alter</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
</span><span class="typ">User</span><span class="pun">.</span><span class="pln">sync</span><span class="pun">({</span><span class="pln"> alter</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Note</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا نكون قد عرّفنا علاقة واحد-إلى-متعدد one-to-many تصل بين جدولي المستخدمين "users" والملاحظات "notes"، كما عدّلنا الخيارات في استدعاءات <code>sync</code> لتتطابق جداول قاعدة البيانات مع التغييرات التي حدثت على تعريفات النموذج. سيبدو مخطط قاعدة البيانات على شاشة الطرفية على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_47" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> \d users
                                     </span><span class="typ">Table</span><span class="pln"> </span><span class="str">"public.users"</span><span class="pln">
  </span><span class="typ">Column</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Collation</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Nullable</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Default</span><span class="pln">
</span><span class="pun">----------+------------------------+-----------+----------+-----------------------------------</span><span class="pln">
 id </span><span class="pun">|</span><span class="pln"> integer </span><span class="pun">|</span><span class="pln"> not </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> nextval</span><span class="pun">(</span><span class="str">'users_id_seq'</span><span class="pun">::</span><span class="pln">regclass</span><span class="pun">)</span><span class="pln">
 username </span><span class="pun">|</span><span class="pln"> character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> not </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
 name </span><span class="pun">|</span><span class="pln"> character varying</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> not </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="typ">Indexes</span><span class="pun">:</span><span class="pln">
    </span><span class="str">"users_pkey"</span><span class="pln"> PRIMARY KEY</span><span class="pun">,</span><span class="pln"> btree </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Referenced</span><span class="pln"> by</span><span class="pun">:</span><span class="pln">
    TABLE </span><span class="str">"notes"</span><span class="pln"> CONSTRAINT </span><span class="str">"notes_user_id_fkey"</span><span class="pln"> FOREIGN KEY </span><span class="pun">(</span><span class="pln">user_id</span><span class="pun">)</span><span class="pln"> REFERENCES users</span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> ON UPDATE CASCADE ON DELETE SET NULL

username</span><span class="pun">=&gt;</span><span class="pln"> \d notes
                                      </span><span class="typ">Table</span><span class="pln"> </span><span class="str">"public.notes"</span><span class="pln">
  </span><span class="typ">Column</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Collation</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Nullable</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Default</span><span class="pln">
</span><span class="pun">-----------+--------------------------+-----------+----------+-----------------------------------</span><span class="pln">
 id </span><span class="pun">|</span><span class="pln"> integer </span><span class="pun">|</span><span class="pln"> not </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> nextval</span><span class="pun">(</span><span class="str">'notes_id_seq'</span><span class="pun">::</span><span class="pln">regclass</span><span class="pun">)</span><span class="pln">
 content </span><span class="pun">|</span><span class="pln"> text </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> not </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
 important </span><span class="pun">|</span><span class="pln"> boolean </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
 date </span><span class="pun">|</span><span class="pln"> timestamp </span><span class="kwd">with</span><span class="pln"> time zone </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
 user_id </span><span class="pun">|</span><span class="pln"> integer </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="typ">Indexes</span><span class="pun">:</span><span class="pln">
    </span><span class="str">"notes_pkey"</span><span class="pln"> PRIMARY KEY</span><span class="pun">,</span><span class="pln"> btree </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Foreign</span><span class="pun">-</span><span class="pln">key constraints</span><span class="pun">:</span><span class="pln">
    </span><span class="str">"notes_user_id_fkey"</span><span class="pln"> FOREIGN KEY </span><span class="pun">(</span><span class="pln">user_id</span><span class="pun">)</span><span class="pln"> REFERENCES users</span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> ON UPDATE CASCADE ON DELETE SET NULL</span></pre>

<p>
	يشير المفتاح الخارجي <code>user_id</code> الذي أُنشئ في الجدول <code>notes</code> إلى أسطر في الجدول <code>users</code>.
</p>

<p>
	لنربط الآن كل ملاحظة جديدة بالمستخدم الذي أنشأها، ولكن قبل تقديم الأمر (ربط الملاحظة بمفتاح استيثاق المستخدم الذي استخدمه لتسجيل دخوله)، لا بُد من كتابة الملاحظة التي ترتبط بالمستخدم الأول الذي يُعثر عليه يدويًا في الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_49" style="">
<span class="pln">router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findOne</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">create</span><span class="pun">({...</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">,</span><span class="pln"> userId</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">id</span><span class="pun">})</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">400</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	انتبه إلى وجود العمود <code>user_id</code> في جدول الملاحظات "notes" على مستوى قاعدة البيانات، ويُشار إلى اسم كل صف في قاعدة البيانات بالطريقة التقليدية للمكتبة Sequelize، وذلك بكتابته على نقيض أسلوب سنام الجمل "userId"، أي كما تُكتب تمامًا في الشيفرة (حروف صغيرة).
</p>

<p>
	من السهل تنفيذ استعلامات مشتركة في Sequelize، لهذا سنغيّر الوجهة التي تعيد كل المستخدمين لتعرض كل ملاحظات المستخدم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4804_51" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> users </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">users</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يُنفَّذ الاستعلام المشترك باستخدام الخيار <a href="https://sequelize.org/master/manual/assocs.html#eager-loading-example" rel="external nofollow">include</a> مثل معامل استعلام، أما تعليمة SQL المولّدة من الاستعلام، فستُطبع على شاشة الطرفية على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4804_53" style="">
<span class="pln">SELECT </span><span class="str">"User"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"User"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"username"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"User"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"name"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Notes"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln"> AS </span><span class="str">"Notes.id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Notes"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"content"</span><span class="pln"> AS </span><span class="str">"Notes.content"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Notes"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pln"> AS </span><span class="str">"Notes.important"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Notes"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"date"</span><span class="pln"> AS </span><span class="str">"Notes.date"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Notes"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"user_id"</span><span class="pln"> AS </span><span class="str">"Notes.UserId"</span><span class="pln">
FROM </span><span class="str">"users"</span><span class="pln"> AS </span><span class="str">"User"</span><span class="pln"> LEFT OUTER JOIN </span><span class="str">"notes"</span><span class="pln"> AS </span><span class="str">"Notes"</span><span class="pln"> ON </span><span class="str">"User"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Notes"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"user_id"</span><span class="pun">;</span></pre>

<p>
	ستبدو النتيجة النهائية كما تتوقع:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111201" href="https://academy.hsoub.com/uploads/monthly_2022_11/01_joint_query.png.7aa7f870132a358b8541369d6ab79945.png" rel=""><img alt="النتيجة النهائية للتمرين باستخدام jQuery" class="ipsImage ipsImage_thumbnailed" data-fileid="111201" data-unique="aef0r9v36" src="https://academy.hsoub.com/uploads/monthly_2022_11/01_joint_query.png.7aa7f870132a358b8541369d6ab79945.png" style="width: 600px; height: auto;"></a>
</p>

<h2>
	الإضافة الملائمة للملاحظات
</h2>

<p>
	لنحاول تغيير طريقة إضافة الملاحظات لتعمل بالطريقة التي عملت بها من قبل، بحيث ينجح إنشاء الملاحظات فقط إذا حمل طلب إنشائها مفتاح استيثاق صحيح عند تسجيل الدخول. تُخزّن بعدها الملاحظة ضمن قائمة الملاحظات التي أنشأها المستخدم المُعرّف بواسطة مفتاح الاستيثاق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_12" style="">
<span class="kwd">const</span><span class="pln"> tokenExtractor </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">,</span><span class="pln"> next</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> authorization </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'authorization'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">authorization </span><span class="pun">&amp;&amp;</span><span class="pln"> authorization</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">().</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">'bearer '</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      req</span><span class="pun">.</span><span class="pln">decodedToken </span><span class="pun">=</span><span class="pln"> jwt</span><span class="pun">.</span><span class="pln">verify</span><span class="pun">(</span><span class="pln">authorization</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">(</span><span class="lit">7</span><span class="pun">),</span><span class="pln"> SECRET</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">{</span><span class="pln">
      res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">401</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error</span><span class="pun">:</span><span class="pln"> </span><span class="str">'token invalid'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">  </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">401</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error</span><span class="pun">:</span><span class="pln"> </span><span class="str">'token missing'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  next</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> tokenExtractor</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">decodedToken</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">create</span><span class="pun">({...</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">,</span><span class="pln"> userId</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">()})</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">400</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يُستخلص مفتاح الاستيثاق من ترويسة الطلب ويفُك تشفيره ويوضع ضمن الكائن <code>req</code> بواسطة الأداة الوسطية <code>tokenExtractor</code>. يُضاف زمن الإنشاء إلى الحقل <code>date</code> أيضًا عند إنشاء الملاحظة.
</p>

<h2>
	ضبط الواجهة الخلفية
</h2>

<p>
	تعمل الواجهة الخلفية حتى اللحظة بنفس الطريقة التي تعمل بها في نسخة القسم 4 من التطبيق ماعدا فكرة معالجة الأخطاء. لنغيّر الآن وجهات إحضار جميع الملاحظات وجميع المستخدمين قليلًا قبل توسيع هذه الواجهة.
</p>

<p>
	سنضيف إلى كل ملاحظة بعض المعلومات المتعلقة بالمستخدم الذي أنشأها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_16" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
    attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">User</span><span class="pun">,</span><span class="pln">
      attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	<a href="https://sequelize.org/master/manual/model-querying-basics.html#specifying-attributes-for-select-queries" rel="external nofollow">كنا قد قيّدنا سابقًا</a> القيم التي يأخذها الحقل المطلوب، إذ كنا نعيد جميع حقول البيانات الخاصة بكل ملاحظة بما في ذلك اسم المستخدم "name" الذي يرتبط بالملاحظة لكن باستثناء حقل المعرّف الفريد للمستخدم "userId".
</p>

<p>
	لنجرِ التغيير ذاته على الوجهة route التي تحضر جميع المستخدمين والملاحظات وذلك بإزالة الحقل <code>userId</code> غير الضروري من الملاحظات المرتبطة بمستخدم معين على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_18" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> users </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      model</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">,</span><span class="pln">
      attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">users</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يمكنك الحصول على شيفرة التطبيق بوضعها الحالي من <a href="https://github.com/fullstack-hy/part13-notes/tree/part13-4" rel="external nofollow">المستودع المخصص على GitHub</a> ضمن الفرع part13-4.
</p>

<h2>
	قليل من الانتباه إلى تعريفات النماذج
</h2>

<p>
	رغم وجود العمود <code>‍‍‌‍‍user_id</code>، إلا أننا لم نغيّر النموذج الذي يعرّف الملاحظات، ولكن يمكننا مع ذلك إضافة مستخدم إلى كائن الملاحظة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_20" style="">
<span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">decodedToken</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">create</span><span class="pun">({</span><span class="pln"> </span><span class="pun">...</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">,</span><span class="pln"> userId</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">()</span><span class="pln"> </span><span class="pun">})</span></pre>

<p>
	يعود السبب وراء ذلك إلى أننا لم نحدّد وجود علاقة واحد-إلى-متعدد في الاتصال بين جدولي المستخدمين "users" والملاحظات "notes" ضمن الملف "models/index.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_23" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./note'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./user'</span><span class="pun">)</span><span class="pln">

</span><span class="typ">User</span><span class="pun">.</span><span class="pln">hasMany</span><span class="pun">(</span><span class="typ">Note</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">belongsTo</span><span class="pun">(</span><span class="typ">User</span><span class="pun">)</span><span class="pln">

</span><span class="com">// ...</span></pre>

<p>
	تُنشئ المكتبة Sequelize تلقائيًا سمةً تُدعى <code>userId</code> في النموذج <code>Note</code> تمنح وصولًا إلى العمود <code>user_id</code> عندما يُشار إليه. وتذكّر أنه يمكنك إنشاء ملاحظة باستخدام التابع <a href="https://sequelize.org/master/class/lib/model.js~Model.html#static-method-build" rel="external nofollow">build</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_25" style="">
<span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">decodedToken</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">

</span><span class="com">// إنشاء ملاحظة دون تخزينها بعد</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">build</span><span class="pun">({</span><span class="pln"> </span><span class="pun">...</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">,</span><span class="pln"> date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">()</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
 </span><span class="com">// للملاحظة المُنشأة userId وضع المعرف الفريد للمستخدم في خاصية</span><span class="pln">
note</span><span class="pun">.</span><span class="pln">userId </span><span class="pun">=</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">id
</span><span class="com">// تخزين كائن الملاحظة في قاعدة البيانات</span><span class="pln">
await note</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span></pre>

<p>
	هكذا نرى صراحة أن <code>userId</code> هي سمة attribute لكائن الملاحظات، وقد كان بالإمكان تعريف النموذج على النحو التالي للحصول على النتيجة ذاتها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_27" style="">
<span class="typ">Note</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  content</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">TEXT</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">BOOLEAN
  </span><span class="pun">},</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">DATE
  </span><span class="pun">},</span><span class="pln">
  userId</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
    allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    references</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> model</span><span class="pun">:</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">,</span><span class="pln"> key</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  sequelize</span><span class="pun">,</span><span class="pln">
  underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'note'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Note</span></pre>

<p>
	لا يوجد داعٍ للتعريف على مستوى الصنف في النموذج كما فعلنا سابقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_29" style="">
<span class="typ">User</span><span class="pun">.</span><span class="pln">hasMany</span><span class="pun">(</span><span class="typ">Note</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">belongsTo</span><span class="pun">(</span><span class="typ">User</span><span class="pun">)</span></pre>

<p>
	وبدلًا من ذلك يمكننا تحقيق الأمر بهذه الطريقة، ولا بُد من استخدام إحدى هاتين الطريقتين وإلا لن تُدرك مكتبة Sequelize كيف يتصل الجدولين ببعضهما على مستوى الشيفرة.
</p>

<h2>
	التمرينات 13.8 إلى 13.11
</h2>

<p>
	حاول إنجاز التمارين الآتية:
</p>

<h3>
	التمرين 13.8
</h3>

<p>
	زِد دعم التطبيق لمستخدميه، إذ لا بُد أن يضم جدول المستخدمين الحقول التالية إضافةً إلى الحقل "ID":
</p>

<ul>
<li>
		name: ذو قيمة نصية (لا يمكن أن يكون فارغًا).
	</li>
	<li>
		username: ذو قيمة نصية (لا يمكن أن يكون فارغًا).
	</li>
</ul>
<p>
	وعلى خلاف ما أوردنا في الشروحات النظرية، لا تمنع مكتبة Sequelize حاليًا إنشاء البصمتين الزمنيتين <em>create_d<em>at</em> و <em>update_d</em>at</em> لجدول المستخدمين.
</p>

<p>
	يمكن إعطاء كلمة المرور نفسها لجميع المستخدمين، وكذلك اختيار طريقة التحقق من كلمة المرور كما في القسم 4، وعليك أيضًا إنجاز الوجهات التالية:
</p>

<ul>
<li>
		"POST api/users": لإضافة مستخدم جديد.
	</li>
	<li>
		"GET api/users": عرض جميع المستخدمين.
	</li>
	<li>
		"PUT api/users/:username": لتغيير اسم المستخدم وليس المعرّف "id".
	</li>
</ul>
<p>
	تأكد من إدراج البصمات الزمنية تلقائيًا من قِبل مكتبة Sequelize وعلى النحو الصحيح عند إضافة مستخدم أو تغيير اسمه.
</p>

<h3>
	التمرين 13.9
</h3>

<p>
	تزودنا مكتبة Sequelize بمجموعة قواعد تحقق معرّفةٌ مسبقًا للتأكد من قيم حقول النموذج تُنفّذها قبل تخزين الكائنات في قاعدة البيانات. ولأننا نريد تغيير سياسة إنشاء مستخدم جديد تتطلب أن يكون البريد الإلكتروني المُدخل صحيحًا كما هو حال اسم المستخدم، أنجِز طريقةً للتحقق من ذلك أثناء إنشاء المستخدم.
</p>

<p>
	عدّل أيضًا بالأداة الوسطية المستخدمة في معالجة الأخطاء لتعرض وصفًا أكثر وضوحًا لرسالة الخطأ مثل استخدام رسائل خطأ Sequelize على سبيل المثال.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_31" style="">
<span class="pun">{</span><span class="pln">
    </span><span class="str">"error"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="str">"Validation isEmail on username failed"</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	التمرين 13.10
</h3>

<p>
	وسّع التطبيق لكي تربط كل مستخدم سجّل دخوله بنجاح عبر مفتاح الاستيثاق بكل مدونة يضيفها. لا بُد من تقديم وصلة endpoint تسجيل دخول "POST /api/login" تُعيد مفتاح الاستيثاق.
</p>

<h3>
	التمرين 13.11
</h3>

<p>
	تأكد أن المستخدم قادرٌ فقط على حذف المدونات التي يضيفها.
</p>

<h3>
	التمرين 13.12
</h3>

<p>
	عدّل الوجهات كي تكون قادرًا على استخلاص جميع المدوّنات والمستخدمين كي تعرض كل مدوّنة المستخدم الذي أضافها وأن يعرض كل مستخدم المدوّنات التي أضافها.
</p>

<h2>
	استعلامات أوسع
</h2>

<p>
	لا يزال تطبيقنا حتى اللحظة بسيطًا من ناحية الاستعلامات التي يجريها، إذ اقتصر البحث على صف واحد بناءً على مفتاح رئيسي من خلال التابع "findByPk"، أو البحث عن كل الصفوف باستخدام التابع "findAll". كانت هذه الاستعلامات كافيةً بالنسبة للواجهة الأمامية في نسخة <a href="https://academy.hsoub.com/programming/javascript/react/%D8%AA%D8%B3%D8%AC%D9%8A%D9%84-%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-r1136/" rel="">القسم 5</a> من التطبيق، لكننا سنوّسع الواجهة الخلفية لنتمكن من تنفيذ استعلامات أعقد قليلًا.
</p>

<p>
	لننجز أولًا طريقة للحصول على ملاحظات مصنّفة على أنها مهمة أو غير مهمة فقط، باستخدام معامل الاستعلام <code>important</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_33" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
    attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      model</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">,</span><span class="pln">
      attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">important </span><span class="pun">===</span><span class="pln"> </span><span class="str">"true"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وهكذا ستتمكن الواجهة الخلفية من استخلاص الملاحظات المهمة عند وصول الطلب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_35" style="">
<span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:3001/api/notes?important=true</span></pre>

<p>
	والملاحظات غير المهمة عند وصول الطلب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_37" style="">
<span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:3001/api/notes?important=false</span></pre>

<p>
	يتضمن استعلام SQL الذي ولّدته Sequelize العبارة <code>WHERE</code>، التي تُرشّح الصفوف المُعادة في الحالة الطبيعية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6819_41" style="">
<span class="pln">SELECT </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"content"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"date"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln"> AS </span><span class="str">"user.id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"name"</span><span class="pln"> AS </span><span class="str">"user.name"</span><span class="pln">
FROM </span><span class="str">"notes"</span><span class="pln"> AS </span><span class="str">"note"</span><span class="pln"> LEFT OUTER JOIN </span><span class="str">"users"</span><span class="pln"> AS </span><span class="str">"user"</span><span class="pln"> ON </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"user_id"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln">
WHERE </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span></pre>

<p>
	وبالطبع لن ينفع إنجاز الأمر بهذه الطريقة ما لم يهتم الاستعلام بأهمية الملاحظة، كأن يكون على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_43" style="">
<span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:3001/api/notes</span></pre>

<p>
	يمكن تدارك الموضوع بطرق عدة، أولها -وقد لا تكون الطريقة الأفضل- على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_45" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Op</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let important </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">[</span><span class="typ">Op</span><span class="pun">.</span><span class="pln">in</span><span class="pun">]:</span><span class="pln"> </span><span class="pun">[</span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">important </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    important </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">important </span><span class="pun">===</span><span class="pln"> </span><span class="str">"true"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
    attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      model</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">,</span><span class="pln">
      attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      important
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يُخزّن الكائن <code>important</code> الآن شرط الاستعلام، وسيكون الشكل الافتراضي لهذا الاستعلام على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6819_47" style="">
<span class="kwd">where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">[</span><span class="typ">Op</span><span class="pun">.</span><span class="kwd">in</span><span class="pun">]:</span><span class="pln"> </span><span class="pun">[</span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أي أن العمود قد يحمل إحدى القيمتين <code>true</code> أو <code>false</code> باستخدام العامل <a href="https://sequelize.org/master/manual/model-querying-basics.html#operators" rel="external nofollow">Op.in</a>، وهو أحد عوامل Sequelize العديدة؛ فإذا حددنا قيمة للمعامل <code>req.query.important</code>، سيتغير الاستعلام ليصبح بأحد الشكلين التاليين:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6819_49" style="">
<span class="kwd">where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أو
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6819_51" style="">
<span class="kwd">where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بناءً على قيمة معامل الاستعلام.
</p>

<p>
	يمكن زيادة القدرة الوظيفية للتطبيق بالسماح للمستخدم بتخصيص كلمة مفتاحية لإحضار البيانات، إذ يعيد الطلب التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_53" style="">
<span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:3001/api/notes?search=database</span></pre>

<p>
	الملاحظات التي تشير إلى الكلمة "database". كما يعيد الطلب التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_55" style="">
<span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:3001/api/notes?search=javascript&amp;important=true</span></pre>

<p>
	جميع الملاحظات التي حُددت أنها مهمة "important" وتشير إلى الكلمة "javascript".
</p>

<p>
	سيكون تنفيذ الأمر على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_57" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let important </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">[</span><span class="typ">Op</span><span class="pun">.</span><span class="pln">in</span><span class="pun">]:</span><span class="pln"> </span><span class="pun">[</span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">important </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    important </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">important </span><span class="pun">===</span><span class="pln"> </span><span class="str">"true"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
    attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      model</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">,</span><span class="pln">
      attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    where</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      important</span><span class="pun">,</span><span class="pln">
      content</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="pun">[</span><span class="typ">Op</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">]:</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">search </span><span class="pun">?</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">search </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يوّلد التابع <a href="https://sequelize.org/master/manual/model-querying-basics.html#operators" rel="external nofollow">Op.substring</a> الاستعلام الذي نريده باستخدام كلمة "LIKE"، فإذا أنشأت الاستعلام التالي مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_59" style="">
<span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:3001/api/notes?search=database&amp;important=true</span></pre>

<p>
	فسيولّد استعلام SQL ما نتوقعه تمامًا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6819_61" style="">
<span class="pln">SELECT </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"content"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"date"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln"> AS </span><span class="str">"user.id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"name"</span><span class="pln"> AS </span><span class="str">"user.name"</span><span class="pln">
FROM </span><span class="str">"notes"</span><span class="pln"> AS </span><span class="str">"note"</span><span class="pln"> LEFT OUTER JOIN </span><span class="str">"users"</span><span class="pln"> AS </span><span class="str">"user"</span><span class="pln"> ON </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"user_id"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln">
WHERE </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> AND </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"content"</span><span class="pln"> LIKE </span><span class="str">'%database%'</span><span class="pun">;</span></pre>

<p>
	لكن لا تزال هناك ثغرة مزعجة تتمثل في أن الطلب التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_63" style="">
<span class="pln"> http</span><span class="pun">:</span><span class="com">//localhost:3001/api/notes</span></pre>

<p>
	والذي يعني أننا نريد الحصول على جميع الملاحظات، سيتسبب في وجود عبارة <code>WHERE</code> غير الضرورية في الاستعلام، والتي قد تؤثر في فعاليته وفقًا لآلية عمل محرك قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6819_65" style="">
<span class="pln">SELECT </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"content"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"date"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln"> AS </span><span class="str">"user.id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"name"</span><span class="pln"> AS </span><span class="str">"user.name"</span><span class="pln">
FROM </span><span class="str">"notes"</span><span class="pln"> AS </span><span class="str">"note"</span><span class="pln"> LEFT OUTER JOIN </span><span class="str">"users"</span><span class="pln"> AS </span><span class="str">"user"</span><span class="pln"> ON </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"user_id"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln">
WHERE </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pln"> IN </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">)</span><span class="pln"> AND </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"content"</span><span class="pln"> LIKE </span><span class="str">'%%'</span><span class="pun">;</span></pre>

<p>
	لنحسّن الشيفرة لكي تُستخدم عبارة <code>WHERE</code> عند الحاجة فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_67" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> where </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    where</span><span class="pun">.</span><span class="pln">important </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">important </span><span class="pun">===</span><span class="pln"> </span><span class="str">"true"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">search</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    where</span><span class="pun">.</span><span class="pln">content </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="pun">[</span><span class="typ">Op</span><span class="pun">.</span><span class="pln">substring</span><span class="pun">]:</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">search
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">({</span><span class="pln">
    attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> exclude</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'userId'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    include</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      model</span><span class="pun">:</span><span class="pln"> user</span><span class="pun">,</span><span class="pln">
      attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    where
  </span><span class="pun">})</span><span class="pln">

  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وإذا احتوى الطلب على شرط للبحث مثل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_69" style="">
<span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:3001/api/notes?search=database&amp;important=true</span></pre>

<p>
	سيتولد استعلام يضم عبارة <code>WHERE</code>:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6819_71" style="">
<span class="pln">SELECT </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"content"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"date"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln"> AS </span><span class="str">"user.id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"name"</span><span class="pln"> AS </span><span class="str">"user.name"</span><span class="pln">
FROM </span><span class="str">"notes"</span><span class="pln"> AS </span><span class="str">"note"</span><span class="pln"> LEFT OUTER JOIN </span><span class="str">"users"</span><span class="pln"> AS </span><span class="str">"user"</span><span class="pln"> ON </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"user_id"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln">
WHERE </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> AND </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"content"</span><span class="pln"> LIKE </span><span class="str">'%database%'</span><span class="pun">;</span></pre>

<p>
	وإذا لم يحتوي شرطًا، فلن يكون لوجود <code>WHERE</code> حاجة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6819_73" style="">
<span class="pln">SELECT </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"content"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"important"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"date"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln"> AS </span><span class="str">"user.id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"name"</span><span class="pln"> AS </span><span class="str">"user.name"</span><span class="pln">
FROM </span><span class="str">"notes"</span><span class="pln"> AS </span><span class="str">"note"</span><span class="pln"> LEFT OUTER JOIN </span><span class="str">"users"</span><span class="pln"> AS </span><span class="str">"user"</span><span class="pln"> ON </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"user_id"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"user"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pun">;</span></pre>

<p>
	يمكنك الحصول على شيفرة التطبيق بوضعها الحالي من <a href="https://github.com/fullstack-hy/part13-notes/tree/part13-5" rel="external nofollow">المستودع المخصص على GitHub</a> ضمن الفرع part13-5.
</p>

<h2>
	التمرينات 13.13 إلى 13.16
</h2>

<p>
	حاول إنجاز التمرينات التالية:
</p>

<h3>
	التمرين 13.13
</h3>

<p>
	قدِّم آليةً لترشيح filtering النتائج من خلال كلمة مفتاحية ضمن الوجهة التي تعيد كل المدوّنات، وينبغي أن تعمل الآلية على النحو التالي:
</p>

<ul>
<li>
		<p>
			"GET /api/blogs?search=react": تعيد كل المدونات التي تضم الكلمة "react" في الحقل علمًا أن البحث حساس لحالة الأحرف.
		</p>
	</li>
	<li>
		<p>
			"GET /api/blogs": يعيد جميع المدوّنات.
		</p>
	</li>
</ul>
<p>
	يمكنك الاستفادة من <a href="https://sequelize.org/master/manual/model-querying-basics.html#operators" rel="external nofollow">عوامل Sequelize</a> لتنفيذ التمرين.
</p>

<h3>
	التمرين 13.14
</h3>

<p>
	وسّع آلية الترشيح للبحث عن كلمة مفتاحية في أحد الحقلين "field" أو "author"، إذ سيعيد الاستعلام:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6819_79" style="">
<span class="pln">GET </span><span class="pun">/</span><span class="pln">api</span><span class="pun">/</span><span class="pln">blogs</span><span class="pun">?</span><span class="pln">search</span><span class="pun">=</span><span class="pln">jami</span></pre>

<p>
	كل المدوّنات التي تضم الكلمة في أحد الحقلين "field" أو "author".
</p>

<h3>
	التمرين 13.15
</h3>

<p>
	عدّل وجهات المدوّنات لتعيد المدوّنات بناءً على عدد الإعجابات بترتيب تنازلي. اطلع من خلال <a href="https://sequelize.org/master/manual/model-querying-basics.html" rel="external nofollow">توثيق Sequelize</a> على تعليمات ترتيب نتائج الاستعلام.
</p>

<h3>
	التمرين 13.16
</h3>

<p>
	أنشئ الوجهة "api/authors/" كي تعيد عدد المدونات التي أضافها المؤلف والعدد الكلي للإعجابات. قدّم العملية على مستوى قاعدة البيانات. قد تحتاج إلى وظيفة التجميع <a href="https://sequelize.org/master/manual/model-querying-basics.html#grouping" rel="external nofollow">group by</a> ودالة التجميع <a href="https://sequelize.org/master/manual/model-querying-basics.html#specifying-attributes-for-select-queries" rel="external nofollow">sequelize.fn</a>.
</p>

<p>
	قد تبدو المعلومات المُعادة بتنسيق <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">JSON</a> على غرار المثال الآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6819_82" style="">
<span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    author</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Jami Kousa"</span><span class="pun">,</span><span class="pln">
    articles</span><span class="pun">:</span><span class="pln"> </span><span class="str">"3"</span><span class="pun">,</span><span class="pln">
    likes</span><span class="pun">:</span><span class="pln"> </span><span class="str">"10"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    author</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Kalle Ilves"</span><span class="pun">,</span><span class="pln">
    articles</span><span class="pun">:</span><span class="pln"> </span><span class="str">"1"</span><span class="pun">,</span><span class="pln">
    likes</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    author</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Dan Abramov"</span><span class="pun">,</span><span class="pln">
    articles</span><span class="pun">:</span><span class="pln"> </span><span class="str">"1"</span><span class="pun">,</span><span class="pln">
    likes</span><span class="pun">:</span><span class="pln"> </span><span class="str">"4"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	<strong>مهمة لعلامة إضافية</strong>: رتِّب البيانات المُعادة بناءً على عدد الإعجابات، على أن تُنفّذ عملية الترتيب من خلال استعلام قاعدة البيانات.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part13/join_tables_and_queries" rel="external nofollow">Join tables and queries</a> من سلسلة Deep Dive Into Modern Web Development
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%B9%D9%84%D8%A7%D9%82%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-sequelize-r655/" rel="">العمل مع قواعد بيانات علاقية باستخدام Sequelize</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/apps/productivity/office/%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D9%88%D8%A7%EF%BB%BB%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AA%D9%82%D8%A7%D8%B1%D9%8A%D8%B1-%D9%81%D9%8A-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D8%A7%D9%8A%D9%83%D8%B1%D9%88%D8%B3%D9%88%D9%81%D8%AA-%D8%A3%D9%83%D8%B3%D8%B3-microsoft-access-r716/" rel="">النماذج واﻻستعلامات والتقارير في برنامج قواعد بيانات مايكروسوفت أكسس Microsoft Access</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r602/" rel="">التعامل مع قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D9%88%D9%85%D8%B9%D9%84%D9%88%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AE%D8%B7%D8%B7-%D9%88%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D9%81%D9%8A-sql-r859/" rel="">تصميم الجداول ومعلومات المخطط وترتيب تنفيذ الاستعلامات في SQL</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">656</guid><pubDate>Thu, 03 Nov 2022 08:04:58 +0000</pubDate></item><item><title>&#x62F;&#x644;&#x64A;&#x644;&#x643; &#x627;&#x644;&#x634;&#x627;&#x645;&#x644; &#x625;&#x644;&#x649; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; DataBase</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/636f9da9a333e_-.png.220d4fd7d65e2a923630932182778868.png" /></p>
<p>
	قواعد البيانات DataBase هي بحر واسع وأساس ضروري، فكل ما تراه من أنظمة كبيرة ومتطورة تتعامل مع البيانات فتخزنها وتسترجعها عبر قواعد البيانات، إذ تُعدُّ إحدى أهم البنى التحتية لأي نظام إلكتروني؛ ولكن ما هي قاعد البيانات؟ وما أهميتها؟ وما أنواعها؟ وماذا نحتاج لتصميمها؟ كل هذه الأسئلة سنجيب عنها في هذا المقال بالإضافة إلى معلومات أخرى ستفيدك في تكوين فكرة مبدئية عنها فسيساعدك المقال في الدخول إلى هذا العالم الشيق.
</p>

<h2>
	مفهوم قواعد البيانات
</h2>

<p>
	تُعَدّ قواعدة البيانات -أو قاعدة المعطيات- وسيلةً من وسائل تجميع وحفظ البيانات في مكان واحد ومنظم يساعد على إدارتها والتعامل معها والاستفادة منها، فهي تشبه الوعاء الجامع للبيانات وخزانة الملابس التي تخزن الملابس بطريقة منظمة مرتبة تسهل استخراج أي لباس بسهولة وسرعة.
</p>

<p>
	تخزن قاعد البيانات البيانات فيها بطريقة تسمح الوصول إليها وتعديلها واسترجاعها وإدارتها بطريقة ذكية وسريعة، وغالبًا ما تُحفَظ البيانات في مجموعة من الكيانات التي تعبِّر عن نوع معيَّن مثل كيان المعلومات الشخصية عن الموظفين وبداخل كل كيان مجموعة من الواصفات التي تمثَّل بأعمدة الكيان مثل اسم الموظف وتاريخ ميلاده، …إلخ، ويمكن النظر إلى قاعدة البيانات على أنها مخزن مركزي للبيانات يمكن للجميع الوصول إليه والنهل منه.
</p>

<p>
	يُرمَز إلى قاعدة البيانات عمومًا بمجسّم أسطواني يشبه الخزان لأنه يُقصد بها خزّان للبيانات، وقد ابتُكرت أداة جديدة مع تطور قاعد البيانات لتسهيل إدارتها في منتصف القرن الماضي تقريبًا من خلال نظام برمجي خاص يدعى نظام إدارة قواعد البيانات DataBase Management System أو DBMS اختصارًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="112003" href="https://academy.hsoub.com/uploads/monthly_2022_11/636f9db88bebc_---database.png.cb3f3eecadc0e1d98c029d8b28fd5c6e.png" rel=""><img alt="مفهوم DataBase" class="ipsImage ipsImage_thumbnailed" data-fileid="112003" data-unique="1p1avu5dv" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/636f9dba9e5d5_---database.thumb.png.666d0124bf63d88bec1617218b600877.png"></a>
</p>

<h2>
	مفهوم نظام إدارة قاعدة البيانات
</h2>

<p>
	يمكِّن نظام إدارة قواعد البيانات Database management system -وتختصر إلى DBMS- المستخدِمين من إنشاء قاعدة البيانات وإدارتها وصيانتها والتحكم في الوصول إليها فلا يمكن التعامل معها مباشرةً ويكون نظام إدارة قاعد البيانات وسيطًا بين المستخدمين وبين قاعدة البيانات، كما يساعدهم على توفير بيئة ملائمة لهم ليتمكنوا من تخزين البيانات فيها واسترجاعها وتعديلها وحذفها منها، بالإضافة إلى أنه يساعد في عمليات التسجيل loging والمراقبة monitoring.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="112004" href="https://academy.hsoub.com/uploads/monthly_2022_11/636f9dbbb1b0f_----database-management-dbms.png.c77eafabc93ea247986262528a712087.png" rel=""><img alt="مفهوم DBMS" class="ipsImage ipsImage_thumbnailed" data-fileid="112004" data-unique="deq61ex41" style="width: 400px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/636f9dbc6e484_----database-management-dbms.thumb.png.1c6edf2c550acba90a74a9fbb9a691a2.png"></a>
</p>

<p>
	ومن أشهر أنظمة إدارة قواعد البيانات DBMS:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/apps/productivity/office/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D8%A7%D9%85%D8%A9-%D8%B9%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D8%A7%D9%8A%D9%83%D8%B1%D9%88%D8%B3%D9%88%D9%81%D8%AA-%D8%A3%D9%83%D8%B3%D8%B3-microsoft-access-r701/" rel="">مايكروسوفت أكسس Microsoft Access</a>: نظام إدارة قواعد بيانات خفيف وبسيط ذو واجهة سهلة الاستخدام لغير المختصين يُستعمل في حالات بسيطة أو متوسطة متعلقة غالبًا بأمور مكتبية ويأتي مدمجًا مع <a href="https://academy.hsoub.com/apps/productivity/office/" rel="">حزمة مايكروسوفت أوفيس</a>.
	</li>
	<li>
		نظام أوراكل Oracle: وهو نظام إدارة قواعد البيانات العلائقية.
	</li>
	<li>
		SQL Server: نظام إدارة قواعد البيانات العلائقية مدفوع من مايكروسوفت وهو قادر على التعامل مع كم بيانات ضخم ما يجعله مناسبًا للشركات الكبيرة.
	</li>
	<li>
		IBM Db2: نظام DBMS متطور من شركة IBM يوفر الكثير من الخيارات والتخصيصات التي تناسب مختلف المشاريع (المتوسطة والكبيرة عادةً).
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/mysql/" rel="">MySQL</a>: نظام DBMS مفتوح المصدر تديره شركة أوراكل.
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D9%88%D8%AA%D8%B5%D8%AF%D9%8A%D8%B1-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-mysql-%D8%A3%D9%88-mariadb-r361/" rel="">MariaDB</a>: نظام DBMS مفتوح المصدر يعد نظامًا مشتقًا من MySQL مع بعض التحسينات والتعديلات المضافة عليه.
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/postgresql/" rel="">PostgreSQL</a>: نظام DBMS مفتوح المصدر يتصف بالمرونة والشمولية ويناسب أغلب المشاريع.
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: إذا كانت قاعدة البيانات علائقيةً بمعنى أنها تتألف من عدة جداول ترتبط فيما بينها بعلاقات كما سنرى لاحقًا، فعندئذ سيطلق على هذا النظام اسم نظام إدارة قواعد البيانات العلائقية.
</p>

<p>
	تعتمد نظم إدارة قواعد البيانات لغات برمجة خاصة تدعى لغات الاستعلام Query Language يستطيع المستخدِم من خلالها التعامل مع البيانات، وفي حال البيانات الهيكلية تكون لغة البرمجة المستخدَمة هي <a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D9%82%D8%AF%D9%85-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-sql-r961/" rel="">لغة الاستعلام البنيوية</a> Structured Query Language أو SQL اختصارًا.
</p>

<p>
	ويدير النظام كل من البيانات و<a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r521/" rel="">تخطيط قاعدة البيانات Database Schema</a> بالإضافة إلى محرّك قاعدة البيانات الذي يسمح بالوصول إلى البيانات أو تعديلها أو منع الوصول إليها، إذ تهدف كل هذه الأمور إلى تحقيق عدة خصائص سنتعرف عليها في الفقرة التالية.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة علوم الحاسوب
		</p>

		<p class="banner-subtitle">
			دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/computer-science/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<img alt="دورة علوم الحاسوب" src="https://academy.hsoub.com/learn/assets/images/courses/computer-science.png">
	</div>
</div>

<h2>
	أهمية قواعد البيانات
</h2>

<p>
	تكمن أهميتها بامتلاكها الكثير من الخصائص التي تميزها عن <a href="https://academy.hsoub.com/devops/servers/databases/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%88%D8%A7%D8%AE%D8%AA%D9%84%D8%A7%D9%81%D9%87-%D8%B9%D9%86-%D9%86%D8%B8%D8%A7%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r509/#comment-46649" rel="">النظام القائم على إدارة الملفات file-based system</a> وطرق التخزين التقليدية الأخرى، ومن أهمها:
</p>

<ul>
	<li>
		تحقيق أمن البيانات والسرية، إذ لا يمكن الوصول إلى إليها إلا عن طريق أشخاص محددين وبصلاحيات مقيدة، بحيث لا يمتلك جميع مستخدِمي قاعدة البيانات الصلاحيات ذاتها للوصول إليها مثل صلاحيات القراءة والكتابة والإدارة وغيرها.
	</li>
	<li>
		تحقيق <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D9%88%D9%82%D9%8A%D9%88%D8%AF%D9%87%D8%A7-%D9%84%D8%B6%D9%85%D8%A7%D9%86-%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r544/" rel="">سلامة البيانات data integrity</a>، إذ يمكن إضافة قيود على القاعدة تجبر المستخدِم على إدخال البيانات وفق نمط ونوع معيّن، بحيث لا يمكن إضافة سلسلة نصية مكان عمر المستخدِم على سبيل المثال، كما يمكن إضافة قيود تمنع إضافة قيمة موجودة مسبقًا.
	</li>
	<li>
		تأمين الوصول المتزامن، بحيث تسمح لأكثر من مستخدِم لديه صلاحية الوصول من الوصول إلى البيانات نفسها وبالوقت نفسه دون التأثير السلبي عليها.
	</li>
	<li>
		تمكنك من إضافة أنواع متنوعة من البيانات، أي يمكن إضافة اسم الشخص مع عمره مع تاريخ ميلاده على سبيل المثال على الرغم من أنّ كل قيمة تعود إلى نمط معيّن، أي يمكن إضافة سلسلة نصية مع عدد مع تاريخ دون وجود أية مشاكل.
	</li>
	<li>
		منع تكرار البيانات وتسهيل التعديل عليها من مكان واحد بإضافة شروط خاصة على بنية قاعدة البيانات أو بتقسيمها إلى عدة جداول وربطها ببعضها مثل إنشاء جدول للمؤلفين وجدول للمدونات يضم تفاصيل المدونة مع عمود يحدد مُعرِّف ID كل مؤلف ويُربط بينهما بعلاقة تشكل جدول رابط بسهولة بحيث يسهل التعديل على جدول البيانات والمؤلفين بشكل منفصل.
	</li>
	<li>
		تنسيق وتنظيم البيانات، وبالتالي عرضها بصورة منظمة والوصول إليها باستعلام برمجي معيّن وواضح وصريح.
	</li>
	<li>
		الوصول إلى بيانات محددة بسرعة كبيرة، ويتحقق ذلك من خلال لغات الاستعلام وتعليمات وبُنى برمجية مخصصة لهذا الغرض، وخاصةً في حال استخدام <a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D9%81%D9%87%D8%A7%D8%B1%D8%B3-indexes-%D9%81%D9%8A-sql-r589/" rel="">الفهارس indexes</a>.
	</li>
	<li>
		تسهيل عملية التعديل والتحديث على البيانات، بالإضافة إلى عمليات الحذف والإضافة، مما يضمن لك الدقة في تلك العمليات.
	</li>
	<li>
		تقليل المساحات المستخدَمة، إذ تُوفَّر المساحات الهائلة على مكاتب الأرشفة عند استخدام قواعد البيانات بدلًا من وسائل التخزين الورقية.
	</li>
	<li>
		حماية البيانات من الضياع والقدرة على استرجاعها في حال تعرضت للتلف من خلال النسخ الاحتياطي backup.
	</li>
</ul>

<h2>
	استخدامات قاعدة البيانات
</h2>

<p>
	تُستخدَم قاعدة البيانات في كل نظام برمجي تراه اليوم أمامك خلف الشاشة مثل وسائل التواصل الاجتماعي والمدونات وتطبيقات الويب والبرامج والتطبيقات الخدمية مثل إدارة المستشفيات وغيرها لأهداف عديدة منها:
</p>

<ul>
	<li>
		تحسين العمليات التجارية، إذ تجمع الشركات بيانات حول العمليات التجارية مثل المبيعات ومعالجة الطلبات وخدمة العملاء ثم تحلل هذه البيانات لتحسين العمليات وتوسيع أعمالهم وزيادة الإيرادات.
	</li>
	<li>
		تتبع العملاء وكل بياناتهم، إذ تُخزّن معلومات المستخدِمين والعملاء ضمن القاعدة، مما يساعد على معالجة هذه المعلومات وعرضها واستخدامها بعدة أشكال مفيدة.
	</li>
	<li>
		تأمين المعلومات الصحية الشخصية، إذ تخزن البيانات ضمن جداول لمعالجتها واستخدامها لاحقًا في مراقبة المرضى وتحسين رعايتهم بل حتى في إجراء تحليلات للتنبؤ بحالات مرضية أو إيجاد علاج لحالات مرضية أخرى.
	</li>
	<li>
		تخزين البيانات الشخصية مثل <a href="https://academy.hsoub.com/apps/operating-systems/windows/%D8%AE%D8%AF%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D8%B3%D8%AD%D8%A7%D8%A8%D9%8A%D8%A9-onedrive-%D9%88%D9%88%D9%8A%D9%86%D8%AF%D9%88%D8%B2-10-r276/" rel="">التخزين السحابي</a> المستخدَم لتخزين الوسائط مثل الصور.
	</li>
</ul>



<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			هل ترغب في  برمجة قواعد بيانات وإدارتها بكفاءة وفاعلية؟
		</p>

		<p class="banner-subtitle">
			وظّف مبرمج قواعد بيانات محترف من مستقل
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://mostaql.com/freelancers/skill/database-programming" rel="external">أضف مشروعك الآن</a>
		</div>
	</div>
</div>




<h2>
	أنواع قواعد البيانات
</h2>

<p>
	تختلف وتتعدد <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">أنواع قواعد البيانات</a>، وهذا الاختلاف ينبع بالدرجة الأولى من التقدم بالزمن وما صاحبه من تقدم في العلوم والتقنيات، ومن ثم بالدرجة الثانية ينبع من التقنيات والخصائص المتعددة لها وما تقدمه من خدمات، ومن بين هذه الأنواع ما يلي:
</p>

<ul>
	<li>
		قواعد البيانات العلائقية Relational Database
	</li>
	<li>
		قواعد البيانات غير العلائقية Non-relational Database
	</li>
	<li>
		قواعد البيانات الهرمية Hierarchy Database
	</li>
	<li>
		قواعد البيانات الشبكية Network Database
	</li>
	<li>
		قواعد البيانات السحابية Cloud Database
	</li>
</ul>

<h3>
	قواعد البيانات العلائقية Relational Database
</h3>

<p>
	هي مجموعة من الجداول المرتبطة فيما بينها بعلاقات تضبط المعلومات في تلك الجداول وتسهل الوصول إلى المعلومات المطلوبة، ويتميز هذا النوع بالمرونة وهي إمكانية التعديل على الجداول والعلاقات بينها من إضافة وحذف في أيّ وقت، كما ترتبط الجداول فيما بينها بعدة علاقات والتي تعطي <a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D8%A6%D9%82%D9%8A%D8%A9-rdm-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r522/" rel="">قواعد البيانات العلائقية</a> اسمها.
</p>

<p>
	يتألف الجدول من مجموعة من الأسطر -أو السجلات records- ومجموعة من الأعمدة -أو السمات attributes-، وتكون مجموعة الأعمدة ثابتة ولكل منها نمط معيّن بحيث يكون خاص بالأعداد أو السلاسل النصية أو التاريخ …إلخ؛ أما الأسطر فعددها غير محدود تبعًا للبيانات المراد تخزينها، كما ينبغي عدم تكرار السطر للحفاظ على جودتها، ويتحقق ذلك بوضع شروط خاصة على الأعمدة بأن يكون فريدًا unique مثلًا.
</p>

<p>
	من الجدير بالذكر أنّ قاعدة البيانات هذه تتميز أيضًا باحتوائها على علاقات تربط جداولها ببعضها بعضًا ولذلك سميت بالعلائقية وتسمى أيضًا <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D8%A9-er-%D9%84%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r543/" rel="">بنموذج الكيان والعلاقة entity relationship</a> أو ER اختصارًا، أي نربط البيانات بعلاقات تسهل علينا الوصول إليها وتعديلها وتجنبنا تكرارها في عدة مواضع، وبالتالي توجد عدة أنواع للعلاقة أهمها علاقة واحد إلى واحد وعلاقة واحد إلى متعدد، فإذا كان لدينا جدولًا يمثِّل الصفوف الدراسية وجدولًا يمثِّل الطلاب على سبيل المثال، فكل صف دراسي يحتوي على عدة طلاب، في حين ينتمي الطالب إلى صف واحد خلال العام الدراسي، فالعلاقة هنا بين جدولَي الطلاب والصفوف الدراسية هي علاقة واحد إلى متعدد؛ أما علاقة واحد إلى واحد فتكون بين جدولَي المديرين وجدول المدارس، إذ يدير المدرسة مدير وحيد كما يشرف المدير على مدرسة واحدة لا أكثر، وهكذا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="112000" href="https://academy.hsoub.com/uploads/monthly_2022_11/636f9db492671_---Relational-Database.png.e54fa82156e5ddd7632be7ee2b47f897.png" rel=""><img alt="قاعد البيانات العلائقية Relational Database" class="ipsImage ipsImage_thumbnailed" data-fileid="112000" data-unique="qadoqcd7h" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/636f9db492671_---Relational-Database.png.e54fa82156e5ddd7632be7ee2b47f897.png"></a>
</p>

<h3>
	قواعد البيانات غير العلائقية Non-relational Database
</h3>

<p>
	يسمح هذا النوع بحفظ بيانات غير مرتبة Unstructured Data ويطلق عليه أيضًا No-SQL Database، وقد ظهر هذا النوع في عصر تضخم البيانات وزيادة حجمها، وبالطبع يُعَدّ هذا النوع نوعًا سيئًا لإمكانية تكرار البيانات بكثرة، مما يؤدي إلى زيادة حجم مكان التخزين بسرعة وزيادة كلفة التعديل في حال أردت إجراء تعديل على اسم المستخدِم على سبيل المثال والمكرر عشرات المرات، في حين يُعَدّ ممتازًا من أجل التطبيقات البسيطة التي تحتاج إلى حجم كبير من التخزين وزمن وصول منخفض ولا تحتاج إلى قواعد بيانات علائقية، ومن الأمثلة على ذلك ملفات الإكسل والكتب والمدونات.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="450" id="ips_uid_4129_16" src="https://academy.hsoub.com/applications/core/interface/index.html" title="YouTube video player" width="800" data-embed-src="https://www.youtube.com/embed/ZLlfTf4w9KU"></iframe>
</p>

<p>
	ينقسم تنظيم هذا النوع إلى أربعة أقسام حسب النموذج المستخدَم وهي كما يلي:
</p>

<ul>
	<li>
		نموذج الجدول الكبير Big Table أو عمودي التوجه Column-oriented database: إذ يُنشَأ في هذا النوع جدول كبير يحتوي على جميع البيانات، أي مثل وجود كل المعلومات التي تمتلكها على ورقة واحدة، ويطلق عليه أحيانًا اسم نموذج الأعمدة الموسَّعة.
	</li>
	<li>
		نموذج المستند الموجّه Document-oriented Database، وتكون صيغة المستند XML أو JSON أو غيرها، أي أنّ <a href="https://academy.hsoub.com/questions/13023-%D9%85%D9%81%D9%87%D9%88%D9%85-json-%D9%85%D8%A7-%D9%87%D9%88-json-%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D9%87/" rel="">ملف JSON</a> هو قاعدة بيانات من النمط، ويُعَدّ هذا النوع مشابهًا لنمط تخزين مفتاح قيمة، إذ يوفِّر مفتاح وقيمة أيضًا لكن بصورة موسّعة قليلًا.
	</li>
	<li>
		نموذج الرسم البياني Graph NoSQL Database، يعتمد هذا النوع على تخزين البيانات المترابطة على صورة رسم بياني.
	</li>
	<li>
		نموذج مفتاح-قيمة Key-Value NoSQL Database: إذ يُسنَد مفتاح فريد غير متكرر لكل قيمة وتحفظ البيانات على صورة جدول من عمودَين هما القيمة والمفتاح، أي عند طلب المفتاح سنحصل على قيمته، ويستخدَم هذا النوع من أجل البيانات الضخمة مع استعلامات بحث بسيطة.
	</li>
</ul>

<p style="text-align: center;">
	<img alt="قواعد البيانات غير العلائقية No SQL" class="ipsImage ipsImage_thumbnailed" data-fileid="112002" data-unique="3rqatrh80" style="width: 580px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/636f9db7db539_---.png.07a3c020f13e26c95494c84ff4148206.png">
</p>

<h3>
	قواعد البيانات الهرمية Hierarchy Database
</h3>

<p>
	يعتمد هذا <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r521/" rel="">النوع</a> على مبدأ التسلسل الهرمي في العمل والذي يجري تسلسلًا من الجذر أو الأصل بنموذج يشبه الشجرة، إذ تمثَّل البيانات فيه باستخدام علاقات الأصل والتابع، فقد يكون لكل أصل عدة توابع، في حين يكون لكل تابع أصل وحيد فقط، وبالتالي تكون العلاقات في النموذج من النواع واحد إلى متعدد، ويعبِّر التابع عن سجل له عدة سمات.
</p>

<p>
	اعتمِد هذا النوع قبل وجود قواعد البيانات العلائقية، وبالتالي فقد أصبح الآن نادر الاستخدام، ويعمل على الوصول إلى البيانات بطريقة متفرعة ومتسلسلة وتكون إما من الأسفل إلى الأعلى بدءًا من التابع أو من الأعلى إلى الأسفل.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="112001" href="https://academy.hsoub.com/uploads/monthly_2022_11/636f9db52f6d2_---Hierarchy-Database.png.da008e9965c9b51e8e3b644ea1364dd9.png" rel=""><img alt="قواعد البيانات الهرمية Hierarchy Database" class="ipsImage ipsImage_thumbnailed" data-fileid="112001" data-unique="30uxgkorc" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/636f9db6d76f6_---Hierarchy-Database.thumb.png.ab212d9580bd8334339060dc8698d323.png"></a>
</p>

<p>
	يوضح الشكل السابق مثالًا عن قاعدة البيانات الهرمية، إذ يمثِّل المستوى الأول سجلات تحتوي على ثلاثة أنواع من السمات وهي المعرِّف S_id والاسم S_name والعمر S_age، ويتبع هذا المستوى سجلات -أو توابع- جديدة تتألف من سمتَين هما معرِّف دورة البرمجة C_id واسم دورة البرمجة C_Name، أي نلاحظ أنّ الأصل يحتوي على ثلاثة توابع وكل تابع يرتبط بتابع ما عدا السجل ذو المعرِّف 151 الذي بتابعَين اثنين.
</p>

<h3>
	قواعد البيانات الشبكية Network Database
</h3>

<p>
	تُعَدّ امتدادًا لقاعد البيانات الهرمية، إذ يمكن أن يكون لدى الابن الواحد أكثر من أب، وبالتالي فإنها تسمح للمصممين بتصميم أكثر مرونةً، وإنّ ما يميّيز هذا النوع هو وجود الأسهم بين العقد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111999" href="https://academy.hsoub.com/uploads/monthly_2022_11/636f9db2afe70_---Network-Database.png.aa06ca8e5343399c7fe872b5c844eaf1.png" rel=""><img alt="قواعد البيانات الشبكية Network Database" class="ipsImage ipsImage_thumbnailed" data-fileid="111999" data-unique="4hpx6rzx4" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/636f9db3d120d_---Network-Database.thumb.png.b9881e66c718a2113eb9faa59e47bdf5.png"></a>
</p>

<h3>
	قواعد البيانات السحابية Cloud Database
</h3>

<p>
	هذا النوع مبني في <a href="https://academy.hsoub.com/devops/cloud-computing/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%B3%D8%AD%D8%A7%D8%A8%D8%A9-cloud-r624/" rel="">سحابة cloud</a> عامة أو خاصة، إذ تُفرَض رسوم على المستخدِمين بناءً على سعة التخزين والنطاق الترددي الذي سيستخدمونه، كما يمكنهم التوسع عن الطلب.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111998" href="https://academy.hsoub.com/uploads/monthly_2022_11/636f9daea88b6_-Cloud-Database.png.6cab20852ee5a7f781fa150ab001fcab.png" rel=""><img alt="قاعدة بيانات سحابية Cloud Database" class="ipsImage ipsImage_thumbnailed" data-fileid="111998" data-unique="9daidv5uo" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/636f9db16fe9b_-Cloud-Database.thumb.png.5132a54373c62b3f76c60daa8da4e4a8.png"></a>
</p>

<h2>
	مكونات قواعد البيانات
</h2>

<p>
	تتكون قاعدة البيانات من المكونات التالية مهما كان نوعها:
</p>

<ul>
	<li>
		العتاد hardware: هو الجهاز الفعلي الذي يعمل عليه برنامج قواعد البيانات، ويشمل أجهزة الحاسوب والخوادم ومحركات الأقراص الصلبة.
	</li>
	<li>
		البرمجية software: يمنح تطبيق أو برمجية قاعدة البيانات المستخدِمين إمكانية التحكم والتعامل مع قاعدة البيانات عن طريق احتوائه على نظام إدارة قواعد البيانات، كما تتنوع البرامج التي تحقق ذلك، ومن بينها أوراكل Oracle و Microsoft Access و Microsoft Excel و Microsoft SQL و PostgreSQL و TeamDesk و knack و TablePlus وغيرها الكثير.
	</li>
	<li>
		البيانات Data: وهي المعلومات الأولية التي تخزنها قواعد البيانات، إذ ينظمها المسؤولون لجعلها أكثر وضوحًا.
	</li>
	<li>
		لغة الوصول إلى البيانات Data access language: وهي لغة البرمجة التي تتحكم في قاعدة البيانات، إذ يجب على لغة البرمجة هذه العمل مع نظام إدارة قواعد البيانات، كما تُعَدّ <a href="https://academy.hsoub.com/programming/sql/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-sql%D8%9F-r1651/" rel="">لغة الاستعلام الهيكلية Structured Query Language أو SQL اختصارًا</a> اللغة الأكثر شيوعًا في إدارة قاعدة البيانات العلائقية.
	</li>
	<li>
		الإجرائيات procedures: وهي قواعد تحدد كيفية عمل القاعدة وكيفية معالجتها للبيانات.
	</li>
</ul>

<p>
	من الجدير بالذكر أنّ أيّ قاعدة بيانات تحتاج إلى موارد مالية دائمة ومستمرة، كما يجب تأمين الحماية الخارجية لها لتجنب اختراقها أو تخريبها، بالإضافة إلى أنّ تطويرها يُعَدّ معقدًا لأنه يحتاج إلى مصممين بخبرات عالية.
</p>

<h2>
	تصميم قاعدة البيانات
</h2>

<p>
	سنتعرف فيما يلي على <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">تصميم قواعد البيانات</a> العلائقية بما أنّ هذا النوع هو الأكثر شيوعًا والأكثر استخدامًا، إذ تتألف عملية التصميم هذه من الخطوات التالية:
</p>

<ul>
	<li>
		تحديد الهدف من قاعدة البيانات: إذ سيساعدك ذلك في تحقيق الخطوات التالية، مثل بناء قاعدة بيانات خاصة بمستشفى ما.
	</li>
	<li>
		تقسيم المعلومات في جداول: وذلك من خلال تقسيم المعلومات إلى وحدات أساسية أو عناوين، بحيث يعبِّر كل عنوان عن جدول فيما بعد مثل جدول الأطباء وجدول المرضى وجدول الاختصاص، …إلخ.
	</li>
	<li>
		تحويل عناصر المعلومات إلى أعمدة: وذلك من خلال تحديد المعلومات التي تريد تخزينها في كل جدول، وهذه المعلومات ستمثِّل الأعمدة الخاصة بكل جدول، إذ تكون المعلومات الخاصة بجدول الأطباء مثلًا هي رقم الطبيب واسم الطبيب واختصاص الطبيب، …إلخ، وبالتالي ستمثِّل المعلومات السابقة أعمدةً لجدول الأطباء.
	</li>
	<li>
		تحديد <a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-sql-%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D9%88%D8%A7%D9%84%D9%82%D9%8A%D9%88%D8%AF-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-r586/" rel="">المفاتيح الأساسية primary keys</a> لكل جدول: والتي ستكون عمودًا أو مجموعة من الأعمدة تشكل قيمة فريدة في كل الجدول، ويُعَدّ المفتاح الأساسي ضروريًا من أجل بناء العلاقات بين الجداول.
	</li>
	<li>
		تعيين العلاقات بين الجداول: وذلك من خلال تحديد ارتباط البيانات في الجداول مع بعضها، فالعلاقة التي تربط جدول الاختصاص مع جدول الأطباء على سبيل المثال هي علاقة واحد إلى متعدد، إذ يمكن أن يحتوي الاختصاص على مجموعة من الأطباء في حين ينتمي الطبيب إلى اختصاص واحد فقط.
	</li>
	<li>
		تحسين التصميم الخاص بك: وذلك عن طريق مراجعة التصميم وإجراء تعديلات إذا دعت الحاجة لذلك بأن يكون هناك جدولًا لا داع له، أو توجد معلومات ناقصة لا يستوفيها التصميم الحالي.
	</li>
</ul>


<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			أنشئ وصمم قواعد البيانات التي تحتاجها لأعمالك
		</p>

		<p class="banner-subtitle">
			استعن بأفضل مقدمي خدمات قواعد البيانات على خمسات
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://khamsat.com/data/databases" rel="external">اطلب خدمتك الآن</a>
		</div>
	</div>
</div>


<h2>
	تعلم قواعد البيانات
</h2>

<p>
	أصبح الانترنت مليئًا بالمحتوى التعليمي والتثقيفي حول أيّ مجال وخاصةً حول قواعد البيانات، إذ تتولى الكثير من المواقع هذه العملية التعليمية وتوفر دروس ومقالات وبصورة مجانية مثل أكاديمية حسوب، بالإضافة إلى وجود العديد من القنوات التعليمية على اليوتيوب، فضلًا عن تعلّمها في المرحلة الجامعية، كما تقدّم أكاديمية حسوب دورة مميزة في <a href="https://academy.hsoub.com/store/7-%D8%AF%D9%88%D8%B1%D8%A9-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">علوم الحاسوب</a> تغطي كل المفاهيم الأساسية المهمة في هذا المجال ومنها بالطبع التعريف بقاعد البيانات والتعامل معها.
</p>

<p style="text-align: center;">
	<iframe allowfullscreen="" frameborder="0" height="450" src="https://player.vimeo.com/video/409436178" width="800"></iframe>
</p>

<p>
	الخطوة الأهم في تعلمها هو تعلم <a href="https://wiki.hsoub.com/SQL/datatype" rel="external">لغة SQL</a> وإتقانها جيدًا إذ هي الأساس في التعامل مع قواعد البيانات كما تقوم عليها كل أنظمة إدارة قواعد البيانات مهما اختلفت بالإضافة إلى توسيعها بتعليمات جديدة يمكن تعلمها بسهولة بعد معرفة نظام إدارة قواعد البيانات المراد استخدامه.
</p>

<p>
	وبعد تلك الخطوة من المهم فهم قواعد البيانات العلائقية فهي الأكثر استخدامًا وشيوعًا في الأنظمة ثم تعلم كيفية تصميمها وبعدها يمكنك الدخول إلى مجال أنظمة الإدارة DBMS وتعلمها وبذلك تكون مؤهلًا للعمل في مجال إدارة أنظمة قواعد البيانات DBMS Admin.
</p>

<p>
	نرشح لك بالإضافة لدورة علوم الحاسوب مراجع داعمة لها يمكنك التعلم منها:
</p>

<ul>
	<li>
		كتاب <a href="https://academy.hsoub.com/files/16-%D9%85%D9%84%D8%A7%D8%AD%D8%B8%D8%A7%D8%AA-%D9%84%D9%84%D8%B9%D8%A7%D9%85%D9%84%D9%8A%D9%86-%D8%A8%D9%84%D8%BA%D8%A9-sql/" rel="">ملاحظات للعاملين بلغة SQL</a>
	</li>
	<li>
		كتاب <a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تصميم قواعد البيانات</a>
	</li>
	<li>
		كتاب <a href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى ostgreSQL</a>
	</li>
	<li>
		مقالات عن <a href="https://academy.hsoub.com/devops/servers/databases/" rel="">قواعد البيانات وإدارتها</a>
	</li>
	<li>
		مقالات عن <a href="https://academy.hsoub.com/programming/sql/" rel="">لغة SQL</a>
	</li>
	<li>
		<a href="https://wiki.hsoub.com/SQL" rel="external">توثيق لغة SQL العربي</a>
	</li>
</ul>

<h2>
	فرص العمل في مجال قواعد البيانات
</h2>

<p>
	تمتد الوظائف الرئيسية للعمل مع قواعد البيانات إلى عدة مجالات مهنية، فإذا وفرت لنفسك التدريب والخبرة المناسبتَين، فسيوفِّر هذا فرصًا وظيفية مجزية وذات دخل عالي، ومن المسميات الوظيفية التي يمكن التخصص فيها في هذا المجال هي:
</p>

<ul>
	<li>
		مدير قواعد بيانات database administrator
	</li>
	<li>
		محلل قواعد بيانات database analyst
	</li>
	<li>
		مطور قواعد بيانات database developer
	</li>
	<li>
		مدير قواعد بيانات database manager
	</li>
	<li>
		مهندس قواعد بيانات database engineer
	</li>
	<li>
		أخصائي قواعد بيانات Database Specialist
	</li>
</ul>

<p>
	والعديد من المسميات الوظيفية التي يُدرج في متطلباتها المعرفة والخبرة بالعمل مع قاعدة البيانات وأنظمة محددة من أنظمة DBMS مثلًا ستجد مثل Oracle Database Administrator أو MS SQL Server Database Administrator وإليك <a href="https://www.indeed.com/jobs?q=Database" rel="external nofollow">قائمة بالمسميات الوظيفية المتعلقة بقواعد البيانات ومتطلباتها</a> على موقع indeed.
</p>

<p>
	كما يمكن العمل عن بعد أي عبر الانترنت بأحد التخصصات السابقة، وبالتالي التواجد الفيزيائي في موقع العمل غير مطلوب بناءً على قرار من الجهة المسؤولة عن العمل.
</p>

<p>
	يُتوقَّع أن ينمو التوظيف في هذا التخصص بنسبة 9 بالمئة بين عامَي 2021 و 2030 بصورة أسرع من متوسط المهن الأخرى، كما يُتوقَّع حوالي 11500 فرصة عمل لمديرِي ومهندسِي قواعد البيانات في كل عام، وقد بلغ متوسط الأجر السنوي لمديرِي قواعد البيانات حوال 96710 دولار أمريكي في شهر 5 من عام 2021 في الولايات المتحدة الأمريكية حسب <a href="https://www.bls.gov/ooh/computer-and-information-technology/database-administrators.htm#tab-1" rel="external nofollow">مكتب الولايات المتحدة الأمريكية لإحصاءات العمالة U.S. BUREAU OF LABOR STATISTICS أو BLS اختصارًا</a>.
</p>

<p>
	لا غنى لأي نظام إلكتروني اليوم عن قاعدة بيانات تخزن بيانات التطبيق وتدير معلوماته، وبالتالي تتعدد المجالات والمؤسسات التي تتطلب المعرفة التامة بقواعد البيانات وكيفية التعامل معها، ومن بين هذه المؤسسات البنوك وشركات الطيران وشركات الاتصال والمستشفيات بالإضافة إلى مجال التعليم والاقتصاد والمالية والمبيعات والتسويق والموارد البشرية، كما أنّ كل برنامج حاسوبي أو موقع ويب أو تطبيق على الهاتف المحمول يتطلب وجود قاعدة بيانات مهما كانت بنيتها وتزداد الحاجة إلى أخصائي قواعد بيانات لإدارتها كلما كبر حجم قواعد البيانات للنظام وقد تجد في الشركات المتوسطة والكبيرة قسم كامل لإدارتها.
</p>

<p>
	وفّر الموقع الأكبر في التوظيف عن بعد في العالم العربي وهو <a href="https://www.baaeed.com/" rel="external nofollow">موقع بعيد</a> عدة وظائف تتعلق في قواعد البيانات بمختلف مجالاتها مثل التصميم والتطوير، …إلخ. يمكنك متابعته والتقدم للشواغر الوظيفية المتاحة في هذا تخصص.
</p>

<h2>
	الخاتمة
</h2>

<p>
	تناول هذا المقال لمحةً عامةً حول قواعد البيانات ليكون بذلك بمثابة حجر أساس في طريقك نحو التعمق فيها، كما بيّن أهمية هذا الموضوع في العديد من المجالات، مع التطرق إلى أنواعها لتختار بدورك ما يناسبك حسب التطبيق الذي تود التعامل معه، بالإضافة إلى ذكر مكوناته وخطوات تصميم قواعد البيانات العلائقية كونها الأكثر استخدامًا، وختامًا ذكرنا مصادر تعلم هذا المجال للتخصص فيها وتطرقنا إلى فرص العمل في هذا التخصص لتكون على بينة قبل دخول سوق العمل.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">المدخل الشامل لتعلم علوم الحاسوب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-mysql-%D9%88-mongodb-r627/" rel="">مقارنة بين MySQL و MongoDB</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D9%83%D9%8A%D9%81-%D8%AA%D8%AB%D8%A8%D9%91%D8%AA-mysql-workbench-%D9%88%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%87-%D9%84%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-mysql-r324/" rel="">كيف تثبّت MySQL Workbench وتستخدمه للاتصال بقواعد بيانات MySQL</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">تعلم أساسيات MySQL</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">علم البيانات Data science: الدليل الشامل</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%AE%D8%B5%D8%A7%D8%A6%D8%B5-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D8%B2%D8%A7%D9%8A%D8%A7-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D9%82%D8%AF%D9%85%D9%87%D8%A7-r520/" rel="">خصائص قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database-development-r553/" rel="">تطوير قواعد البيانات </a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D9%91%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-sql-r585/" rel="">أساسيّات لغة SQL</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%87%D9%85%D9%8A%D8%A9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">أهمية قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">661</guid><pubDate>Sat, 12 Nov 2022 14:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x639;&#x645;&#x644; &#x645;&#x639; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x639;&#x644;&#x627;&#x642;&#x64A;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Sequelize</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%B9%D9%84%D8%A7%D9%82%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-sequelize-r655/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/63636795d52d1_-------Sequelize.png.1c413d30060e347ea30ab008f69ad079.png" /></p>

<p>
	نستكشف في هذا المقال تطبيقات نود Node التي تستخدم قواعد بيانات علاقية، وسنبني خلال تقدمنا في المقال واجهةً خلفيةً تستخدم قاعدة بيانات علاقية ليتعامل معها تطبيق الملاحظات الذي عملنا عليه سابقًا. ولإكمال هذا المقال، لا بُدّ من تعميق معرفتك بقواعد البيانات العلاقية <a href="https://academy.hsoub.com/programming/sql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D9%91%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-sql-r585/" rel="">ولغة SQL</a>. يمكنك الاطلاع على سلسلة مقالات <a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D9%82%D8%AF%D9%85-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-sql-r961/" rel="">المرجع المتقدم إلى SQL</a> في أكاديمية حسوب، وكذلك الاطلاع على <a href="http://wiki,hsoub.com/SQL" rel="external nofollow">توثيق لغة SQL</a> في <a href="http://wiki,hsoub.com" rel="external nofollow">موسوعة حسوب</a>.
</p>

<p>
	ستجد 24 تمرينًا في هذا المقال وعليك أن تنجزها جميعًا لتكمل الدورة التعليمية، تُسلّم الحلول إلى <a href="https://studies.cs.helsinki.fi/stats/courses/fs-psql" rel="external nofollow">منظومة تسليم الحلول</a> كما هو الحال في الأقسام السابقة ما عدا الأقسام من 0 إلى 7 والتي تُسلّم حلول التمارين فيها إلى مكان آخر.
</p>

<h2>
	إيجابيات وسلبيات قواعد بيانات المستندات
</h2>

<p>
	استخدمنا قاعدة البيانات MongoDB في جميع المقال السابقة، وهي <a href="https://en.wikipedia.org/wiki/Document-oriented_database" rel="external nofollow">قاعدة بيانات مستندات</a>، ومن أهم ميزاتها أنها لا تملك أي مخططات، أي أنّ لها معرفةٌ محدودةٌ بطبيعة البيانات المخزنة في كل مجموعة. يتواجد مخطط قاعدة البيانات schema في شيفرة البرنامج فقط، إذ يفسِّر البيانات بطريقة معينة، كأن يحدد أن بعض الحقول هي مراجعٌ لكائنات في مجموعةٍ أخرى.
</p>

<p>
	رأينا في المثال التطبيقي الذي يضم قاعدة بيانات تخزن الملاحظات والمستخدمين (في القسمين <a href="https://academy.hsoub.com/programming/javascript/nodejs/express/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-nodejs-%D9%88express-r1099/" rel="">3</a> و <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%87%D9%8A%D9%83%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-unit-tests-r1132/" rel="">4</a>)، إذ تُخزِّن الملاحظات "notes" على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_8" style="">
<span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"_id"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"600c0e410d10256466898a6c"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"HTML is easy"</span><span class="pln">
    </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2021</span><span class="pun">-</span><span class="lit">01</span><span class="pun">-</span><span class="lit">23T11</span><span class="pun">:</span><span class="lit">53</span><span class="pun">:</span><span class="lit">37.292</span><span class="pun">+</span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"important"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="str">"__v"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"_id"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"600c0edde86c7264ace9bb78"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"CSS is hard"</span><span class="pln">
    </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2021</span><span class="pun">-</span><span class="lit">01</span><span class="pun">-</span><span class="lit">23T11</span><span class="pun">:</span><span class="lit">56</span><span class="pun">:</span><span class="lit">13.912</span><span class="pun">+</span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"important"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    </span><span class="str">"__v"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	وتُخزّن أيضًا بيانات المستخدمين في المجموعة "users" على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_10" style="">
<span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"_id"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"600c0e410d10256466883a6a"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"username"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"mluukkai"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Matti Luukkainen"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"passwordHash"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"$2b$10$Df1yYJRiQuu3Sr4tUrk.SerVz1JKtBHlBOARfY0PBn/Uo7qr8Ocou"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"__v"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln">
    notes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="str">"600c0edde86c7264ace9bb78"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"600c0e410d10256466898a6c"</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	تعرِف MongoDB نوع البيانات في الحقول التي تُخزِّن كيانات البيانات، لكنها لا تعرف إلى أي مجموعة من الكيانات يشير المعرِّف المميز الذي سجّله المستخدم، ولا تهتم أيضًا بالحقول التي تمتلكها الكيانات المُخزنة في مجموعات البيانات؛ لهذا تترك MongoDB أمر التحقق من صحة المعلومات المخزّنة في قاعدة البيانات إلى المبرمج.
</p>

<p>
	هناك طبعًا إيجابيات وسلبيات لعدم وجود مخطط لقاعدة البيانات، وإحدى الإيجابيات هي المرونة التي تضيفها الميزة اللا إدارية في مخطط البيانات، إذ سيسرّع انتفاء الحاجة إلى تعريف مخطط على مستوى <a href="https://academy.hsoub.com/programming/sql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D9%91%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-sql-r585/" rel="">قاعدة البيانات</a> من عمل المطوّر في حالات عدة، كما أنه أسهل من تعريف وتعديل المخطط في حالات أخرى؛ في حين تتعلق المشاكل الناجمة عن عدم وجود المخطط غالبًا بسهولة الوقوع في الأخطاء، فكل شيء ملقىً على عاتق المبرمج، وليس لقاعدة البيانات في هذه الحالة طريقةً للتحقق من نزاهتها honest، أي إذا احتوت كل الحقول الإجبارية على القيم الصحيحة، أو إذا أشارت الحقول ذات النوع المرجعي إلى كيانات من النوع الصحيح عمومًا وهكذا.
</p>

<p>
	تعتمد قاعدة البيانات العلاقية التي ستكون محور حديثنا في هذا المقال بشدة على وجود مخطط، وتكاد تكون الإيجابيات والسلبيات في استخدامها على نقيض تلك المتعلقة بقاعدة بيانات المستندات.
</p>

<p>
	يعود السبب الرئيسي في استخدام قاعدة البيانات MongoDB تحديدًا في الأقسام السابقة إلى طبيعتها التي لا تحتاج مخططات، الأمر الذي يسهّل استخدامها بالنسبة لذوي المعرفة المحدودة بقواعد البيانات العلاقية، لكن نفترض بالنسبة لكل الحالات التي عرضناها في منهاجنا أن القواعد العلاقية هي الأنسب.
</p>

<h2>
	قاعدة بيانات التطبيق
</h2>

<p>
	نحتاج في تطبيقنا إلى قاعدة بيانات علاقية، وهناك خيارات عديدة، لكننا سنستخدم حاليًا الحل الأكثر شعبيةً والمفتوح المصدر <a href="https://www.postgresql.org/" rel="external nofollow">PostgreSQL</a>؛ ويمكنك تثبيت Postgres (هكذا تُدعى قاعدة البيانات هذه غالبًا) على جهازك إذا أردت؛ والأسهل من هذا هو استخدامها بمثابة خدمة سحابية، مثل <a href="https://www.elephantsql.com/" rel="external nofollow">ElephantSQL</a>. بإمكانك أيضًا الاستفادة مما جاء في جزئية سابقة من السلسلة لاستخدام Postgres محليًا من خلال <a href="https://academy.hsoub.com/devops/cloud-computing/docker/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AF%D9%88%D9%83%D8%B1-docker-r607/" rel="">دوكر Docker</a>.
</p>

<p>
	اخترنا في هذا المقال الاستفادة من إمكانية إنشاء قاعدة بيانات Postgres للتطبيق على خدمة "Heroku" السحابية التي ألفنا العمل معها في المقالين 3 و4. سنبني في الجزء النظري من هذا المقال نسخةً مرتبطة بقاعدة البيانات Postgres عن الواجهة الخلفية لتطبيق تخزين الملاحظات الذي بنيناه في المقالين 3 و4.
</p>

<p>
	لننشئ أولًا مجلدًا مناسبًا ضمن تطبيق Heroku ونضيف إليه قاعدة بيانات، ثم نستخدم الأمر <code>heroku config</code> للحصول على "السلسلة النصية connect string" اللازمة للاتصال مع القاعدة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_15" style="">
<span class="pln">heroku create
</span><span class="com"># heroku يعيد اسم التطبيق للتطبيق الذي أنشأته في </span><span class="pln">

heroku addons</span><span class="pun">:</span><span class="pln">create heroku</span><span class="pun">-</span><span class="pln">postgresql</span><span class="pun">:</span><span class="pln">hobby</span><span class="pun">-</span><span class="pln">dev </span><span class="pun">-</span><span class="pln">a </span><span class="pun">&lt;</span><span class="pln">app</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;</span><span class="pln">
heroku config </span><span class="pun">-</span><span class="pln">a </span><span class="pun">&lt;</span><span class="pln">app</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">===</span><span class="pln"> cryptic</span><span class="pun">-</span><span class="pln">everglades</span><span class="pun">-</span><span class="lit">76708</span><span class="pln"> </span><span class="typ">Config</span><span class="pln"> </span><span class="typ">Vars</span><span class="pln">
DATABASE_URL</span><span class="pun">:</span><span class="pln"> postgres</span><span class="pun">:</span><span class="com">//&lt;username&gt;:&lt;password&gt;@&lt;host-of-postgres-addon&gt;:5432/&lt;db-name&gt;</span></pre>

<p>
	يُعد الوصول إلى قاعدة البيانات مباشرةً من الأمور الأساسية التي ينبغي الانتباه إليها تحديدًا في قواعد البيانات العلاقية، نظرًا لوجود أساليب عدة لتنفيذ الأمر، ووجود عدة واجهات مستخدم رسومية، مثل <a href="https://www.pgadmin.org/" rel="external nofollow">pgAdmin</a>، لكن سنستخدم أداة سطر الأوامر <a href="https://www.postgresql.org/docs/current/app-psql.html" rel="external nofollow">psql</a> الخاصة بالقاعدة Postgres.
</p>

<p>
	يمكن الوصول إلى قاعدة البيانات من خلال تنفيذ أمر <code>psql</code> على خادم Heroku على النحو التالي (لاحظ كيف تعتمد معاملات الأمر على <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عنوان url</a> للاتصال بقاعدة بيانات Heroku):
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_19" style="">
<span class="pln">heroku run psql </span><span class="pun">-</span><span class="pln">h </span><span class="pun">&lt;</span><span class="pln">host</span><span class="pun">-</span><span class="pln">of</span><span class="pun">-</span><span class="pln">postgres</span><span class="pun">-</span><span class="pln">addon</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">-</span><span class="pln">p </span><span class="lit">5432</span><span class="pln"> </span><span class="pun">-</span><span class="pln">U </span><span class="str">&lt;username&gt;</span><span class="pln"> </span><span class="str">&lt;dbname&gt;</span><span class="pln"> </span><span class="pun">-</span><span class="pln">a </span><span class="pun">&lt;</span><span class="pln">app</span><span class="pun">-</span><span class="pln">name</span><span class="pun">&gt;</span></pre>

<p>
	بعد إدخال كلمة المرور، سننفذ أمر <code>psql</code> الأساسي وهو <code>d\</code>، الذي يخبرك بمحتوى قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_21" style="">
<span class="typ">Password</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> user </span><span class="str">&lt;username&gt;</span><span class="pun">:</span><span class="pln">
psql </span><span class="pun">(</span><span class="lit">13.4</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Ubuntu</span><span class="pln"> </span><span class="lit">13.4</span><span class="pun">-</span><span class="lit">1.pgdg20.04</span><span class="pun">+</span><span class="lit">1</span><span class="pun">))</span><span class="pln">
<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> connection </span><span class="pun">(</span><span class="pln">protocol</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TLSv1</span><span class="pun">.</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> cipher</span><span class="pun">:</span><span class="pln"> TLS_AES_256_GCM_SHA384</span><span class="pun">,</span><span class="pln"> bits</span><span class="pun">:</span><span class="pln"> </span><span class="lit">256</span><span class="pun">,</span><span class="pln"> compression</span><span class="pun">:</span><span class="pln"> off</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Type</span><span class="pln"> </span><span class="str">"help"</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> help</span><span class="pun">.</span><span class="pln">

username</span><span class="pun">=&gt;</span><span class="pln"> \d
</span><span class="typ">Did</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> find any relations</span><span class="pun">.</span></pre>

<p>
	وكما ترى، لا يوجد شيء حاليًا في قاعدة البيانات. لننشئ إذًا جدولًا للملاحظات:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_23" style="">
<span class="pln">CREATE TABLE notes </span><span class="pun">(</span><span class="pln">
    id SERIAL PRIMARY KEY</span><span class="pun">,</span><span class="pln">
    content text NOT NULL</span><span class="pun">,</span><span class="pln">
    important </span><span class="kwd">boolean</span><span class="pun">,</span><span class="pln">
    date time
</span><span class="pun">);</span></pre>

<p>
	يمكننا ملاحظة بعض النقاط:
</p>

<ul>
<li>
		يُعرِّف العمود <code>id</code> مفتاحًا أساسيًا primary key، ويعني ذلك أن قيم هذا العمود لا بُدّ أن تكون فريدةً لكل سطر في الجدول ولا ينبغي أن تكون قيمتها فارغة.
	</li>
	<li>
		يُعرّف نوع العمود <code>id</code> على أنه تسلسلي <a href="https://www.postgresql.org/docs/9.1/datatype-numeric.html#DATATYPE-SERIAL" rel="external nofollow">SERIAL</a>، وهو ليس نوع حقيقي بل تمثيل لعمود ذي قيم صحيحة تعيّن Postgres قيمه الفريدة تلقائيًا وتزيد هذه القيمة بمقدار "واحد" عند إنشاء سطر جديد.
	</li>
	<li>
		يكون العمود المُسمى <code>content</code> من النوع النصي ويُعُرِّف كي تعيّن له قيمةٌ في كل سطر.
	</li>
</ul>
<p>
	لنلق نظرةً على الوضع الآن من خلال الطرفية، ولننفّذ أولًا الأمر <code>d\</code> الذي يعرض جداول قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_26" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> \d
                 </span><span class="typ">List</span><span class="pln"> of relations
 </span><span class="typ">Schema</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Owner</span><span class="pln">
</span><span class="pun">--------+--------------+----------+----------------</span><span class="pln">
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> notes </span><span class="pun">|</span><span class="pln"> table </span><span class="pun">|</span><span class="pln"> username
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> notes_id_seq </span><span class="pun">|</span><span class="pln"> sequence </span><span class="pun">|</span><span class="pln"> username
</span><span class="pun">(</span><span class="lit">2</span><span class="pln"> rows</span><span class="pun">)</span></pre>

<p>
	إذ تُنشئ Postgres إضافةً إلى الجدول <code>notes</code> جدولًا فرعيًا يُدعى <code>notes_id_seq</code> يتتبع القيم المُسندة إلى العمود <code>id</code> عند إنشاء ملاحظة جديدة. وبتنفيذ الأمر <code>d notes\</code> يمكننا رؤية طريقة تعريف الجدول <code>notes</code>:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_28" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> \d notes</span><span class="pun">;</span><span class="pln">
                                     </span><span class="typ">Table</span><span class="pln"> </span><span class="str">"public.notes"</span><span class="pln">
  </span><span class="typ">Column</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Collation</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Nullable</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Default</span><span class="pln">
</span><span class="pun">-----------+------------------------+-----------+----------+-----------------------------------</span><span class="pln">
 id </span><span class="pun">|</span><span class="pln"> integer </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> nextval</span><span class="pun">(</span><span class="str">'notes_id_seq'</span><span class="pun">::</span><span class="pln">regclass</span><span class="pun">)</span><span class="pln">
 content </span><span class="pun">|</span><span class="pln"> text </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
 important </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">boolean</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
 date </span><span class="pun">|</span><span class="pln"> time without time zone </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="typ">Indexes</span><span class="pun">:</span><span class="pln">
    </span><span class="str">"notes_pkey"</span><span class="pln"> PRIMARY KEY</span><span class="pun">,</span><span class="pln"> btree </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span></pre>

<p>
	إذًا، للعمود <code>id</code> قيم افتراضية تُستخرج من تنفيذ الدالة الداخلية <code>nextval</code> في Postgres. لنُضِف بعض المحتوى إلى الجدول:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_30" style="">
<span class="pln">insert </span><span class="kwd">into</span><span class="pln"> notes </span><span class="pun">(</span><span class="pln">content</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="str">'Relational databases rule the world'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span><span class="pln">
insert </span><span class="kwd">into</span><span class="pln"> notes </span><span class="pun">(</span><span class="pln">content</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="str">'MongoDB is webscale'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">);</span></pre>

<p>
	لنرى الآن كيف يبدو المحتوى الذي أضفناه:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_32" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">select</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> notes</span><span class="pun">;</span><span class="pln">
 id </span><span class="pun">|</span><span class="pln"> content </span><span class="pun">|</span><span class="pln"> important </span><span class="pun">|</span><span class="pln"> date
</span><span class="pun">----+-------------------------------------+-----------+------</span><span class="pln">
  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> relational databases rule the world </span><span class="pun">|</span><span class="pln"> t </span><span class="pun">|</span><span class="pln">
  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">MongoDB</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> webscale </span><span class="pun">|</span><span class="pln"> f </span><span class="pun">|</span><span class="pln">
</span><span class="pun">(</span><span class="lit">2</span><span class="pln"> rows</span><span class="pun">)</span></pre>

<p>
	إذا حاولنا تخزين البيانات في قاعدة البيانات دون العودة إلى مخطط، فلن ينجح الأمر، لأنّ قيم الأعمدة الإجبارية لا بُد أن تكون موجودةً:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_34" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> insert </span><span class="kwd">into</span><span class="pln"> notes </span><span class="pun">(</span><span class="pln">important</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">);</span><span class="pln">
ERROR</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> value </span><span class="kwd">in</span><span class="pln"> column </span><span class="str">"content"</span><span class="pln"> of relation </span><span class="str">"notes"</span><span class="pln"> violates </span><span class="kwd">not</span><span class="pun">-</span><span class="kwd">null</span><span class="pln"> constraint
DETAIL</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Failing</span><span class="pln"> row contains </span><span class="pun">(</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> t</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">).</span></pre>

<p>
	ولا يمكن أن تكون قيمة العمود من النوع الخاطئ:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_37" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> insert </span><span class="kwd">into</span><span class="pln"> notes </span><span class="pun">(</span><span class="pln">content</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="str">'only valid data can be saved'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
ERROR</span><span class="pun">:</span><span class="pln"> column </span><span class="str">"important"</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> of type </span><span class="kwd">boolean</span><span class="pln"> but expression </span><span class="kwd">is</span><span class="pln"> of type integer
LINE </span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="pun">...</span><span class="pln">tent</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="str">'only valid data can be saved'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span><span class="pun">^</span></pre>

<p>
	ولا يمكن القبول بأعمدة غير موجودة في المخطط:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_39" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> insert </span><span class="kwd">into</span><span class="pln"> notes </span><span class="pun">(</span><span class="pln">content</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="str">'only valid data can be saved'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">);</span><span class="pln">
ERROR</span><span class="pun">:</span><span class="pln"> column </span><span class="str">"value"</span><span class="pln"> of relation </span><span class="str">"notes"</span><span class="pln"> does </span><span class="kwd">not</span><span class="pln"> exist
LINE </span><span class="lit">1</span><span class="pun">:</span><span class="pln"> insert </span><span class="kwd">into</span><span class="pln"> notes </span><span class="pun">(</span><span class="pln">content</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="str">'only ...</span></pre>

<p>
	سننتقل تاليًا إلى طريقة الدخول إلى قاعدة البيانات من التطبيق.
</p>

<h2>
	تطبيق Node يستخدم قاعدة بيانات علاقية
</h2>

<p>
	لنشغّل التطبيق كما جرت العادة من خلال التعليمة <code>npm init</code> ونثبّت "nodemon" على أنه اعتمادية تطوير development dependency وكذلك اعتماديات زمن التشغيل التالية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_41" style="">
<span class="pln">npm install express dotenv pg sequelize</span></pre>

<p>
	نجد من بين هذه الاعتماديات <a href="https://sequelize.org/master/" rel="external nofollow">sequelize</a>، وهي المكتبة التي يمكننا من خلالها استخدام Postgres؛ وتنتمي هذه المكتبة إلى مكتبات الربط العلاقي للكائنات <a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping" rel="external nofollow">Object relational mapping</a> -أو اختصارًا ORM-، التي تسمح بتخزين كائنات جافا سكربت JavaScript في قاعدة بيانات علاقية دون استخدام <a href="https://academy.hsoub.com/programming/sql/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-sql-r844/" rel="">لغة SQL</a> بحد ذاتها وبصورةٍ مشابهة للمكتبة "Mongoose" التي استخدمناها مع قاعدة البيانات MongoDB.
</p>

<p>
	لنختبر الآن قدرتنا على الاتصال الناجح بقاعدة البيانات، لهذا أنشئ الملف index.js وأضف إليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_44" style="">
<span class="kwd">require</span><span class="pun">(</span><span class="str">'dotenv'</span><span class="pun">).</span><span class="pln">config</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> sequelize </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">(</span><span class="pln">process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">DATABASE_URL</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dialectOptions</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">require</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      rejectUnauthorized</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> main </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await sequelize</span><span class="pun">.</span><span class="pln">authenticate</span><span class="pun">()</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Connection has been established successfully.'</span><span class="pun">)</span><span class="pln">
    sequelize</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="str">'Unable to connect to the database:'</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

main</span><span class="pun">()</span></pre>

<p>
	ينبغي تخزين سلسلة الاتصال النصية connect string بقاعدة البيانات التي أظهرها الأمر <code>heroku config</code> في ملفٍ له الامتداد <code>env.</code>، وينبغي أن تكون مشابهةً لما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_46" style="">
<span class="pln">$ cat </span><span class="pun">.</span><span class="pln">env
DATABASE_URL</span><span class="pun">=</span><span class="pln">postgres</span><span class="pun">:</span><span class="com">//&lt;username&gt;:&lt;password&gt;@ec2-54-83-137-206.compute-1.amazonaws.com:5432/&lt;databasename&gt;</span></pre>

<p>
	لنتحقق من نجاح الاتصال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_48" style="">
<span class="pln">$ node index</span><span class="pun">.</span><span class="pln">js
</span><span class="typ">Executing</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">default</span><span class="pun">):</span><span class="pln"> SELECT </span><span class="lit">1</span><span class="pun">+</span><span class="lit">1</span><span class="pln"> AS result
</span><span class="typ">Connection</span><span class="pln"> has been established successfully</span><span class="pun">.</span></pre>

<p>
	إذا عمل الاتصال، يمكننا حينها تشغيل الاستعلام الأول. لنعدّل البرنامج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_50" style="">
<span class="kwd">require</span><span class="pun">(</span><span class="str">'dotenv'</span><span class="pun">).</span><span class="pln">config</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">,</span><span class="pln"> </span><span class="typ">QueryTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> sequelize </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">(</span><span class="pln">process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">DATABASE_URL</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dialectOptions</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">require</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      rejectUnauthorized</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> main </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    await sequelize</span><span class="pun">.</span><span class="pln">authenticate</span><span class="pun">()</span><span class="pln">

   </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await sequelize</span><span class="pun">.</span><span class="pln">query</span><span class="pun">(</span><span class="str">"SELECT * FROM notes"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">QueryTypes</span><span class="pun">.</span><span class="pln">SELECT </span><span class="pun">})</span><span class="pln">
   console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
   sequelize</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
 </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="str">'Unable to connect to the database:'</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

main</span><span class="pun">()</span></pre>

<p>
	ينبغي أن يطبع تنفيذ البرنامج ما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_52" style="">
<span class="typ">Executing</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">default</span><span class="pun">):</span><span class="pln"> SELECT </span><span class="pun">*</span><span class="pln"> FROM notes
</span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Relational databases rule the world'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'MongoDB is webscale'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	وعلى الرغم من كون Sequelize مكتبة ربط علاقي للكائنات ORM، أي أنها تحتاج إلى قليلٍ فقط من شيفرة SQL التي تكتبها بنفسك، فقد استخدمنا شيفرة SQL مباشرةً مع تابع Sequelize الذي يُدعى <a href="https://sequelize.org/master/class/lib/sequelize.js~Sequelize.html#instance-method-query" rel="external nofollow">query</a>.
</p>

<p>
	طالما أنّ كل شيء يعمل على ما يرام، لنحوّل التطبيق إلى تطبيق ويب.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_54" style="">
<span class="kwd">require</span><span class="pun">(</span><span class="str">'dotenv'</span><span class="pun">).</span><span class="pln">config</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">,</span><span class="pln"> </span><span class="typ">QueryTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> express </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'express'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> sequelize </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">(</span><span class="pln">process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">DATABASE_URL</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dialectOptions</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">require</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      rejectUnauthorized</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">});</span><span class="pln">


app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/api/notes'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await sequelize</span><span class="pun">.</span><span class="pln">query</span><span class="pun">(</span><span class="str">"SELECT * FROM notes"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">QueryTypes</span><span class="pun">.</span><span class="pln">SELECT </span><span class="pun">})</span><span class="pln">
 res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> PORT </span><span class="pun">=</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">PORT </span><span class="pun">||</span><span class="pln"> </span><span class="lit">3001</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span class="pln">PORT</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">`Server running on port ${PORT}`</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يبدو أن التطبيق يعمل جيدًا. لنتحول الآن إلى استخدام Sequelize بدلًا من SQL.
</p>

<h2>
	النماذج في Sequelize
</h2>

<p>
	يُمثَّل كل جدول من جداول قاعدة البيانات عند استخدام Sequelize بنموذج <a href="https://sequelize.org/master/manual/model-basics.html" rel="external nofollow">model</a>، والذي يُعدُّ صنف <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-javascript-r664/" rel="">JavaScript</a> الخاص بالجدول. لنعرِّف الآن النموذج <code>Note</code> المتعلق بالجدول <code>notes</code> من التطبيق وذلك بتغيير الشيفرة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_56" style="">
<span class="pln">require</span><span class="pun">(</span><span class="str">'dotenv'</span><span class="pun">).</span><span class="pln">config</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Model</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'sequelize'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> express </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'express'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> sequelize </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Sequelize</span><span class="pun">(</span><span class="pln">process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">DATABASE_URL</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dialectOptions</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      require</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      rejectUnauthorized</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> extends </span><span class="typ">Model</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="typ">Note</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
 id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
   primaryKey</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
   autoIncrement</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
 </span><span class="pun">},</span><span class="pln">
 content</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">TEXT</span><span class="pun">,</span><span class="pln">
   allowNull</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
 </span><span class="pun">},</span><span class="pln">
 important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">BOOLEAN
 </span><span class="pun">},</span><span class="pln">
 date</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">DATE
 </span><span class="pun">}</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 sequelize</span><span class="pun">,</span><span class="pln">
 underscored</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
 timestamps</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
 modelName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'note'</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/api/notes'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">()</span><span class="pln">  
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> PORT </span><span class="pun">=</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">PORT </span><span class="pun">||</span><span class="pln"> </span><span class="lit">3001</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span class="pln">PORT</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">Server</span><span class="pln"> running on port $</span><span class="pun">{</span><span class="pln">PORT</span><span class="pun">}`)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لا يوجد شيء جديد في تعريف النموذج، فكل عمودٍ له نوع معرَّف، إضافةً إلى خاصيات أخرى عند الضرورة كأن يكون العمود مفتاحًا أساسيًا للجدول. يضم المعامل الثاني في تعريف النموذج السمة <code>sequelize</code> إضافةً إلى غيرها من معلومات التهيئة. كما عرّفنا أن الجدول لا ينبغي أن يضم أعمدة لها بصمات زمنية timestamps، مثل <code>created_at</code>أنشئ عند و <code>updated_at</code> حُدِّث عند.
</p>

<p>
	عرّفنا أيضًا القيمة <code>true</code> إلى <code>underscored</code>، والتي تعني أن أسماء الجدول مشتقةٌ من أسماء النموذج لكن بصيغة الجمع وباستخدام <a href="https://en.wikipedia.org/wiki/Snake_case" rel="external nofollow">تنسيق الأفعى snake_case</a>، الذي تُوضع فيه الشرطة السفلية بدلًا من الفراغات بين الكلمات وتُكتب بأحرف صغيرة؛ ويعني هذا عمليًا أنه إذا كان اسم النموذج "Note"، فسيكون اسم الجدول المقابل "notes". ولو كان اسم النموذج مكونًا من جزئين مثل "StudyGroup"، فسيكون اسم الجدول المقابل "study_groups". وبدلًا من الاستدلال على أسماء الجداول تلقائيًا، تسمح لك المكتبة Sequelize بتعريف أسماء الجداول صراحةً أيضًا.
</p>

<p>
	تُطبق سياسة التسمية هذه على أسماء الأعمدة أيضًا. فلو عرّفنا أن ملاحظةً ما سترتبط بعام الإنشاء <code>creationYear</code> أي بالمعلومات المتعلقة بعام إنشاء الملاحظة، سنعرّفها في النموذج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_63" style="">
<span class="typ">Note</span><span class="pun">.</span><span class="pln">init</span><span class="pun">({</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  creationYear</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DataTypes</span><span class="pun">.</span><span class="pln">INTEGER</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	سيكون اسم العمود المقابل في قاعدة البيانات <code>creation_year</code>، لكن الإشارة إلى العمود في الشيفرة تكون دائمًا باستخدام تنسيق النموذج نفسه أي طريقة سنام الجمل camel case. وعرّفنا كذلك السمة <code>modelName</code> التي أُسندت إليها القيمة <code>note</code>، وستكون القيمة الافتراضية لاسم النموذج بحرف بداية كبير "Note"، وسترى أنّ هذا أكثر ملاءمةً لاحقًا.
</p>

<p>
	يسهل التعامل مع قاعدة البيانات من خلال <a href="https://sequelize.org/master/manual/model-querying-basics.html" rel="external nofollow">واجهة الاستعلام</a> التي يؤمنها النموذج، إذ يعمل التابع <code>works</code> تمامًا كما يوحي اسمه:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_65" style="">
<span class="pln">app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/api/notes'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">()</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تخبرك الطرفية أن التابع <code>()Note.findAll</code> يُنفِّذ الاستعلام التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_67" style="">
<span class="typ">Executing</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">default</span><span class="pun">):</span><span class="pln"> SELECT </span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"content"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"important"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"date"</span><span class="pln"> FROM </span><span class="str">"notes"</span><span class="pln"> AS </span><span class="str">"note"</span><span class="pun">;</span></pre>

<p>
	سننجز تاليًا وصلة endpoint بغرض إنشاء ملاحظات جديدة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_7956_69" style="">
<span class="pln">app</span><span class="pun">.</span><span class="kwd">use</span><span class="pun">(</span><span class="pln">express</span><span class="pun">.</span><span class="pln">json</span><span class="pun">())</span><span class="pln">

</span><span class="com">// ...</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/api/notes'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">)</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تُضاف الملاحظة الجديدة باستدعاء التابع <a href="https://sequelize.org/master/manual/model-querying-basics.html#simple-insert-queries" rel="external nofollow">create</a> الذي يوفّره النموذج "Note" بعد تمرير كائن يعرِّف قيم الأعمدة لسطر الملاحظة الجديدة على أنه وسيطٌ لهذا التابع.
</p>

<p>
	وبإمكانك أيضًا حفظ قاعدة البيانات بتنفيذ التابع <a href="https://sequelize.org/master/class/lib/model.js~Model.html#static-method-build" rel="external nofollow">build</a> أولًا لإنشاء كائن نموذج من البيانات المطلوبة، ثم استدعاء التابع <a href="https://sequelize.org/master/class/lib/model.js~Model.html#instance-method-save" rel="external nofollow">save</a> وذلك بدلًا من التابع create:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_71" style="">
<span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">build</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">)</span><span class="pln">
await note</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span></pre>

<p>
	لا يؤدي استدعاء التابع <code>build </code>إلى حفظ الكائن في قاعدة البيانات، وبالتالي من الممكن تعديله قبل تنفيذ أمر الحفظ الفعلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_73" style="">
<span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">build</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">)</span><span class="pln">
note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
await note</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span></pre>

<p>
	يُعد استخدام التابع <code>create</code> في المثال السابق أكثر ملاءمةً لما نريده من التطبيق، لذلك سنلتزم باستخدامه من الآن فصاعدًا.
</p>

<p>
	إذا لم يكن الكائن المُنشأ صالحًا، ستظهر رسالة خطأ، لذلك إذا حاولت إضافة ملاحظة جديدة دون محتوى، ستخفق العملية وتكشف لك الطرفية عن السبب بأن "المحتوى لا يمكن أن يكون فارغًا":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_75" style="">
<span class="pun">(</span><span class="pln">node</span><span class="pun">:</span><span class="lit">39109</span><span class="pun">)</span><span class="pln"> </span><span class="typ">UnhandledPromiseRejectionWarning</span><span class="pun">:</span><span class="pln"> </span><span class="typ">SequelizeValidationError</span><span class="pun">:</span><span class="pln"> notNull </span><span class="typ">Violation</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">content cannot be </span><span class="kwd">null</span><span class="pln">
    at </span><span class="typ">InstanceValidator</span><span class="pun">.</span><span class="pln">_validate </span><span class="pun">(</span><span class="str">/Users/</span><span class="pln">mluukkai</span><span class="pun">/</span><span class="pln">opetus</span><span class="pun">/</span><span class="pln">fs</span><span class="pun">-</span><span class="pln">psql</span><span class="pun">/</span><span class="pln">node_modules</span><span class="pun">/</span><span class="pln">sequelize</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">instance</span><span class="pun">-</span><span class="pln">validator</span><span class="pun">.</span><span class="pln">js</span><span class="pun">:</span><span class="lit">78</span><span class="pun">:</span><span class="lit">13</span><span class="pun">)</span><span class="pln">
    at processTicksAndRejections </span><span class="pun">(</span><span class="pln">internal</span><span class="pun">/</span><span class="pln">process</span><span class="pun">/</span><span class="pln">task_queues</span><span class="pun">.</span><span class="pln">js</span><span class="pun">:</span><span class="lit">93</span><span class="pun">:</span><span class="lit">5</span><span class="pun">)</span></pre>

<p>
	لنضف آليةً بسيطةً لاصطياد الأخطاء عند إضافة ملاحظةٍ جديدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_79" style="">
<span class="pln">app</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/api/notes'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">400</span><span class="pun">).</span><span class="pln">json</span><span class="pun">({</span><span class="pln"> error </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<h2>
	التمرينات 13.1 إلى 13.3
</h2>

<p>
	سنبني في هذه التمرينات واجهة خلفية لتطبيق مدوّنات يشابه ما فعلنا في <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%87%D9%8A%D9%83%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-unit-tests-r1132/" rel="">القسم 4</a>، وينبغي أن يتوافق مع الواجهة الأمامية التي أنشأناها في <a href="https://academy.hsoub.com/programming/javascript/react/%D8%AA%D8%B3%D8%AC%D9%8A%D9%84-%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-r1136/" rel="">القسم 5</a> باستثناء معالجة الأخطاء. سنضيف أيضًا ميزات مختلفة إلى الواجهة الخلفية لا يمكن للواجهة الأمامية في القسم 5 التعامل معها.
</p>

<h3>
	التمرين13.1
</h3>

<p>
	أنشئ مستودع غيت هاب GitHub مخصص للتطبيق، ثم أنشئ تطبيق Heroku خاص به إضافةً إلى قاعدة بيانات Postgres، وتأكد من قدرتك على تأسيس اتصال بين التطبيق وقاعدة البيانات.
</p>

<h3>
	التمرين 13.2
</h3>

<p>
	أنشئ باستخدام سطر الأوامر الجدول "blogs" الذي يضم الأعمدة التالية:
</p>

<ul>
<li>
		id: يمثل قيمةً فريدةً تزداد باستمرار.
	</li>
	<li>
		author: قيمة نصية.
	</li>
	<li>
		url: قيمة نصية لا يمكن أن تكون فارغة.
	</li>
	<li>
		title: قيمة نصية لا يمكن أن تكون فارغة.
	</li>
	<li>
		likes: قيمة صحيحة تبدأ من الصفر افتراضيًا.
	</li>
</ul>
<p>
	أضف مدونتين على الأقل إلى قاعدة البيانات. احفظ بعد ذلك الأوامر التي استخدمتها في ملف يُدعى "commands.sql" في جذر التطبيق.
</p>

<h3>
	التمرين 13.3
</h3>

<p>
	أضف إلى تطبيقك وظيفة طباعة المدوّنات الموجودة في قاعدة البيانات باستخدام سطر الأوامر كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_81" style="">
<span class="pln">$ node cli</span><span class="pun">.</span><span class="pln">js
</span><span class="typ">Executing</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">default</span><span class="pun">):</span><span class="pln"> SELECT </span><span class="pun">*</span><span class="pln"> FROM blogs
</span><span class="typ">Dan</span><span class="pln"> </span><span class="typ">Abramov</span><span class="pun">:</span><span class="pln"> </span><span class="str">'On let vs const'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> likes
</span><span class="typ">Laurenz</span><span class="pln"> </span><span class="typ">Albe</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Gaps in sequences in PostgreSQL'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> likes</span></pre>

<h2>
	إنشاء جداول قاعدة البيانات تلقائيا
</h2>

<p>
	يوجد في تطبيقنا الحالي جانب غير مرغوب فهو يفترض وجود قاعدة بيانات مع المخطط المعين، أي أنّ الجدول "notes" قد أُنشأ بتنفيذ الأمر <code>create table</code>.
</p>

<p>
	تُخزّن شيفرة البرنامج على <a href="https://academy.hsoub.com/programming/workflow/git/%d9%83%d9%8a%d9%81-%d8%aa%d8%b3%d8%a7%d9%87%d9%85-%d9%81%d9%8a-%d9%85%d8%b4%d8%a7%d8%b1%d9%8a%d8%b9-%d9%85%d9%81%d8%aa%d9%88%d8%ad%d8%a9-%d8%a7%d9%84%d9%85%d8%b5%d8%af%d8%b1-%d8%b9%d9%84%d9%89-github-r265/" rel="">غيت هاب GitHub</a>، لذلك من المنطقي تخزين الأوامر التي أنشأت بها قاعدة البيانات ضمن سياق الشيفرة لكي يبقى مخطط قاعدة البيانات نفسه كما تتوقعه شيفرة البرنامج. يُمكن للمكتبة أن تولّد تلقائيًا مخططًا انطلاقًا من تعريف النموذج من خلال التابع <a href="https://sequelize.org/master/manual/model-basics.html#model-synchronization" rel="external nofollow">sync</a>.
</p>

<p>
	لندمر الآن قاعدة البيانات الموجودة من خلال أوامر الطرفية على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_84" style="">
<span class="pln">drop table notes</span><span class="pun">;</span></pre>

<p>
	تأكد من تدمير القاعدة بتنفيذ الأمر <code>d\</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_86" style="">
<span class="pln">username</span><span class="pun">=&gt;</span><span class="pln"> \d
</span><span class="typ">Did</span><span class="pln"> not find any relations</span><span class="pun">.</span></pre>

<p>
	لن يعمل التطبيق الآن، لهذا سننفِّذ الأمر التالي مباشرةً بعد تعريف النموذج "Note":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_88" style="">
<span class="typ">Note</span><span class="pun">.</span><span class="pln">sync</span><span class="pun">()</span></pre>

<p>
	عندما يعمل التطبيق سيظهر ما يلي على شاشة الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_91" style="">
<span class="typ">Executing</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">default</span><span class="pun">):</span><span class="pln"> CREATE TABLE IF NOT EXISTS </span><span class="str">"notes"</span><span class="pln"> </span><span class="pun">(</span><span class="str">"id"</span><span class="pln"> SERIAL </span><span class="pun">,</span><span class="pln"> </span><span class="str">"content"</span><span class="pln"> TEXT NOT NULL</span><span class="pun">,</span><span class="pln"> </span><span class="str">"important"</span><span class="pln"> BOOLEAN</span><span class="pun">,</span><span class="pln"> </span><span class="str">"date"</span><span class="pln"> TIMESTAMP WITH TIME ZONE</span><span class="pun">,</span><span class="pln"> PRIMARY KEY </span><span class="pun">(</span><span class="str">"id"</span><span class="pun">));</span></pre>

<p>
	وهكذا، عندما يعمل التطبيق، تُنفَّذ التعليمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_93" style="">
<span class="pln">CREATE TABLE IF NOT EXISTS </span><span class="str">"notes"</span><span class="pun">...</span></pre>

<p>
	التي تُنشئ الجدول "notes" إن لم يكن موجودًا.
</p>

<h2>
	خيارات أخرى
</h2>

<p>
	لنكمل تطبيقنا بإضافة عدة خيارات أخرى.
</p>

<p>
	بإمكاننا البحث عن ملاحظة محددة باستخدام التابع <a href="https://sequelize.org/master/manual/model-querying-finders.html" rel="external nofollow"><code>findByPk</code></a> لأنه يبحث ضمن قيم <code>id</code> التي تمثّل المفتاح الرئيسي لقاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_96" style="">
<span class="pln">app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/api/notes/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يؤدي البحث عن ملاحظة محددة إلى تنفيذ أمر SQL التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_98" style="">
<span class="typ">Executing</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">default</span><span class="pun">):</span><span class="pln"> SELECT </span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"content"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"important"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"date"</span><span class="pln"> FROM </span><span class="str">"notes"</span><span class="pln"> AS </span><span class="str">"note"</span><span class="pln"> WHERE </span><span class="str">"note"</span><span class="pun">.</span><span class="pln"> </span><span class="str">"id"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'1'</span><span class="pun">;</span></pre>

<p>
	في حال عدم وجود أية ملاحظات، سيعيد البحث القيمة <code>null</code> (لا شيء)، وسيعطي رمز الحالة المناسب.
</p>

<p>
	تُعدَّل الملاحظة على النحو التالي، ولا يمكن تعديل سوى الحقل <code>important</code> لأن الواجهة الأمامية لا تحتاج أي شيء آخر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_100" style="">
<span class="pln">app</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="str">'/api/notes/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">important
    await note</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يُستخرج الكائن المتعلق بسطر قاعدة البيانات باستخدام التابع <code>findByPk</code>، ويُعدّل بعدها الكائن وتُخزَّن النتيجة باستدعاء التابع <code>save</code>.
</p>

<p>
	بإمكانك إيجاد شيفرة التطبيق كاملةً في <a href="https://github.com/fullstack-hy/part13-notes/tree/part13-1" rel="external nofollow">المستودع المخصص على GitHub</a> ضمن الفرع "part13-1".
</p>

<h2>
	طباعة الكائن الذي تعيده Sequelize على الطرفية
</h2>

<p>
	تُعد الأداة <code>console.log</code> أفضل أدوات مبرمجي <a href="https://wiki.hsoub.com/JavaScript" rel="external">JavaScript</a> إذ يمكّنهم استعمالها المتكرر من التقاط أسوأ الثغرات. لهذا سنطبع الملاحظات على الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_103" style="">
<span class="pln">app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/api/notes/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لاحظ أنّ النتيجة النهائية ليست ما نتوقعه تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_105" style="">
<span class="pln">note </span><span class="pun">{</span><span class="pln">
  dataValues</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Notes are attached to a user'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2021</span><span class="pun">-</span><span class="lit">10</span><span class="pun">-</span><span class="lit">03T15</span><span class="pun">:</span><span class="lit">00</span><span class="pun">:</span><span class="lit">24.582Z</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  _previousDataValues</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Notes are attached to a user'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2021</span><span class="pun">-</span><span class="lit">10</span><span class="pun">-</span><span class="lit">03T15</span><span class="pun">:</span><span class="lit">00</span><span class="pun">:</span><span class="lit">24.582Z</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  _changed</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Set</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
  _options</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    isNewRecord</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    _schema</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
    _schemaDelimiter</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln">
    raw</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    attributes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="str">'id'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'content'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'important'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'date'</span><span class="pln"> </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  isNewRecord</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فكل الأشياء التي يحتويها الكائن إضافةً إلى البيانات قد طُبعت على الطرفية، لهذا يمكن الوصول إلى النتيجة المرجوة باستدعاء التابع <a href="https://sequelize.org/master/class/lib/model.js~Model.html#instance-method-toJSON" rel="external nofollow"><code>toJSON</code></a> العائد إلى كائن النموذج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_107" style="">
<span class="pln">app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/api/notes/:id'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findByPk</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">toJSON</span><span class="pun">())</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	ها هي النتيجة الآن كما هو متوقع.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_109" style="">
<span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'MongoDB is webscale'</span><span class="pun">,</span><span class="pln">
  important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2021</span><span class="pun">-</span><span class="lit">10</span><span class="pun">-</span><span class="lit">09T13</span><span class="pun">:</span><span class="lit">52</span><span class="pun">:</span><span class="lit">58.693Z</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	في الحالة التي نريد فيها طباعة مجموعة من الكائنات، لن يعمل التابع <code>toJSON</code> مباشرةً، بل يجب أن يُستدعى بصورةٍ مستقلة لكل كائن في المجموعة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_111" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">()</span><span class="pln">

  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">n</span><span class="pun">=&gt;</span><span class="pln">n</span><span class="pun">.</span><span class="pln">toJSON</span><span class="pun">()))</span><span class="pln">

  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وتبدو النتيجة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_113" style="">
<span class="pun">[</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'MongoDB is webscale'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2021</span><span class="pun">-</span><span class="lit">10</span><span class="pun">-</span><span class="lit">09T13</span><span class="pun">:</span><span class="lit">52</span><span class="pun">:</span><span class="lit">58.693Z</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Relational databases rule the world'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2021</span><span class="pun">-</span><span class="lit">10</span><span class="pun">-</span><span class="lit">09T13</span><span class="pun">:</span><span class="lit">53</span><span class="pun">:</span><span class="lit">10.710Z</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">]</span></pre>

<p>
	وربما من الأفضل أن تحوّل المجموعة إلى تنسيق <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">JSON</a> لطباعتها باستخدام التابع <a href="https://wiki.hsoub.com/JavaScript/JSON/stringify" rel="external"><code>JSON.stringify</code></a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_116" style="">
<span class="pln">router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">findAll</span><span class="pun">()</span><span class="pln">

  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">))</span><span class="pln">

  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تُعد هذه الطريقة أكثر ملاءمةً خاصةً إذا احتوت الكائنات على كائنات أخرى، كما أنها مفيدةٌ لتنسيق الكائنات على الشاشة بطريقة تُسهِّل القراءة، ويُنفَّذ ذلك من خلال الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_119" style="">
<span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">))</span></pre>

<p>
	وتبدو النتيجة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7956_121" style="">
<span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"MongoDB is webscale"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"important"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2021-10-09T13:52:58.693Z"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Relational databases rule the world"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"important"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2021-10-09T13:53:10.710Z"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">]</span></pre>

<h2>
	التمرين 13.4
</h2>

<p>
	حوّل تطبيقك إلى تطبيق ويب يدعم العمليات التالية:
</p>

<ul>
<li>
		الحصول على كل المدونات: <code>GET api/blogs</code>.
	</li>
	<li>
		إضافة مدوّنة جديدة: <code>POST api/blogs</code>.
	</li>
	<li>
		حذف مدوّنة: <code>DELETE api/blogs/:id</code>.
	</li>
</ul>
<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part13/using_relational_databases_with_sequelize" rel="external nofollow">Using relational databases with Sequelize</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: أ<a href="https://academy.hsoub.com/devops/cloud-computing/docker/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D8%A7%D9%84%D8%AD%D8%A7%D9%88%D9%8A%D8%A7%D8%AA-r643/" rel="">ساسيات تنسيق الحاويات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">مقدمة عن قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r602/" rel="">التعامل مع قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D8%A6%D9%82%D9%8A%D8%A9-rdm-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r522/" rel="">مفاهيم نموذج البيانات العلائقية RDM الأساسية المهمة في تصميم قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%d9%85%d9%82%d8%a7%d8%b1%d9%86%d8%a9-%d8%a8%d9%8a%d9%86-%d8%a3%d9%86%d8%b8%d9%85%d8%a9-%d8%a5%d8%af%d8%a7%d8%b1%d8%a9-%d9%82%d9%88%d8%a7%d8%b9%d8%af-%d8%a7%d9%84%d8%a8%d9%8a%d8%a7%d9%86%d8%a7%d8%aa-%d8%a7%d9%84%d8%b9%d9%84%d8%a7%d9%82%d9%8a%d8%a9-sqlite-%d9%85%d8%b9-mysql-%d9%85%d8%b9-postgresql-r72/" rel="">مقارنة بين أنظمة إدارة قواعد البيانات العلاقية: SQLite مع MySQL مع PostgreSQL</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">655</guid><pubDate>Thu, 03 Nov 2022 07:07:57 +0000</pubDate></item><item><title>&#x645;&#x627; &#x647;&#x64A; &#x62A;&#x642;&#x646;&#x64A;&#x629; NoSQL&#x61F;</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D9%82%D9%86%D9%8A%D8%A9-nosql%D8%9F-r640/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_08/62f01f539207e_nosql.png.794d591001433c02e342e5adab2fc473.png" /></p>

<p>
	في هذا الفيديو نشرح NoSQL أو مايعرف بـ Not Only SQL، حيث سنشرح لماذا قد نفكر باستخدام <a href="https://academy.hsoub.com/devops/servers/databases/%d8%b4%d8%b1%d8%ad-%d8%a7%d9%84%d9%81%d8%b1%d9%88%d9%82%d8%a7%d8%aa-%d8%a8%d9%8a%d9%86-%d9%82%d9%88%d8%a7%d8%b9%d8%af-%d8%a8%d9%8a%d8%a7%d9%86%d8%a7%d8%aa-sql-%d9%88%d9%86%d8%b8%d9%8a%d8%b1%d8%a7%d8%aa%d9%87%d8%a7-nosql-r71/" rel="">قواعد بيانات NoSQL</a> والفائدة منها، ونعرفك بأنواع قواعد بيانات NoSQL  ولماذا قد نختارها عوضًا عن قواعد البيانات التقليدية كـ <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">MySQL</a> أو <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-postgresql-r481/" rel="">PostgreSQL</a>.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="480" title="ما هي تقنية NoSQL" width="853" src="https://www.youtube.com/embed/ZLlfTf4w9KU"></iframe>
</p>

<p>
	بعد تعرفك على أساسيات تقنية NoSQL، يمكنك البدء في تعلم NoSQL وأنظمة إدارة قواعد البيانات باحترافية من خلال <a href="https://academy.hsoub.com/learn/computer-science/" rel="">دورة علوم الحاسوب المقدمة من أكاديمية حسوب</a>.
</p>
]]></description><guid isPermaLink="false">640</guid><pubDate>Fri, 29 Jul 2022 15:00:00 +0000</pubDate></item><item><title>&#x645;&#x642;&#x627;&#x631;&#x646;&#x629; &#x628;&#x64A;&#x646; MySQL &#x648; MongoDB</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-mysql-%D9%88-mongodb-r627/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_06/6297c1b53bc3a_--MySQL--MongoDB.jpg.37e1899a78e7f8a7b03eb800284b5e37.jpg" /></p>
<p>
	تلعب البيانات أهمية كبيرة في أعمال وشركات اليوم بل إنه يستحيل أن نجد شركة قوية ومنافسة في السوق وليس لديها <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة بيانات</a> قوية، هذه هي قواعد اللعبة في عصرنا الحالي، هل تريد المنافسة والسيطرة على السوق؟ إذا جهز نفسك لبناء قاعدة بيانات قوية ومتكاملة، ولفهم أهمية قواعد البيانات لا بدّ لنا في البداية من تبسيط المفاهيم والتعرف بدقة على ماهيّة <strong>قواعد البيانات</strong> والتي ببساطة هي مجموعة من المعلومات المنظمة في شكل مهيكل (مثل جداول) أو غير مهيكل (مثل المستندات)، ويمكن الوصول إليها وإدارتها وتحديثها بسهولة من خلال أنظمة إدارة قواعد البيانات مثل <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">MySQL</a> و MongoDB.
</p>

<p>
	تكمن أهمية قواعد البيانات في أنها تخزن المعلومات المتعلقة بتفاصيل المنتج البرمجي مثلًا إذا كانت المنتج متجر إلكتروني فستكون المعلومات مثلًا عدد المبيعات ومخزون المنتجات وملفات العملاء وأنشطة التسويق …إلخ، وتساعد قواعد البيانات في جعل عملك أقوى مما يزيد من أرباح شركتك آنذاك. لنتخيل أنه ليس لديك مكان مركزي لتخزين كل هذه المعلومات التي تصدرها الشركة في هذه الحالة لن يكون لديك أدنى فكرة عما يحدث بالفعل في شركتك، وعندها ستبدأ في وضع الافتراضات لما يحدث داخل شركتك، وتتخذ القرارات بناء على تكهنات بدلًا أن يكون بناء على الحقائق.
</p>

<p>
	لاحظ كيف يمكن توظيف قواعد البيانات في فهم ما يحدث بالضبط في مثال المتجر السابق من خلال قراءة المعلومات وتحليلها، في الحقيقة مع اكتشاف الشركات لأهمية قواعد البيانات ازداد الاعتماد عليها، وبدأت شركات البرمجيات بتطوير قواعد البيانات وأنظمتها وجعلها تواكب متطلبات البيانات الحديثة فظهرت لدينا قواعد بيانات كثيرة بعضها للشركات الصغيرة وبعضها للكبير بعضها مغلقة المصدر وبعضها مفتوح المصدر، ومع هذا التنوع وكثرة الخيارات تزداد الحيرة والقلق من اختيار نوع خاطئ يؤدي لكوارث لاحقة للشركة، فما هو نوع قواعد البيانات المناسبة للشركات الناشئة؟ وكيف نختار ما يناسبنا في ظل هذا التنوع الكبير بين قواعد البيانات وأنظمة إدارتها؟
</p>

<p>
	سنحاول في المقال تسليط الضوء على اثنين من أشهر أنظمة إدارة قواعد البيانات وهما MySQL و MongoDB والذين يديران قواعد البيانات العلائقية Relational Database وقواعد بيانات غير العلائقية Non-Relational Database على التتالي، وسنقارن بينهما ونكتشف كيف فرضا نجاحهما وجدارتهما في سوق العمل الحديث، ولنتمكن لاحقًا من استخدامهما في المشاريع التي تناسبهما، وسنسعى لتجنب التحيز بين أنظمة إدارة قواعد البيانات ولكن بالتأكيد هناك بعض المشاريع التي تناسب إحدى الأنظمة أكثر من الآخرى وهذا أمر طبيعي.
</p>

<h2>
	نبذة موجزة عن MySQL و MongoDB
</h2>

<p>
	تُعرف <strong><a href="https://academy.hsoub.com/programming/sql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D9%91%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-sql-r585/" rel="">لغة SQL</a></strong> بأنها لغة استعلام مهيكلة تستخدم لتخزين ومعالجة واسترجاع البيانات الموجودة في قاعدة بيانات علائقية Relational Database وهذه الأخيرة وهي مجموعة من عناصر البيانات التي تترابط مع بعضها بعلاقات محددة على شكل مجموعة من الجداول ذات الأعمدة والأسطر، ويعد التعامل مع هذه اللغة واضحًا لأن قواعد البيانات مهيكلة ومنظمة حتى مع المشاريع الكبيرة.
</p>

<p>
	أما <strong>لغة NoSQL</strong> فهي لغة استعلام غير مهيكلة تستخدم لتخزين ومعالجة واسترجاع البيانات من قاعدة بيانات غير علائقية Non-Relational Database وهذا النوع من قواعد البيانات لا يستخدمُ المخططات Schema لبناء قواعد بيانات وإنما يستخدم نماذج مرن مثل أزواج الاسم والقيمة للمتطلبات Name-Value أو المستندات وهذا ما يمنح قاعدة البيانات المرونة العالية في التكيف مع البيانات المتغيرة للمشاريع الحديثة، ويعد التعامل مع هذه اللغة صعبًا نسبيًا في المشاريع الكبيرة.
</p>

<p>
	تعد أنظمة إدارة قواعد البيانات DBMS -وهي اختصارا Database Management Systems- أنظمة برمجية تُستخدم لتخزين واسترجاع وتنفيذ الاستعلامات على البيانات المخزنة في قاعدة البيانات، وتعمل هذه الأنظمة كواجهة بين المستخدم النهائي وقاعدة البيانات، مما يسمح للمستخدمين بإنشاء وقراءة وتحديث وحذف البيانات في قاعدة البيانات.
</p>

<p>
	قبل أن ندخل في تفاصيل الحديث عن هذين النظامين لا بدّ أن نوضح بأنه يمكن النظر إلى هذه المقارنة على أنها مقارنة بين نوعي قواعد البيانات SQL و NoSQL ولكن بطريقة غير مباشرة، كما أنه من الجدير بالذكر أن هنالك العديد من الأنظمة التي تدير قواعد البيانات من نوع <a href="https://wiki.hsoub.com/SQL" rel="external">SQL</a> نذكر منها MySQL و <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-postgresql-r481/" rel="">PostgreSQL</a> و Microsoft SQL Server وغيرها، وأيضًا هنالك أنظمة إدارة لقواعد البيانات NoSQL مثل MongoDB و BigTable و Redis و RavenDB و Cassandra و HBase و Neo4j و CouchDB وغيرها.
</p>

<h3>
	ما هي MySQL؟
</h3>

<p>
	تعريف قواعد بيانات MySQL هو نظام إدارة قواعد بيانات علائقية RDBMS -وهو اختصارا Relational Database Management System- يستخدم لتحديث وإدارة وإنشاء قواعد البيانات العلائقية، صدر عام 1995 وسرعان ما بنى تاريخًا قويًا وسمعة عالية وموثوقية كبيرة بفضل مميزاته من السهولة والأمان ومع إتاحته كنظام مفتوح المصدر الأمر الذي الذي عزز شعبيته ومكّن المبرمجين من التعديل على الشيفرة البرمجية. أما <strong>قاعدة البيانات العلائقية Relational Database</strong>: فهي مجموعة من عناصر البيانات مرتبطة بعلاقات محددة مسبقًا فيما بينها، وتنظم هذه العناصر كمجموعة من الجداول ذات الأعمدة والصفوف، ويمكن تمييز كل صف في الجدول بمعرف فريد يسمى مفتاح أساسي، ويمكن جعل الصفوف الموجودة بين جداول متعددة مرتبطة باستخدام مفاتيح خارجية.
</p>

<p>
	يتوافق نظام إدارة MySQL مع العديد من الخوادم عبر جميع اللغات والبرامج الوسيطة، كما أن تصميمه متعدد الطبقات مع وحدات مستقلة الأمر الذي يوفر الحماية المطلوبة وهو يدعم الخيوط دعمًا كاملًا من خلال خيوط النواة Kernel Threads، كما يقدم أدوات مدمجة لتحليل الاستعلام وتحليل المساحة، ويمكنه التعامل مع كميات كبيرة من البيانات تصل حتى 50 مليون صف أو أكثر، ويعمل مع العديد من توزيعات يونكس UNIX <a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%A7-%D9%87%D9%88-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%8A%D9%86%D9%83%D8%B3%D8%9F-r451/" rel="">ولينكس Linux</a>.
</p>

<h3>
	ما هو MongoDB؟
</h3>

<p>
	تعريف MongoDB هو نظام لإدارة قواعد البيانات غير العلائقية Non-Relational Databases مثل NoSQL و Cassandra، ويمكننا هذا النظام من إدارة المعلومات في قواعد البيانات سواء إضافة أو حذف أو تعديل أو استرداد، كما أن هذا النظام <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D8%A7%D9%84%D9%85%D9%82%D8%B5%D9%88%D8%AF-%D8%A8%D9%85%D8%B5%D8%B7%D9%84%D8%AD-%D9%85%D9%81%D8%AA%D9%88%D8%AD-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1-open-source%D8%9F-r885/" rel="">مفتوح المصدر</a> وله أيضًا إصدارات تجارية أيضًا. ظهرت الشركة في البداية في عام 2007 عندما واجه المبرمجون الثلاثة وايت ميريمان وإليوت هورويتز وكيفين رايان مشكلة أثناء عمليات التطوير وقابلية التوسع لتطبيق الويب المشهور DoubleClick إذ كان يتطلب الموقع عرض 400,000 إعلان في الثانية، ولكن الاعتماد على مناهج قواعد البيانات العلائقية التقليدية أدى لبطئ كبير الأمر الذي حفزهم لتأسيس شركة 10Gen ولتطور الشركة بعدئذٍ ويغير اسمها لاحقًا إلى MongoDB Inc في عام 2013 ولتطرح اسهمها للاكتتاب العام في عام 2017.
</p>

<p>
	يدعم النظام أشكالًا مختلفة من البيانات وهذا لأن قواعد البيانات التي من نوع NoSQL بحد ذاتها تدعم هذه الأنواع ولا تتطلب قواعد البيانات أي مخططات مسبقة Database Schema مما يسمح بمرونة عالية في تطوير قواعد البيانات. في الواقع يمكن أن تكون المستندات في نفس المجموعة ومع ذلك لها هياكل مختلفة تمامًا فيما بينها.
</p>

<p>
	يعتمد نظام MongoDB أسلوبًا مختلفًا لتخزين البيانات إذ يمثل المعلومات كسلسلة من المستندات المشابهة لصيغة JSON الموجودة في لغة جافاسكربت (للتوسع في فهم صيغة JSON يمكنك الاطلاع على مقال <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">ما هي JSON؟</a>)، وتسمى الصياغة التي يخزن بها Binary JSON أو BSON. وتعرف <a href="https://en.wikipedia.org/wiki/BSON" rel="external nofollow">BSON</a> بأنها شكل ثنائي لتمثيل هياكل البيانات البسيطة أو المعقدة بما في ذلك المصفوفات الترابطية Associative Arrays (المعروفة أيضًا باسم أزواج الاسم والقيمة Name-Value)، والمصفوفات المفهرسة بالأرقام الصحيحة، ومجموعة من الأنواع العددية الأساسية. تتشابه الحقول الموجودة في هذه المستندات مع الأعمدة الموجودة في قاعدة البيانات العلائقية. وعادة ما يستخدم المتغير BSON لتبادل البيانات، يذكر أن شركة MongoDB طورت هذا المتغير عام 2009.
</p>

<h2>
	مقارنة بين MySQL vs MongoDB
</h2>

<p>
	يتشابه هذان النظامان في شكليهما إذ كلاهما نظام إدارة قواعد بيانات DBMS، وكلاهما يمكن الشركات من نشر وتوزيع تطبيقاتها السحابية أو تعديلها أو نشرها. علاوة على ذلك أنشأ مطورو كلا النظامين هذه القواعد في الأصل كقواعد بيانات مفتوحة المصدر لتكون الشيفرة البرمجية مجانية لأي شخص لاستخدامها وتوزيعها. هذه أبرز أوجه التشابه أما الاختلافات سنناقشها بالتفصيل.
</p>

<h3>
	المجتمع والتطوير
</h3>

<p>
	لننظر في المجتمع لتقييم تطوير هذه الأنظمة يشير المجتمع الأكبر إلى أن تطوير هذه الأطر مستمر على قدم وساق. كما أن كثرة استخدام المبرمجين لنظام قاعدة بيانات معين يجعل من السهولة الحصول على الدعم والمساعدة في المجتمعات التقنية.
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th>
				وجه المقارنة
			</th>
			<th>
				قواعد بيانات MySQL
			</th>
			<th>
				قواعد بيانات MongoDB
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				الموقع الرسمي
			</td>
			<td>
				<a href="https://www.mongodb.com/" rel="external nofollow">MongoDB</a>
			</td>
			<td>
				<a href="https://www.mysql.com/" rel="external nofollow">MySQL</a>
			</td>
		</tr>
		<tr>
			<td>
				تاريخ أول إصدار
			</td>
			<td>
				1995
			</td>
			<td>
				2009
			</td>
		</tr>
		<tr>
			<td>
				رقم الاصدار الحالي (الذي كان وقت كتابة المقال)
			</td>
			<td>
				8.0.28
			</td>
			<td>
				5.0.5
			</td>
		</tr>
	</tbody>
</table>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="100419" href="https://academy.hsoub.com/uploads/monthly_2022_06/6297b67d1ff67_databasestackoverflowsurvey.png.7fd55206bd04d923304f1dacf0b5c650.png" rel="" data-fileext="png"><img alt="database stackoverflow survey.png" class="ipsImage ipsImage_thumbnailed" data-fileid="100419" data-unique="baxi3a4uw" src="https://academy.hsoub.com/uploads/monthly_2022_06/6297b6808bc3c_databasestackoverflowsurvey.thumb.png.5471fec156f2a24ff712084291f25ded.png"></a>
</p>

<p>
	بحسب <a href="https://insights.stackoverflow.com/survey/2021#most-popular-technologies-database" rel="external nofollow">الاستبيان</a> السنوي لموقع Stackoverflow جاء فيه سيطرة واضحة لنظام إدارة قواعد بيانات MySQL وهذا أمر منطقي نظرًا لقدمها وفعاليتها في معظم المشاريع آنذاك، ولكن سنجد أيضًا صعود قوي وسريع لنظام إدارة قواعد بيانات MongoDB على مر <a href="https://insights.stackoverflow.com/survey/2020#most-popular-technologies-database" rel="external nofollow">السنوات</a> الماضية وذلك لأن تقنيات الويب تغيرت جدًا وأصبح كل شيء يتفاعل معه المستخدم في الموقع يولد بيانات وهذا الكم الكبير من البيانات تصعبُ إدارته من خلال MySQL، ولذلك ومع أن MySQL ستفوز في سباق الشعبية إلا أن MongoDB ستحجز لنفسها مكانًا في أوائل الأنظمة تطوير قواعد بيانات في المستقبل، وبحسب الاستبيان أيضًا نجد توافق بين جميع المستجيبين والمطورين المحترفين لقواعد بيانات الأكثر شيوعًا، والاختلاف الوحيد الذي نجده هو أن المطورين المحترفين يميلون أكثر قليلًا إلى استخدام Microsoft SQL Server على MongoDB.
</p>

<h3>
	قابلية التوسع
</h3>

<p>
	غالبًا ما يواجه المهندسون والمطورون تحديًا عندما يحتاج المشروع للتوسعة أو عند الزيادة الكبيرة لعدد المستخدمين والطلبات، ويكون ضمان توفر موارد موقع (سواء من قواعد بيانات أو الصور ..,إلخ) من أصعب التحديات، وهذا الأمر يحتاج للدراسة والتخطيط للتعامل مع عدد الزوار الكبير في أوقات ذروة الطلبات. في هكذا مواقف أول ما يخطر ببال المهندسين أننا سنحتاج لتوسيع قوة معالجة الخادم وسعة التخزين ومستويات التوفر للخادم …إلخ، ولكن هل تطوير الخادم هو الخيار الوحيد الذي لدينا؟ أم أن لدينا خيارات أخرى؟ وما هو التوسع بقواعد البيانات أفقيًا وعموديًا؟
</p>

<p>
	ظهر مفهومي التوسع أفقيًا أو التوسع عموديًا في قواعد البيانات عند الزيادة الكبيرة في الاعتماد عليها وكمية البيانات الضخمة وعدد الزوار الكبير لمواقع وتطبيقات الويب الذين يطلبون البيانات ويمكن أن يختلط الأمر على المبتدئين بين لأن كليهما يشتملان على إضافة موارد إلى البنية التحتية التي نضع عليها قواعد البيانات، ولكن هناك فروقات واضحة بين الاثنين من حيث التنفيذ والأداء.
</p>

<p>
	يشير <strong>التوسع العمودي Vertical Scaling</strong> إلى التوسعة من خلال زيادة إمكانيات المكونات المادية للمخدم مثل زيادة قدرة وحدة المعالجة المركزية أو ذاكرة الوصول العشوائي …إلخ، بينما يشير <strong>التوسع الأفقي Horizontal Scaling</strong> إلى التوسع من خلال إضافة المزيد من الخوادم وتوزيع الحمولة عليها.
</p>

<p>
	أحد الاختلافات الأساسية بين الاثنين هو أن القياس الأفقي يتطلب تغيير منطق قاعدة البيانات وجعلها في أجزاء صغيرة من أجل وضعها بالتوازي عبر أجهزة متعددة وتوزيع الحمولة بينها، وغالبًا ما يكون التوسع الرأسي أسهل لأن المنطق لا يحتاج إلى التغيير وإنما فقط توسعة عدد المعالجات والأجهزة.
</p>

<p>
	يمكن لقواعد البيانات MySQL التوسع عموديًا وهذا الأمر يجعلها غير محبذة للمشاريع الضخمة أو التي تتغير بنيتها باستمرار، بينما نجد بأن قواعد MongoDB يمكنها التوسع أفقيًا وعموديًا ولذلك نجدها في المشاريع الكبيرة، ومن الجدير بالذكر أن هنالك عدة فروقات أخرى بين التوسع الأفقي والرأسي لن نناقشها في هذا المقال لكي لا يطول ونخرج عن الموضوع ويمكنك البحث عنها.
</p>

<p>
	بالرغم من ذلك هنالك بعض المبرمجين يحاولون المواربة عن مشكلة عدم إتاحة نظام قاعدة بيانات MySQL توزيع البيانات على مجموعة من المخدمات للقراءة فقط ولكن هذه الترقيعات لا يمكن مقارنتها مع الدعم الأصيل الموجود في MongoDB، ونشير أيضًا إلى أن التوسع العمودي في قواعد البيانات له حد أعظمي سواء من قدرة المعالج أو سعة الذاكرة العشوائية …إلخ.
</p>

<h3>
	مخطط البيانات وتنوع البيانات
</h3>

<p>
	في نظام قواعد البيانات MongoDB تعرض البيانات في أزواج مثل مستندات JSON، مما يتيح لقاعدة البيانات قيودًا أقل ومرونة أكبر بالمقارنة مع الطرق الأساسية بالتصميم والتي تعتمد على المخطط وأنواع البيانات والقيود والروابط، ولكن الأمر يتغير بالنسبة لنظام قواعد البيانات MySQL، فبالرغم من إمكانية تغيير المخطط مع مرور الزمن، إلا أن التعديلات ليست مرنة وديناميكية كما هو الحال في قواعد بيانات القائمة على المستندات مثل NoSQL.
</p>

<p>
	كما تتطلب MySQL إنشاءً مسبقًا لمخطط قواعد وتنظيم الجداول والأعمدة قبل تخزين أي بيانات، بالإضافة إلى ذلك يتطلب تعديل مخطط البيانات إعادة التفكير بعناية بكيفية تنفيذ التعديل من خلال لغة تعريف البيانات DDL (وهي اختصار Data Definition Language) أو لغة معالجة البيانات DML (وهي اختصار Data Manipulation Language) لأن نظام التعديل الذي تفرضه قواعد بيانات SQL صارم لذلك عندما يتغير مخطط قاعدة البيانات خصوصًا إن كانت التغييرات كبيرة، فنعيد بناء قاعدة البيانات ثم ننقل البيانات عليها من جديد، وفي الواقع هذا الاتساق هو من أكثر نقاط القوة في MySQL لأنه يحافظ على البيانات منظمة ومتسقة.
</p>

<p>
	وأما بالنسبة لتنوع البيانات فإن قاعدة بيانات MongoDB تسمح بتخزين المستندات والتي تختلف في المحتوى والحجم، أما MySQL نظرًا لأن مخطط البيانات أكثر تقييدًا وصرامة، فإن كل صف داخل الجدول يتطلب نفس الأعمدة (أي مثلًا يجب لعمود الاسم في جدول بيانات MySQL أن يأخذ نفس نوع البيانات ونفس الحجم وفي حالتنا كون Varchar(50) أي بحجم 50 محرف فقط‎) والتي يمكن أن تكون صعبة، ولذلك تتفوق قاعدة بيانات MongoDB على قاعدة بيانات MySQL عند التعامل مع كميات متنوعة وكبيرة من البيانات المعقدة.
</p>

<h3>
	الأداء والسرعة
</h3>

<p>
	تحتل سرعة وأداء قواعد البيانات مكانة كبيرة في سباق المقارنة وفي الحقيقة لا تتطلب كل المشاريع البرمجية سرعة كبيرة لنتخيل مثلًا نشاطًا تجاريًا يعمل بكميات صغيرة من البيانات ذات تنوع بسيط سنُلاحظ بأن السرعة ليست بالضرورة أمرًا مهمًا نظرًا لأن الميزات الأخرى (مثل الموثوقية واتساق البيانات)، ولذلك فإن الخيار الأفضل في هذه الحالة هو قواعد البيانات.
</p>

<p>
	تقبل MongoDB كميات أكبر من البيانات المهيكلة أو غير المهيكلة كما أنها أسرع من MySQL. ومع ذلك لا ينظر المهندسون إلى السرعة كعنصر محوري بقدر ما أنها ميزة إضافية لمميزات إحدى قواعد البيانات، في الحقيقة إن المقارنة بين السرعة ستكون منطقية في حال المقارنة بين نوعين من قواعد البيانات المهيكلة ولن نستطيع تطبيق ذلك لأن هذا سيُعد ظلمًا لقواعد البيانات MongoDB بإهمال أفضل ميزة بها وهي قواعد البيانات غير المهيكلة، وعمومًا تتمتع MySQL بسرعة جيدة في قواعد البيانات المهيكلة وتتحسن سرعتها من خلال الاستخدام الصحيح للفهارس، كما تتمتع MongoDB بأداء مرِن وسرعة كبيرة للبيانات غير المهيكلة، ولكن إنشاء فهارس على سمات بيانات متنوعة يصبح أمرًا صعبًا، الأمر الذي يجعل MongoDB تتطلب تحسينًا متكررًا لمخطط البيانات، ولذلك يكون هناك مخاطرة بمشاكل تتعلق باتساق البيانات.
</p>

<h3>
	الحماية
</h3>

<p>
	تستخدم نظام قواعد البيانات MySQL نموذج أمان قائم على الامتيازات Privileges، والذي يتطلب مصادقة المستخدم أي أن النظام يتطلب عمليات أمان وهي المصادقة Authentication والتفويض Authorization والتحقق Verification، بالإضافة إلى ذلك تستخدم قواعد البيانات MySQL اتصالات مشفرة بين العملاء والخادم وذلك من خلال طبقة مآخذ التوصيل الآمنة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr></abbr> بروتوكول أمان.
</p>

<p>
	تتشابه طريقة الحماية التي يوفرها نظام قواعد البيانات MongoDB إذ هو الآخر يعتمد على الامتيازات. بالإضافة إلى ذلك إذا كان التشفير مطلوبًا فيمكن تطبيق بروتوكول طبقة التوصيل الآمنة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr></abbr> أو تعطيله إن لزم الأمر، في الحقيقة يوفر نظامي MongoDB و MySQL نماذج أمان قوية والفارق غالبًا ما يكون في طريقة تطبيق المطورين والمهندسين للمارسات الأمنية الشائعة أما قواعد البيانات وأنظمتها فهي ذات أمان قوي.
</p>

<h3>
	خصائص ACID
</h3>

<p>
	تعد خصائص ACID وهي اختصار للكلمات التالية: الذرية Atomicity والاتساق Consistency والعزل Isolation والمتانة Durability من الخصائص المهمة جدًا عند التعامل مع قواعد البيانات، ويعد توافر هذه الشروط أساسيًا للوثوق بتعاملات قاعدة البيانات يذكر أن أول من طرح هذه الشروط هو العالم جيم جراي Jim Gray وذلك في أواخر الستينات القرن العشرين. تتكون تعاملات قواعد البيانات <a href="https://wiki.hsoub.com/SQL/transactions" rel="external">Database Transaction</a> من مجموعة من العمليات المفردة. فمثلًا عند تحويل مبلغ من حساب بنكي إلى آخر، يخصم المبلغ من حساب المصدر ويضاف في الحساب المستقبل. فيكون لدينا عمليتان لكنهما معا تشكلات تعاملًا واحدًا، وعمومًا لنشرح بالضبط أهمية كل خاصية من هذه الخواص:
</p>

<ol>
	<li>
		<strong>الذرية Atomicity</strong>: وتعني أن تعاملات قاعدة البيانات إما أن تنفذ جميع عملياتها بصورة كاملة أو لا تُنفذ أيًا منها، بمعنى أنه لا يوجد حل وسط، ففي مثال التحويل البنكي إما أن تنفذ عمليتي الخصم والإيداع أو لا تُنفذ أية واحدة منها لأن تنفيذ أحدهما وفشل الآخر سينتجُ عنه خلل في صحة البيانات.
	</li>
	<li>
		<strong>الاتساق Consistency</strong>: وتعني أن تظل قاعدة الباينات ملتزمة بقوانين تكامل البيانات كما حددها مصمم قاعدة البيانات بعد تنفيذ التعامل، فمثلًا إذا حُدد الحد الأدنى للرصيد بمبلغ معين يجب أن ترفض قاعدة البيانات أي تعامل ينتج عنه في النهاية إخلال بهذا القانون.
	</li>
	<li>
		<strong>العزل Isolation</strong>: وتعني أن تنفذ التعاملات المختلفة بمعزل عن بعضها بعضًا، ويختص هذا الشرط بقواعد البيانات التي تنفذ عدة تعليمات متزامنة، فمثلًا إذا أراد العميل الكشف عن رصيده أثناء أجراء تعامل التحويل مالي يجب أن تمنحه قاعدة البيانات إما البيانات التي سبقت التحويل أو التي نتجت عنه (بفرض أنها نفذت بنجاح).
	</li>
	<li>
		<strong>المتانة Durability</strong>: وهي إذا ظهر للمستخدم نتيجة مفادها أن التعامل نُفذّ بنجاح، فإن ذلك يعني أن التعامل لن يُتراجع عنه مهما حدث، حتى في حالة حدوث أي أعطال لاحقة في قاعدة البيانات.
	</li>
</ol>

<p>
	يوفر كلا النظامين خصائص ACID وبالرغم من أن MongoDB تأخرت سنة كاملة لإضافتها ولكنها الآن متاحة، كما أن نظام قواعد البيانات جعل MongoDB هذه الخصائص غير مفعلة بصورة افتراضية إلا أنه يمكننا تفعيلها، ولكن تنفيذ هكذا خصائص سيتطلب التضحية بالسرعة والتوافر العالي.
</p>

<h3>
	طريقة كتابة الاستعلام
</h3>

<p>
	يعد الفرق بين البيانات المهيكلة وغير المهيكلة نقطة انطلاق مفيدة لأن البيانات المنظمة تتبع نموذجًا أو مخططًا محددًا جيدًا. بينما نجد بأن البيانات غير المهيكلة ليست منظمة وفقًا لأي نموذج محدد مسبقًا. ولذلك من المنطقي أن نجد نظام قواعد البيانات MySQL يستخدم لغة الاستعلام المهيكلة SQL عند طلب معلومات من جدول قاعدة بيانات، كما أنه لإنشاء جداول في قاعدة البيانات يتطلب معرفة بلغة تعريف البيانات DDL، ولتعديل البيانات يجب تعلم لغة معالجة البيانات DML وبذلك نستطيع التحكم الكامل بقواعد البيانات.
</p>

<p>
	أما بالنسبة لنظام قواعد البيانات MongoDB فهي تعتمد على لغة استعلام غير مهيكلة وهي MongoDB Query Language، والتي تعتمد بدورها على جافاسكربت وتحديدًا طريقة تبادل البيانات JSON الأمر الذي يجعل MongoDB تدعم لغات متعددة (مثل بايثون وجافا و C#‎ و Perl و PHP وروبي وجافاسكربت) ويمكن كتابة استعلام مركب ومحدد لمختلف الحقول داخل مستندات المجموعة باستخدام عوامل تشغيل الاستعلام.
</p>

<p>
	لنستعرض المثال التالي لفهم كيفية الاختلافات التي تحدث بين الاستعلامات لنفترض أن لدينا قاعدة بيانات تحتوي على جدول به الأعمدة التالية:
</p>

<ul>
	<li>
		الاسم
	</li>
	<li>
		العنوان
	</li>
	<li>
		رقم حساب
	</li>
	<li>
		متوسط كمية الطلب
	</li>
	<li>
		السعر
	</li>
	<li>
		عدد مخزون المنتجات
	</li>
</ul>

<p>
	من قراءة سريعة للتسميات يمكننا معرفة أو توقع المدخلات في كل عمود وبالتالي يمكننا الاستعلام عن البيانات وتحليلها بسهولة لأن تدفق البيانات محدد جيدًا. أما بالنسبة للقواعد البيانات غير المهيكلة فإن البيانات بها لا تتناسب بدقة مع الأعمدة. فمثلًا يمكن أن يتضمن جدول بيانات غير مهيكلة ما يلي:
</p>

<ul>
	<li>
		مقاطع فيديو
	</li>
	<li>
		نشاط الجهاز المحمول
	</li>
	<li>
		استخدام وسائل التواصل الاجتماعي
	</li>
	<li>
		مستندات نصية
	</li>
	<li>
		صور
	</li>
</ul>

<p>
	هل هنالك طريقة لمعرفة ما هو مقطع الفيديو أو الأغنية الشائعة التي أدخلها المستخدم؟ غالبًا لا يمكننا معرفة أو توقع ذلك، ولهذا السبب لا يمكننا استخدام الأدوات التقليدية للاستعلام عنه لأن تغير البيانات ينتج عنه تغير طريقة التعامل معها، وعمومًا الجدول التالي سيمنحنا المعرفة مبدئية للفوارق بين طريقة طريقة الاستعلام في MySQL و MongoDB.
</p>

<p>
	وهذه نظرة سريعة لبعض التعليمات في كل من نظام إدارة قواعد البيانات MySQL و MongoDB.
</p>

<p>
	الاستعلام عن جميع الموظفين:
</p>

<ul>
	<li>
		من خلال MySQL تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_33" style=""><span class="kwd">select</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="typ">Employee</span><span class="pun">;‎</span></pre>

<ul>
	<li>
		من خلال MongoDB تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_35" style=""><span class="pln">db</span><span class="pun">.</span><span class="typ">Employee</span><span class="pun">.</span><span class="pln">find</span><span class="pun">()‎</span></pre>

<p>
	الاستعلام في بنية قواعد البيانات المعقدة:
</p>

<ul>
	<li>
		من خلال MySQL تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_37" style=""><span class="pln">SELECT E</span><span class="pun">.*</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="typ">Employee</span><span class="pln"> E inner join </span><span class="typ">Dept</span><span class="pln"> D on E</span><span class="pun">.</span><span class="pln">EMPID</span><span class="pun">=</span><span class="pln">D</span><span class="pun">.</span><span class="pln">EMPID </span><span class="typ">Where</span><span class="pln"> D</span><span class="pun">.</span><span class="typ">City</span><span class="pun">=’</span><span class="typ">Irving</span><span class="pun">’</span></pre>

<ul>
	<li>
		من خلال MongoDB تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_41" style=""><span class="pln">db</span><span class="pun">.</span><span class="typ">Employee</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"Address.City"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"Irving"</span><span class="pln"> </span><span class="pun">}).</span><span class="pln">pretty</span><span class="pun">()‎</span></pre>

<p>
	ادخال مجموعة من البيانات:
</p>

<ul>
	<li>
		من خلال MySQL تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_39" style=""><span class="typ">Insert</span><span class="pln"> </span><span class="kwd">into</span><span class="pln"> </span><span class="typ">Employee</span><span class="pln"> values </span><span class="pun">(‘</span><span class="typ">Brian</span><span class="pln"> </span><span class="typ">Lockwood</span><span class="pun">’,</span><span class="lit">45</span><span class="pun">,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">A</span><span class="pun">’),(‘</span><span class="typ">Charles</span><span class="pun">’,</span><span class="lit">35</span><span class="pun">,’</span><span class="pln">A</span><span class="pun">’)</span></pre>

<ul>
	<li>
		من خلال MongoDB تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_43" style=""><span class="pln">document </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"Name"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"Brian Lockwood"</span><span class="pun">,</span><span class="str">"Age"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"45"</span><span class="pun">,</span><span class="pln"> status</span><span class="pun">:</span><span class="str">"A"</span><span class="pun">},</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"Name"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"Charles"</span><span class="pun">,</span><span class="str">"Age"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"35"</span><span class="pun">,</span><span class="pln"> status</span><span class="pun">:</span><span class="str">"A"</span><span class="pun">}]</span></pre>

<p>
	طريقة استخدام distinct لتصفية النتائج المكررة من استعلام معين:
</p>

<ul>
	<li>
		من خلال MySQL تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_45" style=""><span class="typ">Select</span><span class="pln"> distinct status </span><span class="kwd">from</span><span class="pln"> </span><span class="typ">Employee</span><span class="pun">;‎</span></pre>

<ul>
	<li>
		من خلال MongoDB تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_47" style=""><span class="pln">db</span><span class="pun">.</span><span class="typ">Employee</span><span class="pun">.</span><span class="pln">distinct</span><span class="pun">(</span><span class="pln"> </span><span class="str">"status"</span><span class="pun">);‎</span></pre>

<p>
	طريقة الاستعلام مشروط:
</p>

<ul>
	<li>
		في MySQL تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_49" style=""><span class="typ">Select</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="typ">Employee</span><span class="pln"> </span><span class="kwd">where</span><span class="pln"> </span><span class="typ">Age</span><span class="pun">&gt;</span><span class="lit">30</span></pre>

<ul>
	<li>
		في MongoDB تكون التعليمة:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_4716_31" style=""><span class="pln">db</span><span class="pun">.</span><span class="typ">Employee</span><span class="pun">.</span><span class="pln">find </span><span class="pun">(</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Age</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">$gt </span><span class="pun">:</span><span class="pln"> </span><span class="str">"30"</span><span class="pun">}</span><span class="pln"> </span><span class="pun">});‎</span></pre>

<p>
	يمكننا في MySQL تطبيق تعليمات الدمج لاسترداد البيانات من جدولين أو أكثر من جداول قاعدة البيانات كما أن تعليمة الدمج <a href="https://wiki.hsoub.com/SQL/join" rel="external">JOIN</a> توفر العديد من أنواع الدمج مثل الدمج الداخلي أو الخارجي أو اليساري أو اليمني أو المتقاطع، بينما لا تقدم MongoDB عمليات دمج لنتائج الاستعلام وليس لديها تعليمات تعادل هذه الوظيفة بالإضافة إلى ذلك لا توفر MongoDB القوادح Triggers والتي هي وحدات منطقية مقادة بالأحداث مزروعة في قاعدة البيانات، وتُنفذُ قاعدة البيانات أوامر القوادح أوتوماتيكيًا وتكون هذه التعليمات خاصة بالتعامل مع بيانات موجودة في جداول محددة بينما MySQL توفرها.
</p>

<h3>
	سهولة التعلم للمبتدئين
</h3>

<p>
	يعد نظام قواعد بيانات MySQL سهل نسبيًا وذلك بسبب أنه متسق ومنظم وهيكليته واضحة ولذلك من الطبيعي أن يكون تعلمه سهل وبسيط رغم طول منحنى تعلمه لكثرة المفاهيم فيه (وأحيانًا تعقيدها) بينما في المقابل نجد بأن البنية غير المهيكلة والمرونة العالية يمكن أن تجعل عملية التعلم أصعب نظرًا لكثرة التفاصيل والسيناريوهات رغم أن تعلم بدء استعمالها وتنفيذها سهل وسريع ويكون غالبًا مدمجًا مع اللغة البرمجية نفسها (أي تكتب الاستعلامات بلغة جافاسكربت بدلًا من لغة SQL) لما تخفي عن المستخدم التعقيد الداخلي.
</p>

<h2>
	أيهما أفضل MySQL vs MongoDB؟
</h2>

<p>
	يعد كل من نظامي MySQL و MongoDB من الأنظمة القوية لإدارة قواعد البيانات، وتعمل كل واحدة منها بصورة مختلفة عن الأخرى نظرًا للاختلاف في نوع قواعد البيانات التي يتعاملان معها، ومن الصعوبة تحديد قاعدة البيانات الأفضل إذ يعتمد الأمر كله على السياق بعض الشركات تعتمد على كلا النظامين للتعامل مع مهام مختلفة وهذا أمر جيد والبعض الآخر يفضل التعامل فقط مع MongoDB لزيادة التركيز وتخفيف التشتت.
</p>

<h2>
	متى نستخدم MySQL و MongoDB؟
</h2>

<p>
	بالرغم من المزايا العديدة التي يتمتع بها نظام MongoDB إلا أن MySQL تفوقت عليها في الموثوقية واتساق البيانات. وإذا كان الأمان يمثل أيضًا أولوية فإن MySQL معترف به على نطاق واسع كواحد من أكثر نظم إدارة قواعد البيانات أمانًا.
</p>

<p>
	تعد قواعد البيانات العلائقية الخيار الأنسب للتطبيقات متعددة المستخدمين وكل مستخدم له صلاحيات مختلفة وتتطلب أمان عال وموثوقية، مثل أنظمة المحاسبة والمصارف والبنوك لأن MySQL تركز على الوفاء بخصائص ACID وسلامة المعاملات، بينما تركز MongoDB على السماح بمعدل معاملات مرتفع ولذلك نجدها لا تدعم خصائص ACID في الوضع الافتراضي، وعمومًا يوصى باستخدام نظام MySQL للشركات أو المؤسسات أو المشاريع ذات مخطط البيانات الثابت والتي لا تنوي توسيع نطاق تنوع البيانات، مما يتطلب صيانة سهلة ومنخفضة مع ضمان سلامة البيانات وموثوقيتها، وهي مناسبة أيضًا لمشاريع <a href="https://academy.hsoub.com/entrepreneurship/ecommerce/%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D8%A7%D9%84%D8%AA%D8%AC%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9-%D9%88%D9%85%D8%A7-%D8%A7%D9%84%D9%81%D8%B1%D8%B5-%D9%88%D8%A7%D9%84%D8%AA%D8%AD%D8%AF%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%8A-%D8%B3%D8%AA%D9%88%D8%A7%D8%AC%D9%87%D9%86%D8%A7-%D8%B9%D9%86%D8%AF-%D8%AF%D8%AE%D9%88%D9%84%D9%86%D8%A7-%D9%84%D9%84%D8%B3%D9%88%D9%82%D8%9F-r732/" rel="">التجارة الإلكترونية</a> والمواقع التي تتطلب بروتوكولات أمان وموثوقية عالية مثل المشاريع الحكومية.
</p>

<p>
	أما نظام إدارة قواعد البيانات MongoDB فهو الخيار الأنسب للشركات الحديثة أو المشاريع التقنية المتطورة ذات المخطط غير مستقر لأن طبيعة البيانات غير العلائقية تسمح باستخدام قواعد البيانات بحرية وبدون بنية محددة مسبقًا الأمر الذي يسهل التحديث البنية أو تطويرها، وتستخدم غالبًا في المشاريع التي تتطلب إدارة المحتوى المتنوع، ومشاريع إنترنت الأشياء Internet of Things، ومواقع التحليلات والإحصائيات في الزمن الحقيقي Real-Time، والمواقع والتطبيقات عالية الاستخدام إجمالًا.
</p>

<p>
	يعد موقع Shutterfly مثلًا مميزًا لكيفية الانتقال إلى قواعد البيانات MongoDB، وهو واحدٌ من أشهر مواقع مشاركة للصور عبر الإنترنت، واعتمد في البداية على استخدام قواعد البيانات العلائقية المقدمة من شركة أوراكل لكن قواعد البيانات العلائقية غير مرنة لطبيعة عمل الموقع ومكلفة عند التوسع، كما تسببت في بعض الأحيان باختناقات خصيصًا عند التعامل مع عدد كبير من البيانات، لأن الشركة لديها أكثر من 6 مليارات صورة بالإضافة إلى معدل عمليات يصل إلى 10000 عملية في الثانية، وسرعان ما أدركت الشركة بأن الانتقال إلى قاعدة بيانات غير علائقية تعتمد على المستندات سيُساعدها على زيادة قابلية تطوير الموقع وتحسين أدائه وزيادة إنتاجية وقت البرمجة.
</p>

<p>
	يتيح نموذج مستند MongoDB للمطورين تخزين البيانات بالطريقة التي هي عليها بدلًا من محاولة تحويلها لتناسب نوع قواعد بيانات معين، من خلال عملية Normalization وهي عملية تنظيم البيانات في قاعدة البيانات (لمزيد من المعلومات يمكنك الاطلاع على مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AD%D9%8A%D8%AF-normalization-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r551/" rel="">فهم عملية التوحيد Normalization المستخدمة عند تصميم قاعدة البيانات</a>)، قارنت الشركة بين العديد من أنظمة قواعد البيانات البديلة الأخرى مثل BerkeleyDB أو CouchDB أو Cassandra لتستقر في النهاية على MongoDB لإدارة وتخزين بيناتها وأكدت الشركة أنها مسرورة بقرارها الانتقال من Oracle إلى MongoDB واستطاعت توفير 20% من النفقات المتعلقة بقواعد البيانات بعد هذا الانتقال بحسب <a href="https://www.mongodb.com/customers/shutterfly" rel="external nofollow">تصريح</a> أحد مهندسيها.
</p>

<p>
	إذا أردت الاطلاع على مقارنة شاملة وسريعة حول كل من MongoDB و MySQL، فيمكنك مشاهدة الفيديو الآتي:
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="639" referrerpolicy="strict-origin-when-cross-origin" src="https://academy.hsoub.com/applications/core/interface/index.html" title="مقارنة قواعد البيانات MySQL و MongoDB" width="1136" data-embed-src="https://www.youtube.com/embed/UL-gPrgoRFo"></iframe>
</p>

<h2>
	الخاتمة
</h2>

<p>
	تعرفنا في هذا المقال على أهمية قواعد البيانات في الشركات وأخذنا نظرة سريعة إلى سرعة تطورها مع كثرة الاعتماد عليها وبعدها اطلعنا على نظامي إدارة قواعد البيانات MySQL و MongoDB وتعمقنا في فهم الاختلافات والتشابه بينهما من خلال الاطلاع على المجتمع والشعبية وقابلية التوسع ومن ثم فهمنا بين مخطط البيانات وتنوعها بين كِلا النظامين كما تعرفنا على تشابه سرعة وأداء النظامين ولنتعرف بعدها على طريقة حماية قواعد البيانات وإيفاء كل نظام بخصائص ACID ولندخل بعدها بالعمق أكثر من خلال معرفة كيفية كتابة الاستعلامات بينها ومن ثم سهولة تعلم المبتدئين لهذين النظامين وأجبنا بعدها على السؤال المكرر في الأوساط التقنية وهو أيهما أفضل MySQL vs MongoDB؟ كما اختتمنا المقال من خلال معرفة متى نستخدم كل منهما.
</p>

<p>
	وختامًا يعتمد القرار النهائي على متطلبات المشروع ونوعية بياناته الذي نعكف على تطويره لذلك يجب أن تكون متطلبات المشروع واضحة، وعمومًا ستقدم كلتا قاعدتي البيانات أداءً مُرضيًا للغاية إذا طبقت في سياق يناسبها.
</p>

<h2>
	المصادر
</h2>

<ul>
	<li>
		مقال <a href="https://searchdatamanagement.techtarget.com/definition/MongoDB" rel="external nofollow">?What is MongoDB</a> لصاحبه Jack Vaughan.
	</li>
	<li>
		مقال <a href="https://www.nextplatform.com/2021/03/25/the-world-has-changed-why-havent-database-designs/" rel="external nofollow">?THE WORLD HAS CHANGED – WHY HAVEN’T DATABASE DESIGNS</a> لكاتبه Avishai Ish-Shalom.
	</li>
	<li>
		مقال <a href="https://blog.panoply.io/mongodb-and-mysql" rel="external nofollow">MongoDB vs MySQL: The Differences Explained</a> لكاتبه Mauro Chojrin.
	</li>
	<li>
		مقال <a href="https://www.mongodb.com/compare/mongodb-mysql" rel="external nofollow">?What are the main differences between MongoDB and MySQL</a> لمحرري الموقع.
	</li>
	<li>
		مقال <a href="https://blog.quest.com/how-to-work-with-data-using-mongodb-query-language/" rel="external nofollow">How to work with data using MongoDB Query Language</a> لصاحبه Prashanth Jayaram.
	</li>
	<li>
		مقال <a href="https://devopedia.org/mongodb-query-language" rel="external nofollow">MongoDB Query Language</a> لمحرري الموقع.
	</li>
</ul>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		كتاب <a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تصميم قواعد البيانات</a>
	</li>
	<li>
		كتاب <a href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL</a>
	</li>
	<li>
		<a href="https://wiki.hsoub.com/SQL" rel="external">توثيق SQL</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">627</guid><pubDate>Tue, 28 Jun 2022 16:08:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r602/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_04/6247f9bbc4eb2_---.png.27b62bdb45846857a8f3058f38d91042.png" /></p>
<p>
	سنركز في هذا الجزء من السلسلة على بعض التطبيقات العملية التي يمكن استخدام <a href="https://wiki.hsoub.com/Python" rel="external">لغة بايثون</a> فيها، وكذلك وحدات المكتبات التي سنستخدمها في كتابة تلك التطبيقات، كما سنتعلم بعض التقنيات الجديدة أثناء كتابة تلك التطبيقات، مثل <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">قواعد البيانات </a>و<a href="https://academy.hsoub.com/certificates/comptia/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D9%88%D8%A7%D8%B3%D9%8A%D8%A8-%D9%85%D8%B5%D8%B7%D9%84%D8%AD%D8%A7%D8%AA-%D9%88%D9%81%D9%87%D9%85-%D8%B7%D8%A8%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A9-r65/" rel="">شبكات الحواسيب</a> و<a href="https://academy.hsoub.com/devops/networking/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8%D9%8A%D8%A9-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%B9%D8%A7%D9%84%D9%85%D9%8A%D8%A9-r548/" rel="">الشبكة العالمية -الويب-</a>، وكذلك بعض المزايا الأساسية لنظم تشغيل الحواسيب، لكننا لن نتعمق في هذه التقنيات كثيرًا لأننا نهتم بتعليم البرمجة فقط، ويمكنك الاستعانة بمواقع أخرى أو مصادر يمكن الاستزادة منها.
</p>

<p>
	وقد اخترنا موضوعات تعكس المجالات التي تتكرر في قائمة Python tutor البريدية (القائمة البريدية لمعلمي بايثون)، والتي يفترض أن تكون الأفضل في تلبية احتياجات المبرمجين الجدد، فإذا لم يكن المجال الذي تريده موجودًا فيها فقد تجد روابط إلى مصادر تتعلم فيها عن ذلك المجال.
</p>

<p>
	تعتمد جميع الفصول الباقية من السلسلة على <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a> وحدها، ولا شك أن الإمكانيات التي سنذكرها قد تكون موجودةً في <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت</a> وVBScript، إلا أن الاختلافات في هذا المستوى من العمق والتفاصيل أكبر من أوجه التشابه بكثير، لأن هذه تطبيقات عملية وليست مفاهيم نظريةً.، فأسهل طريقة للوصول إلى ويندوز مثلًا من جافاسكربت أو VBScript ستكون من خلال مضيف سكربت ويندوز WSH الذي ذكرناه من قبل، لكن هذا يختلف كليًا عن وحدة نظام التشغيل في بايثون، فلا معنى للموازنة بينها.
</p>

<p>
	سننظر في هذا المقال من سلسلة <a href="https://academy.hsoub.com/tags/%D8%AA%D8%B9%D9%84%D9%85%20%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">تعلم البرمجة</a> في كيفية تخزين البيانات ومعالجتها من خلال حزمة قاعدة البيانات، وقد رأينا سابقًا كيفية استخدام الملفات في تخزين كميات صغيرة من البيانات في برنامج دليل جهات الاتصال الذي مررنا عليه عدة مرات من قبل، غير أن استخدام الملفات يزداد تعقيدًا مع زيادة تعقيد البيانات نفسها، وزيادة حجمها، وتعقيد العمليات التي تُجرى عليها، مثل الفرز والبحث والترشيح filtering وغير ذلك، وتوجد عدة حزم لقواعد البيانات للعناية بإدارة الملفات، وكشف البيانات في شكل أكثر تجريدًا ويسهل التعديل عليه، بعضها عبارة عن مكتبات للشيفرات code libraries تبسط عمليات الملفات التي رأيناها من قبل مثل وحدتي <a href="https://docs.python.org/3/library/pickle.html#module-pickle" rel="external nofollow">pickle</a> و <a href="https://docs.python.org/3/library/shelve.html#module-shelve" rel="external nofollow">shelve</a> اللتين تأتيان مع بايثون، لكننا في هذا المقال سندرس حزمًا أكثر قوةً صممت للتعامل مع أحجام كبيرة من البيانات المعقدة، حيث سنشرح الحزمة SQLite، وهي حزمة مجانية مفتوحة المصدر وسهلة التثبيت والاستخدام، ومع هذا فهي قادرة على معالجة حاجات أغلب المبرمجين المبتدئين والمتوسطين أيضًا، ولا يحتاج المبرمج في الغالب إلى حزمة أقوى منها إلا إذا كان يتعامل مع مجموعات كبيرة للغاية من البيانات -ملايين السجلات مثلًا-، وحتى في تلك الحالة نستطيع نقل ما تعلمناه من <a href="https://academy.hsoub.com/devops/servers/databases/%d9%83%d9%8a%d9%81-%d9%88%d9%85%d8%aa%d9%89-%d9%86%d8%b3%d8%aa%d8%ae%d8%af%d9%85-sqlite-r111/" rel="">SQLite </a>إلى الحزمة الجديدة.
</p>

<p>
	يمكن تحميل <a href="http://www.sqlite.org/download.html" rel="external nofollow">حزمة SQLite من موقعها</a>، فاختر حزمة سطر الأوامر -أي الأدوات- المناسبة لمنصتك، وبعد التحميل اتبع إرشادات التثبيت الموجودة في الموقع لتثبيت الحزمة.
</p>

<p>
	توجد عدة بيئات تطوير لـ SQLite، غير أننا لا نحتاجها في هذه السلسلة.
</p>

<p>
	سندرس في هذا المقال ما يلي:
</p>

<ul>
	<li>
		مفهوم قواعد البيانات <a href="https://academy.hsoub.com/programming/sql/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D9%91%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-sql-r585/" rel="">وSQL</a>.
	</li>
	<li>
		إنشاء الجداول وإدخال البيانات.
	</li>
	<li>
		استخراج البيانات والتعديل عليها.
	</li>
	<li>
		ربط مجموعات البيانات بعضها ببعض.
	</li>
	<li>
		الوصول إلى SQL من بايثون.
	</li>
</ul>

<h2>
	مفاهيم قاعدة البيانات العلائقية
</h2>

<p>
	يمكن وصف <a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D8%A6%D9%82%D9%8A%D8%A9-rdm-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r522/" rel="">قواعد البيانات العلائقية relational databases</a> بأنها مجموعة من الجداول، حيث يمكن لخلية في جدول فيها أن تشير إلى صف في جدول آخر، وتسمى الأعمدة في تلك الجداول بالحقول fields، كما تسمى الصفوف بالسجلات records.
</p>

<p>
	سيبدو جدول بيانات الموظفين في إحدى الشركات كما يلي:
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th style="text-align:center">
				EmpID
			</th>
			<th style="text-align:center">
				Name
			</th>
			<th style="text-align:center">
				HireDate
			</th>
			<th style="text-align:center">
				Grade
			</th>
			<th style="text-align:center">
				ManagerID
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				1020304
			</td>
			<td style="text-align:center">
				Hasan Saleh
			</td>
			<td style="text-align:center">
				20030623
			</td>
			<td style="text-align:center">
				Foreman
			</td>
			<td style="text-align:center">
				1020311
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				1020305
			</td>
			<td style="text-align:center">
				Amin Akbar
			</td>
			<td style="text-align:center">
				20040302
			</td>
			<td style="text-align:center">
				Labourer
			</td>
			<td style="text-align:center">
				1020304
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				1020307
			</td>
			<td style="text-align:center">
				Ayat Othman
			</td>
			<td style="text-align:center">
				19991125
			</td>
			<td style="text-align:center">
				Labourer
			</td>
			<td style="text-align:center">
				1020304
			</td>
		</tr>
	</tbody>
</table>

<p>
	نلاحظ بعض المصطلحات هنا:
</p>

<ol>
	<li>
		لدينا حقل معرِّف <code>ID</code> فريد يعرف كل صف، ويُعرف باسم المفتاح الأساسي primary key، ويمكن أن يكون لدينا عدة مفاتيح أخرى، لكن سيكون لدينا حقل ID دومًا لتعريف سجل ما، وهذا مفيد إذا كان لموظفين اثنين نفس الاسم مثلًا.
	</li>
	<li>
		يمكن ربط صف بآخر بأن يحمل حقلٌ ما المفتاحَ الأساسي لصف آخر، فمثلًا يُحدَّد مدير الموظف بواسطة معرف المدير <code>ManagerID</code> الذي هو مرجع إلى حقل <code>EmpID</code> آخر، ويتضح بالنظر إلى البيانات التي لدينا أن لكل من <code>Amin</code> و<code>Ayat</code> المدير نفسه وهو <code>Hasan</code>، و Hasan هذا له مدير آخر لكننا لا نرى بياناته في هذا الجزء من الجدول.
	</li>
</ol>

<p>
	ويمكن إنشاء جدول آخر للرواتب <code>Salary</code> مثلًا، فلسنا مقيدين بربط البيانات داخل جدول واحد، ويُربط هذا بالدرجة <code>Grade</code> الخاصة بكل موظف، فنحصل عندها على جدول شبيه بما يلي:
</p>

<table>
	<thead>
		<tr>
			<th style="text-align:center">
				SalaryID
			</th>
			<th style="text-align:center">
				Grade
			</th>
			<th style="text-align:center">
				Amount
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				000010
			</td>
			<td style="text-align:center">
				Foreman
			</td>
			<td style="text-align:center">
				60000
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				000011
			</td>
			<td style="text-align:center">
				Labourer
			</td>
			<td style="text-align:center">
				35000
			</td>
		</tr>
	</tbody>
</table>

<p>
	نستطيع الآن أن نبحث عن درجة موظف ما مثل <code>Hasan</code>، وسنجد أن درجته هي كبير عمال <code>Foreman</code>، وإذا بحثنا في جدول <code>Salary</code> فسنجد أن راتب هذه الدرجة هو 60000$، وإمكانية ربط صفوف الجداول معًا في علاقات هي التي تعطي قواعد البيانات العلائقية اسمها.
</p>

<p>
	توجد قواعد بيانات أخرى مثل قواعد بيانات الشبكات network databases، وقواعد البيانات الهرمية hierarchical databases، وقواعد بيانات الملفات المسطحة flat-file databases، ولكن القواعد العلائقية هي أكثرها شهرةً، رغم أن الاتجاه السائد الآن في معالجة الأحجام الهائلة من البيانات هو <a href="https://academy.hsoub.com/devops/servers/databases/%d8%b4%d8%b1%d8%ad-%d8%a7%d9%84%d9%81%d8%b1%d9%88%d9%82%d8%a7%d8%aa-%d8%a8%d9%8a%d9%86-%d9%82%d9%88%d8%a7%d8%b9%d8%af-%d8%a8%d9%8a%d8%a7%d9%86%d8%a7%d8%aa-sql-%d9%88%d9%86%d8%b8%d9%8a%d8%b1%d8%a7%d8%aa%d9%87%d8%a7-nosql-r71/" rel="">NoSQL</a> -أي ليست SQL فقط "Not only SQL"-، وهي قواعد بيانات تبنى في الغالب على هياكل شبكية أو هرمية.
</p>

<p>
	يمكن إجراء استعلامات أعقد من تلك التي أجريناها، وسنرى كيفية ذلك فيما يلي، لكن يجب أن ننشئ قاعدة بيانات أولًا ونضع فيها بعض البيانات.
</p>

<h2>
	لغة الاستعلامات الهيكلية SQL
</h2>

<p>
	<a href="https://www.google.com/url?q=https://academy.hsoub.com/programming/sql/%25D8%25A7%25D9%2584%25D9%2585%25D8%25B1%25D8%25AC%25D8%25B9-%25D8%25A7%25D9%2584%25D9%2585%25D8%25AA%25D9%2582%25D8%25AF%25D9%2585-%25D8%25A5%25D9%2584%25D9%2589-%25D9%2584%25D8%25BA%25D8%25A9-sql-r961&amp;sa=D&amp;source=editors&amp;ust=1632496008722000&amp;usg=AOvVaw2DN1tpCDjarp6ASVNU64WO" rel="external nofollow">لغة الاستعلامات الهيكلية أو Structured Query Language - SQL</a> هي أداة قياسية تُستخدم لتعديل قواعد البيانات العلائقية، ويسمى التعبير فيها عادةً استعلامًا query حتى لو لم يجلب أي بيانات، وتتكون SQL من جزأين هما: لغة تعريف البيانات Data Definition Language واختصارًا DDL، وهي مجموعة من الأوامر التي تُستخدم لإنشاء وتعديل هيكل قاعدة البيانات نفسها، وتكون عادةً خاصةً لكل قاعدة بيانات، ويوفر كل مزود قواعد بيانات صيغةً مختلفةً قليلًا لمجموعة أوامر SQL الخاصة بتعريف البيانات، أما الجزء الآخر فهو لغة تعديل البيانات Data Manipulation Language، واختصارًا DML، وهي قياسية أكثر بين قواعد البيانات، وتُستخدم لتعديل محتويات البيانات، وهي التي سنستخدمها غالبًا في التعامل مع قواعد البيانات، لذا سنتعلم بعض أوامر DDL التي تكفينا لإنشاء قاعدة بياناتنا باستخدام التعليمة <code>CREATE</code>، وتدمير جداولها باستخدام التعليمة <code>DROP</code>، ثم ننتقل بعدها إلى ملء الجداول بالبيانات، ثم نجلب تلك البيانات بطرق مختلفة باستخدام أوامر <a href="https://academy.hsoub.com/programming/sql/%D9%84%D8%BA%D8%A9-%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-dml-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-sql-r1369/" rel="">DML</a> مثل <code>INSERT</code> و<code>SELECT</code> و<code>UPDATE</code> و<code>DELETE</code> وغيرها.
</p>

<p>
	ربما تجدر الإشارة إلى مزية أخرى في <a href="https://academy.hsoub.com/programming/sql/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-sql-r844/" rel="">SQL</a>، وهي أنها ليست حساسةً لحالة الأحرف، على عكس بايثون وجافاسكربت، لذا يمكننا استخدام <code>CREATE</code> أو <code>create</code> أو <code>Create</code> أو حتى <code>CrEaTe</code>، فلن يهتم مفسر SQL بهذا، ومع هذا يتبع مبرمجو SQL نسقًا بحيث تكون كلمات SQL المفتاحية بأحرف كبيرة، بينما تكون المتغيرات وأسماء الجداول والحقول بأحرف صغيرة، وسنتبع هذا النسق في الشرح، لكننا ذكرنا الملاحظة أعلاه لننبه إلى أن SQL لا تهتم لحالة الأحرف.
</p>

<p>
	ومن الأمور التي تجعل <a href="https://wiki.hsoub.com/SQL" rel="external">SQL</a> مختلفةً عن اللغات الأخرى أنها مصممة للتعبير عن الخرج المطلوب بدلًا من إخبار الحاسوب بكيفية تنفيذه، أي أننا نخبر المفسر بما نريده فقط، وليس بالكيفية التي نريد تنفيذه بها، ونترك آلية التنفيذ للمفسر، ويستطيع المبرمجون الخبراء في قواعد البيانات أو مدراء النظم adminstrators أن يغيروا سلوك المفسر في تنفيذ المهام من خلال تعريف خطة التنفيذ أو تعديلها، غير أن هذا مستوىً متقدم خارج نطاق شرحنا.
</p>

<h2>
	إنشاء الجداول
</h2>

<p>
	نستخدم الأمر <code>CREATE</code> لإنشاء جدول في SQL، وهو أمر سهل ويأخذ الصورة التالية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_22" style=""><span class="pln">CREATE TABLE tablename </span><span class="pun">(</span><span class="pln">fieldName</span><span class="pun">,</span><span class="pln"> fieldName</span><span class="pun">,....);</span></pre>

<p>
	نلاحظ أن تعليمات SQL تنتهي بفاصلة منقوطة <code>;</code>، وهي لا تهتم بمستويات الإزاحة أو المسافات البيضاء، لكننا سنرى اتباع اصطلاح بعينه -مع أنه ليس لازمًا، ولا تهتم SQL له إطلاقًا- ولا نستخدمه إلا لاتساق سير العمل.
</p>

<p>
	لنجرب الآن إنشاء جداول الموظفين والرواتب في SQLite، حيث سيكون أول ما علينا فعله هو بدء المفسر عن طريق استدعائه مع وسيط هو اسم الملف، فإذا كانت قاعدة البيانات موجودةً فسيفتح الملف، أما إذا لم تكن موجودةً فسينشئها، وعليه فمن أجل إنشاء <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة بيانات</a> الموظفين نبدأ SQLite كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_24" style=""><span class="pln">E</span><span class="pun">:</span><span class="pln">\PROJECTS\SQL</span><span class="pun">&gt;</span><span class="pln"> sqlite3 employee</span><span class="pun">.</span><span class="pln">db</span></pre>

<p>
	سينشئ هذا قاعدة بيانات فارغةً اسمها <code>employee.db</code>، ويتركنا عند محث <code>sqlite&gt;‎</code> لنكتب أوامر SQL، ثم ننشئ بعض الجداول كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_28" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> CREATE TABLE </span><span class="typ">Employee</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="typ">EmpID</span><span class="pun">,</span><span class="typ">Name</span><span class="pun">,</span><span class="typ">HireDate</span><span class="pun">,</span><span class="typ">Grade</span><span class="pun">,</span><span class="typ">ManagerID</span><span class="pun">);</span><span class="pln">
sqlite</span><span class="pun">&gt;</span><span class="pln"> CREATE TABLE </span><span class="typ">Salary</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="typ">SalaryID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="typ">Amount</span><span class="pun">);</span><span class="pln">
sqlite</span><span class="pun">&gt;.</span><span class="pln">tables
</span><span class="typ">Employee</span><span class="pln">    </span><span class="typ">Salary</span><span class="pln">
sqlite</span><span class="pun">&gt;</span></pre>

<p>
	لاحظ أننا نقلنا قائمة الحقول إلى سطر منفصل لتسهيل رؤيتها، وتُرتَّب الحقول هنا بالاسم، وليس لها أي معلومات تعرِّفها -مثل نوع البيانات- وهذا في SQLite وحدها، إذ تطلب أغلب قواعد البيانات الأخرى تحديد النوع مع الاسم، ويمكن تحديد النوع في SQLite، كما سنرى بعد قليل.
</p>

<p>
	ونلاحظ أيضًا أننا تحققنا من عمل تعليمات <code>CREATE</code> باستخدام الأمر <code>‎.tables</code> لسرد جميع الجداول في قاعدة البيانات، وتحتوي SQLite على العديد من هذه الأوامر المنقوطة، والتي نستخدمها لجلب معلومات عن قاعدة البيانات، وللحصول على قائمة بتلك الأوامر يُستخدم الأمر <code>‎.help</code>.
</p>

<p>
	يمكننا تحديد قيود على القيم، بالإضافة إلى التصريح عن أنواع البيانات في كل عمود، فمثلًا <code>NOT NULL</code> تعني أن القيمة إلزامية ويجب ملؤها، ونجعل عادةً حقل المفتاح الأساسي غير خالٍ <code>NOT NULL</code> وفريدًا <code>UNIQUE</code>، كما نستطيع تحديد الحقل الذي سيكون المفتاح الأساسي <code>PRIMARY KEY</code>.
</p>

<p>
	سنترك تعريف الجدول الأساسي كما هو، وننتقل إلى التعديل في البيانات نفسها.
</p>

<h2>
	إدخال البيانات
</h2>

<p>
	أول ما نفعله بعد إنشاء الجداول هو ملؤها بالبيانات، وذلك باستخدام تعليمة <code>INSERT</code> في SQL، والتي لها هيكل أساسي بسيط هو:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_30" style=""><span class="pln">INSERT INTO tablename </span><span class="pun">(</span><span class="pln"> column1</span><span class="pun">,</span><span class="pln"> column2</span><span class="pun">...</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="pln"> value1</span><span class="pun">,</span><span class="pln"> value2</span><span class="pun">...</span><span class="pln"> </span><span class="pun">);</span></pre>

<p>
	كما توجد لها صيغة أخرى تستخدم استعلامًا لاختيار البيانات من مكان آخر في قاعدة البيانات، لكن هذا مستوىً متقدم ننصح بالقراءة عنه في <a href="http://www.sqlite.org/lang_insert.html" rel="external nofollow">دليل SQLite</a>.
</p>

<p>
	يمكننا أن ندخِل بعض الصفوف في جدول موظفينا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_32" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> INSERT INTO </span><span class="typ">Employee</span><span class="pln"> </span><span class="pun">(</span><span class="typ">EmpID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">HireDate</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ManagerID</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'1020304'</span><span class="pun">,</span><span class="str">'Hasan Saleh'</span><span class="pun">,</span><span class="str">'20030623'</span><span class="pun">,</span><span class="str">'Foreman'</span><span class="pun">,</span><span class="str">'1020311'</span><span class="pun">);</span><span class="pln">
sqlite</span><span class="pun">&gt;</span><span class="pln"> INSERT INTO </span><span class="typ">Employee</span><span class="pln"> </span><span class="pun">(</span><span class="typ">EmpID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">HireDate</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ManagerID</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'1020305'</span><span class="pun">,</span><span class="str">'Amin Akbar'</span><span class="pun">,</span><span class="str">'20040302'</span><span class="pun">,</span><span class="str">'Labourer'</span><span class="pun">,</span><span class="str">'1020304'</span><span class="pun">);</span><span class="pln">
sqlite</span><span class="pun">&gt;</span><span class="pln"> INSERT INTO </span><span class="typ">Employee</span><span class="pln"> </span><span class="pun">(</span><span class="typ">EmpID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">HireDate</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ManagerID</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'1020307'</span><span class="pun">,</span><span class="str">'Ayat Othman'</span><span class="pun">,</span><span class="str">'19991125'</span><span class="pun">,</span><span class="str">'Labourer'</span><span class="pun">,</span><span class="str">'1020304'</span><span class="pun">);</span></pre>

<p>
	وكذلك في جدول الرواتب:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_34" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> INSERT INTO </span><span class="typ">Salary</span><span class="pln"> </span><span class="pun">(</span><span class="typ">SalaryID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="typ">Amount</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> VALUES</span><span class="pun">(</span><span class="str">'000010'</span><span class="pun">,</span><span class="str">'Foreman'</span><span class="pun">,</span><span class="str">'60000'</span><span class="pun">);</span><span class="pln">
sqlite</span><span class="pun">&gt;</span><span class="pln"> INSERT INTO </span><span class="typ">Salary</span><span class="pln"> </span><span class="pun">(</span><span class="typ">SalaryID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="typ">Amount</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> VALUES</span><span class="pun">(</span><span class="str">'000011'</span><span class="pun">,</span><span class="str">'Labourer'</span><span class="pun">,</span><span class="str">'35000'</span><span class="pun">);</span></pre>

<p>
	وبهذا نكون قد انتهينا من إنشاء جدولين وملئهما بالبيانات الموافقة للقيم الموصوفة في المقدمة أعلاه، وسننتقل الآن إلى إجراء بعض التجارب على البيانات.
</p>

<h2>
	استخراج البيانات
</h2>

<p>
	تُستخرج البيانات من قاعدة البيانات باستخدام الأمر <code>SELECT</code> في SQL، والذي هو لب SQLite، وهو أعقد الأوامر هيكلًا، لذا سنبدأ بأبسط صورة ثم نضيف مزايا جديدةً أثناء العمل.
</p>

<p>
	ستبدو أبسط صورة ممكنة لتعليمة <code>SELECT</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_36" style=""><span class="pln">SELECT column1</span><span class="pun">,</span><span class="pln"> column2</span><span class="pun">...</span><span class="pln"> FROM table1</span><span class="pun">,</span><span class="pln">table2</span><span class="pun">...;</span></pre>

<p>
	فلاختيار أسماء جميع العاملين نستخدم:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_38" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT </span><span class="typ">Name</span><span class="pln"> FROM </span><span class="typ">Employee</span><span class="pun">;</span></pre>

<p>
	حيث سنحصل على قائمة بجميع الأسماء في جدول الموظفين، وهي ثلاثة أسماء في حالتنا، لكن إذا كان لدينا قاعدة بيانات كبيرة فسنحصل على معلومات أكثر مما نريد، وسنحتاج إلى تحسين بحثنا بطريقة ما للتحكم في الخرج، وتسمح لنا SQL بفعل ذلك بإضافة الشرط <code>WHERE</code> إلى تعليمة <code>SELECT</code>، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_40" style=""><span class="pln">SELECT col1</span><span class="pun">,</span><span class="pln">col2</span><span class="pun">...</span><span class="pln"> FROM table1</span><span class="pun">,</span><span class="pln">table2</span><span class="pun">...</span><span class="pln"> WHERE condition</span><span class="pun">;</span></pre>

<p>
	حيث الشرط <code>condition</code> هو تعبير بولياني معقد وعشوائي، ويمكن أن يتضمن تعليمات <code>SELECT</code> متشعبةً داخله، لنستخدم الشرط <code>WHERE</code> لتحسين بحث الأسماء، حيث نريد البحث عن أسماء الموظفين العمال فقط، أي أصحاب الدرجة <code>labourer</code>.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_43" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT </span><span class="typ">Name</span><span class="pln"> 
   </span><span class="pun">...&gt;</span><span class="pln"> FROM </span><span class="typ">Employee</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE </span><span class="typ">Employee</span><span class="pun">.</span><span class="typ">Grade</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Labourer'</span><span class="pun">;</span></pre>

<p>
	سنحصل الآن على اسمين فقط، ونستطيع توسيع الشرط باستخدام معامِلات بوليانية مثل <code>AND</code> و<code>OR</code> و<code>NOT</code> وغيرها، لاحظ أن استخدام الشرط <code>=</code> في حالة السلسلة النصية مهم، فلم يكن البحث عن <code>labourer</code> لينجح لولاه، وسنرى كيفية حل هذه المشكلة لاحقًا.
</p>

<p>
	كما نلاحظ أننا استخدمنا الصيغة النقطية dot notation في شرط <code>WHERE</code> لإبراز حقل <code>Grade</code>، ولم يكن ذلك ضروريًا في هذه الحالة لأننا نعمل مع جدول واحد، لكن عند وجود عدة جداول محددة فسنحتاج إلى توضيح الجدول الذي ينتمي إليه الحقل، فمثلًا لنغير استعلامنا ليبحث عن أسماء جميع الموظفين الذين يحصلون على راتب أكثر من 50000$، حيث سنحتاج إلى النظر في بيانات كلا الجدولين:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_45" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT </span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Amount</span><span class="pln"> FROM </span><span class="typ">Employee</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Salary</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE  </span><span class="typ">Employee</span><span class="pun">.</span><span class="typ">Grade</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Salary</span><span class="pun">.</span><span class="typ">Grade</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> AND    </span><span class="typ">Salary</span><span class="pun">.</span><span class="typ">Amount</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="str">'50000'</span><span class="pun">;</span></pre>

<p>
	نلاحظ استخدام المسافات البيضاء لترتيب شكل الاستعلام، وقد وضعنا شرط FROM هذه المرة في السطر الأول، وهذا أمر تنسيقي بحت يُستخدم لتحسين القراءة، فلغة SQLite لا تهتم بالفراغات.
</p>

<p>
	سنحصل هنا على اسم واحد كما توقعنا، وهو اسم كبير العمال foreman، لكن انتبه إلى أننا سنحصل على الراتب لأننا أضفنا <code>Amount</code> إلى قائمة الأعمدة المحددة، ولدينا شرط <code>WHERE</code> مكوَّن من جزأين مدمجين معًا باستخدام المعامِل البولياني <code>AND</code>، حيث يربط الجزء الأول الجدولين معًا عن طريق ضمان تساوي الحقول المشتركة، وهو ما يُعرف بالربط join في SQL، وقد يصبح أمر الربط معقدًا للغاية وفقًا لكل حالة، ولهذا يفضل القائمون على اعتماد المزايا الجديدة في <a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D9%82%D8%AF%D9%85-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-sql-r961/" rel="">SQL</a> صورةً أكثر صراحةً من الربط، وهي مشروحة بالتفصيل في <a href="https://www.guru99.com/sqlite-join.html" rel="external nofollow">موقع guru99</a>.
</p>

<p>
	علينا تحديد كلا الجدولين اللذين ستظهر النتيجة منهما، لأن الحقول التي نختارها تأتي من جدولين، ويكون ترتيب أسماء الحقول هو الترتيب الذي نحصل به على البيانات مرةً أخرى، لكن ترتيب الجداول نفسه لا يهم طالما أن الحقول تظهر في تلك الجداول.
</p>

<p>
	لقد حدَّدنا اثنين من أسماء الحقول الفريدة، فإذا أردنا عرض الدرجة الوظيفية <code>Grade</code> التي تظهر في كلا الجدولين، لكنا استخدمنا الصيغة النقطية لتحديد الجدول الذي نريده، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_49" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT </span><span class="typ">Employee</span><span class="pun">.</span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Amount</span><span class="pln"> 
   </span><span class="pun">...&gt;</span><span class="pln"> FROM </span><span class="typ">Employee</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Salary</span><span class="pln">
   etc</span><span class="pun">/...</span></pre>

<p>
	آخر ما نريد الحديث عنه من مزايا <code>SELECT</code> هي القدرة على تصنيف الخرج، رغم وجود عدة مزايا أخرى يمكن الرجوع إليها في <a href="http://www.sqlite.org/lang_select.html" rel="external nofollow">توثيق SQL</a>، فقواعد البيانات تحتفظ بالبيانات بالترتيب الذي يسهل به إيجادها أو بالترتيب الذي أُدخلت به، وفي كلا الحالتين لا يكون هو الترتيب الذي نريد عرض البيانات به، لذا نستخدم الشرط <code>ORDER BY</code> الخاص بتعليمة <code>SELECT</code> لحل هذه المشكلة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_52" style=""><span class="pln">SELECT columns FROM tables WHERE expression ORDER BY columns</span><span class="pun">;</span></pre>

<p>
	نلاحظ أن شرط <code>ORDER BY</code> الأخير قد يأخذ عدة أعمدة، وهذا يمكننا من الحصول على طلبات الفرز والتصنيف الأولية والثانوية، لنستخدم ذلك الآن للحصول على قائمة بأسماء الموظفين مصنفة وفق تاريخ التوظيف <code>HireDate</code>:
</p>

<pre class="ipsCode">sqlite&gt; SELECT Name FROM Employee
   ...&gt; ORDER BY HireDate;
</pre>

<p>
	لم يبقَ إلا ذكر أننا لم نستخدم شرط <code>WHERE</code> هنا، فإذا استخدمناه فسيأتي قبل شرط <code>order by</code>، لذا ورغم أن SQL لا تمانع إذا أهملنا الشرط إلا أنها تدقق كثيرًا في ترتيب الشروط داخل التعليمة.
</p>

<h2>
	تعديل البيانات
</h2>

<p>
	توجد طريقتان لتعديل البيانات في قواعد البيانات، إما بتغيير محتويات سجل واحد أو مجموعة سجلات، أو بحذف السجلات أو الجدول كاملًا، والحالة الأشهر هي تغيير محتويات سجل موجود بالفعل من خلال الأمر <code>UPDATE</code> في SQL، وأبسط صورة هي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_54" style=""><span class="pln">UPDATE tablename SET column </span><span class="pun">=</span><span class="pln"> value WHERE condition</span><span class="pun">;</span></pre>

<p>
	نستطيع تجربة ذلك في قاعدة البيانات التي لدينا بتغيير راتب كبير العمال foreman إلى 70000$:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_56" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> UPDATE </span><span class="typ">Salary</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> SET </span><span class="typ">Amount</span><span class="pln"> </span><span class="pun">=</span><span class="str">'70000'</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE </span><span class="typ">Grade</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Foreman'</span><span class="pun">;</span></pre>

<p>
	لاحظ أن جميع البيانات التي أدخلناها واخترناها كانت أنواعًا نصيةً string types، لأن SQLite تخزن بياناتها داخليًا في سلاسل نصية، لكنها تدعم عدة أنواع مختلفة من البيانات بما فيها الأعداد، لذا كان بالإمكان تحديد الراتب في صيغة رقمية لتسهيل العمليات الحسابية، وسنرى كيفية فعل ذلك فيما يلي.
</p>

<p>
	لكن المشكلة هنا أن SQL ستعدل كل الصفوف التي تطابق الشرط، فإذا كنا نريد تعديل صف واحد فقط فعلينا أن نتأكد أن الشرط <code>WHERE</code> يحدد حتمًا صفًا واحدًا فقط، إذ كثيرًا ما يغير المبرمجون المبتدئون دون قصد حقلًا في كل صف في الجدول أو فرع منه، لذا يجب الحذر عند استخدام أوامر التعديل لصعوبة إصلاح هذا الخطأ، ومن الأفضل التحقق من شرط <code>WHERE</code> بوضعه في تعليمة <code>SELECT</code> أولًا لمعرفة القيمة المعادة.
</p>

<p>
	أما الصورة الأخرى للتغيير الجذري الذي نستطيع تنفيذه على بياناتنا فهو حذف صف أو مجموعة صفوف، باستخدام الأمر <code>DELETE FROM</code>، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_58" style=""><span class="pln">DELETE FROM </span><span class="typ">Tablename</span><span class="pln"> WHERE condition</span></pre>

<p>
	فإذا أردنا حذف Ayat Othman من جدول الموظفين فسنكتب ما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_60" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> DELETE FROM </span><span class="typ">Employee</span><span class="pln"> WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Ayat Othman'</span><span class="pun">;</span></pre>

<p>
	فإذا طابق شرطنا أكثر من صف فستُحذف تلك الصفوف جميعها، لأن SQL تنفَّذ على جميع الصفوف التي تطابق الاستعلام، فهي ليست مثل استخدام البحث المتتابع sequential search لملف ما أو سلسلة نصية باستخدام تعبير نمطي.
</p>

<p>
	أما لحذف الجدول كله بمحتوياته فنستخدم الأمر <code>DROP</code>، ويجب توخي الحذر الشديد عند استخدام مثل هذه الأوامر التدميرية مثل <code>DELETE</code> و<code>DROP</code> لما لها من آثار قد لا يمكن إصلاحها.
</p>

<h2>
	ربط البيانات بين الجداول
</h2>

<p>
	تحدثنا عن ربط البيانات بين الجداول من قبل في القسم الخاص بتعليمة <code>SELECT</code>، أما الآن فننتقل إلى جزء مهم في نظرية قواعد البيانات.
</p>

<h3>
	قيود البيانات Data Constraints
</h3>

<p>
	تمثل الروابط بين الجداول علاقات Relations بين وحدات البيانات التي تعطي قاعدة البيانات العلائقية -مثل SQLite- اسمها، وتحتفظ قاعدة البيانات بالبيانات الخام عن الكيانات، بل تحتفظ بمعلومات عن العلاقات بينها أيضًا.
</p>

<p>
	تُخزَّن المعلومات عن العلاقات في صيغة قيود لقاعدة البيانات، والتي تتصرف مثل قواعد تحدد نوع البيانات الذي يمكن تخزينها، بالإضافة إلى مجموعة قيمها الصالحة، وتطبَّق تلك القيود عندما نعرِّف هيكل قواعد البيانات باستخدام تعليمة <code>CREATE</code>، عادةً نعبر عن قيود كل حقل على حدة، لذا نستطيع توسيع التعريف الأساسي في تعليمة <code>CREATE</code> حيث نعرِّف أعمدتنا من:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_62" style=""><span class="pln">CREATE TABLE </span><span class="typ">Tablename</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Column</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Column</span><span class="pun">,...);</span></pre>

<p>
	إلى:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_64" style=""><span class="pln">CREATE TABLE </span><span class="typ">Tablename</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
</span><span class="typ">ColumnName</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="typ">Constraint</span><span class="pun">,</span><span class="pln">
</span><span class="typ">ColumnName</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="typ">Constraint</span><span class="pun">,</span><span class="pln">
</span><span class="pun">...);</span></pre>

<p>
	حيث أغلب القيود:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_66" style=""><span class="pln">NOT NULL 
PRIMARY KEY </span><span class="pun">[</span><span class="pln">AUTOINCREMENT</span><span class="pun">]</span><span class="pln"> 
UNIQUE 
DEFAULT value </span></pre>

<p>
	يسهل فهم عمل القيد <code>NOT NULL</code> إذ يشير إلى أن القيمة يجب أن تكون موجودةً أي ليست <code>NULL</code>، حيث تشير القيمة <code>NULL</code> إلى قيمة غير محددة أو معرَّفة، وبالتالي فالعبارة <code>NOT NULL</code> تعني أنه يجب إعطاء قيمة لذلك الحقل، وإلا فسنحصل على خطأ ولن تُدخَل البيانات.
</p>

<p>
	أما المفتاح الرئيسي <code>PRIMARY KEY</code> فيخبر SQLite أن تستخدم هذا العمود مفتاحًا رئيسيًا لعمليات البحث، مما يُحسّن تنفيذ عمليات بحث أسرع.
</p>

<p>
	كما تعني <code>AUTOINCREMENT</code> أن قيمة النوع هي <code>INTEGER</code> ستُسنَد تلقائيًا عند كل عملية إدخال <code>INSERT</code>، وتتزايد القيمة بمقدار واحد، مما يوفر على المبرمج كثيرًا من حيث المحافطة على أعداد مستقلة، ولا تُستخدم الكلمة المفتاحية <code>AUTOINCREMENT</code> حقيقةً، وإنما تكون مضمنةً في تجميعة نوع/قيد بدمج <code>INTEGER PRIMARY KEY</code>، وهذه خاصية غير واضحة في توثيق SQLite إلى الحد الذي يجعلها من <a href="http://www.sqlite.org/faq.html" rel="external nofollow">أبرز الأسئلة في الأسئلة الشائعة حول SQLite</a>.
</p>

<p>
	وتدل <code>UNIQUE</code> على أن القيمة يجب أن تكون فريدةً في العمود، فإذا حاولنا إدخال قيمة موجودة مسبقًا في عمود له قيد <code>UNIQUE</code> فسنحصل على خطأ ولن يُدخَل الصف، ويُستخدم قيد <code>UNIQUE</code> عادةً لأعمدة المفاتيح الرئيسية غير العددية.
</p>

<p>
	يصاحب القيد <code>DEFAULT</code> قيمة دومًا، وهذه القيمة هي التي تخبرنا بما ستدخِله SQLite في ذلك الحقل إذا لم يقم المستخدم بذلك صراحةً، وهذا يفيد في أن الأعمدة التي لها القيد <code>DEFAULT</code> لا تكون <code>NULL</code> إلا نادرًا، لأن علينا ضبط القيمة <code>NULL</code> بصراحة إذا أردنا إنشاءها، ونستطيع رؤية مثال سريع على استخدام <code>DEFAULT</code> هنا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_68" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> CREATE TABLE test
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id </span><span class="typ">Integer</span><span class="pln"> PRIMARY KEY</span><span class="pun">,</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">Value</span><span class="pln"> </span><span class="typ">Integer</span><span class="pln"> DEFAULT </span><span class="lit">42</span><span class="pun">);</span><span class="pln">
sqlite</span><span class="pun">&gt;</span><span class="pln"> INSERT INTO test </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Value</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'Alan'</span><span class="pun">,</span><span class="lit">24</span><span class="pun">);</span><span class="pln">
sqlite</span><span class="pun">&gt;</span><span class="pln"> INSERT INTO test </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'Heather'</span><span class="pun">);</span><span class="pln">
sqlite</span><span class="pun">&gt;</span><span class="pln"> INSERT INTO test </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">,</span><span class="typ">Value</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'Linda'</span><span class="pun">,</span><span class="pln"> NULL</span><span class="pun">);</span><span class="pln">
sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT </span><span class="pun">*</span><span class="pln"> FROM test</span><span class="pun">;</span><span class="pln">
</span><span class="lit">1</span><span class="pun">|</span><span class="typ">Alan</span><span class="pun">|</span><span class="lit">24</span><span class="pln">
</span><span class="lit">2</span><span class="pun">|</span><span class="typ">Heather</span><span class="pun">|</span><span class="lit">42</span><span class="pln">
</span><span class="lit">3</span><span class="pun">|</span><span class="typ">Linda</span><span class="pun">|</span><span class="pln">
sqlite</span><span class="pun">&gt;</span></pre>

<p>
	نلاحظ هنا كيف تعينت القيمة الافتراضية لحقل value الموافقة للاسم المدخَل <code>Heather</code>، وأن قيمة value للمدخل Linda غير موجودة أو NULL، وهذا اختلاف جوهري بين <code>NOT NULL</code> و<code>DEFAULT</code>، فالأول لن يسمح بقيم <code>NULL</code> افتراضيًا أو صراحةً، والقيد <code>DEFAULT</code> يمنع <code>NULL</code> غير المحددة، لكنه يسمح في نفس الوقت بالإنشاء المتعمد لها.
</p>

<p>
	لقد استخدمنا محرف النجمة <code>*</code> مكان قائمة الحقل في آخر تعليمة <code>SELECT</code>، وهذه طريقة بسيطة لجلب جميع الحقول في الجدول، وهي ممتازة لمثل هذه التجارب، لكن يجب ألا تُستخدم في البرامج العملية لأن أي تغيير في هيكل البيانات سيتسبب في تغيير النتائج أو تعطيل أي شيفرة تعتمد على عدد أو ترتيب الحقول التي طُلبت.
</p>

<p>
	توجد قيود يمكن تطبيقها على الجدول نفسه، لكننا لن نناقشها في هذه السلسلة.
</p>

<p>
	أما النوع الآخر من القيود الذي نستطيع تطبيقه كما ذكرنا من قبل فهو تحديد نوع العمود، وهو يشبه مفهوم الأنواع في لغة البرمجة، ومجموعة الأنواع الصالحة في SQLite هي ما يلي:
</p>

<ul>
	<li>
		TEXT.
	</li>
	<li>
		INTEGER.
	</li>
	<li>
		REAL.
	</li>
	<li>
		NUMERIC.
	</li>
	<li>
		BLOB.
	</li>
	<li>
		NULL.
	</li>
</ul>

<p>
	يجب أن تكون هذه الأنواع مفهومةً وواضحةً، باستثناء <code>NUMERIC</code> و<code>BLOB</code>، فالأول يسمح بتخزين أعداد الفاصلة العائمة floating-point numbers والأعداد الصحيحة، أما <code>BLOB</code> فيُستخدم لتخزين البيانات الثنائية، مثل الصور أو المستندات غير النصية، فهو أفضل في تخزين مثل تلك العناصر في ملفات منفصلة مع وجود مرجع reference فقط يشير إليها في قاعدة البيانات.
</p>

<p>
	أما <code><a href="https://wiki.hsoub.com/SQL#.D8.A7.D9.84.D9.82.D9.8A.D9.85.D8.A9_NULL" rel="external">NULL</a></code> فهو ليس نوعًا حقيقيًا، وإنما يشير إلى أننا لا نحتاج إلى تحديد نوع مطلقًا، فأغلب قواعد البيانات تأتي بمجموعة واسعة من الأنواع بما فيها النوع <code>DATE</code>، لكن SQLite لديها أسلوب غير تقليدي في الأنواع التي تجعل مثل هذه التفاصيل غير مهمة.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		أنشئ معيار SQL بواسطة لجنة شُكلت من جميع الجهات المزودة لقواعد البيانات، لذا فإن قائمة الأنواع تشمل جميع الأنواع المختلفة التي يسمح بها هؤلاء المزودون، والتي كانت موجودةً قبل وضع الأنواع القياسية، وتدعم SQLite العديد من تلك الأنواع على مستوى الصياغة syntactical، لكنها في الممارسة العملية تُسمى بأسلوب بديل alias لأفضل نوع مكافئ محلي، لذا فإن النوع <code>VARCHAR</code> في قاعدة Oracle مثلًا هو اسم بديل للنوع <code>TEXT</code> الخاص بـ SQLite، والفكرة هنا هي القدرة على استيراد سكربتات SQL إلى SQLite بأقل قدر ممكن من التغيير.
	</p>
</blockquote>

<p>
	تطبق أغلب قواعد البيانات الأنواع المحددة بصرامة، لكن SQLite تتبع نهجًا أكثر ديناميكيةً ومرونةً، حيث يكون النوع المحدَّد أشبه بالتلميح أو الإرشاد hint، ويمكن تخزين أي نوع من البيانات في الجدول، وعند تحميل بيانات من نوع مختلف إلى الحقل فإن SQLite ستستخدم النوع المصرَّح عنه لتحاول تحويل البيانات إليه، فإن لم تستطع فستخزنها في صورتها الأصلية، فإذا صُرِّح عن حقل على أنه عددي <code>INTEGER</code> ثم مُررت القيمة النصية '123'، فستحول SQLite السلسلة النصية '123' إلى العدد 123، لكن إذا كانت القيمة النصية <code>TEXT</code> هي 'Amindy' فلن ينجح تحويلها إلى عدد، وستخزنها SQLite في صورتها كما هي في الحقل، وقد يسبب هذا سلوكًا غريبًا إذا لم يكن المبرمج على علم بهذا العيب، أما بقية قواعد البيانات فتعدّ التصريح عن الأنواع قيدًا صارمًا، وتفشل عند تمرير قيمة غير مسموح بها.
</p>

<h3>
	نمذجة العلاقات مع القيود
</h3>

<p>
	لنر الآن كيف تساعدنا هذه القيود في صنع نماذج للبيانات والعلاقات، من خلال العودة إلى قاعدة البيانات البسيطة ذات الجدولين التي بدأنا المقال بها:
</p>

<ul>
	<li>
		الجدول 1:
	</li>
</ul>

<table>
	<thead>
		<tr>
			<th style="text-align:center">
				EmpID
			</th>
			<th style="text-align:center">
				Name
			</th>
			<th style="text-align:center">
				HireDate
			</th>
			<th style="text-align:center">
				Grade
			</th>
			<th style="text-align:center">
				ManagerID
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				1020304
			</td>
			<td style="text-align:center">
				Hasan Saleh
			</td>
			<td style="text-align:center">
				20030623
			</td>
			<td style="text-align:center">
				Foreman
			</td>
			<td style="text-align:center">
				1020311
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				1020305
			</td>
			<td style="text-align:center">
				Amin Akbar
			</td>
			<td style="text-align:center">
				20040302
			</td>
			<td style="text-align:center">
				Labourer
			</td>
			<td style="text-align:center">
				1020304
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				1020307
			</td>
			<td style="text-align:center">
				Ayat Othman
			</td>
			<td style="text-align:center">
				19991125
			</td>
			<td style="text-align:center">
				Labourer
			</td>
			<td style="text-align:center">
				1020304
			</td>
		</tr>
	</tbody>
</table>

<ul>
	<li>
		الجدول 2:
	</li>
</ul>

<table>
	<thead>
		<tr>
			<th style="text-align:center">
				SalaryID
			</th>
			<th style="text-align:center">
				Grade
			</th>
			<th style="text-align:center">
				Amount
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				000010
			</td>
			<td style="text-align:center">
				Foreman
			</td>
			<td style="text-align:center">
				60000
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				000011
			</td>
			<td style="text-align:center">
				Labourer
			</td>
			<td style="text-align:center">
				35000
			</td>
		</tr>
	</tbody>
</table>

<p>
	ينبغي أن يكون نوع قيمة المعرِّف <code>ID</code> عددًا صحيحًا، أي <code>INTEGER</code>، ويحمل القيد <code>PRIMARY KEY</code>، أما العمود الآخر فيجب أن يكون <code>NOT NULL</code>، باستثناء <code>ManagerID</code> الذي يجب أن يكون عددًا صحيحًا.
</p>

<p>
	ونرى هنا في جدول الرواتب <code>Salary</code> أن معرِّف الراتب <code>SalaryID</code> يجب أن يكون عددًا صحيحًا <code>INTEGER</code> مع قيد <code>PRIMARY KEY</code>، كما يجب أن يكون عمود مقدار الراتب <code>Amount</code> عددًا صحيحًا، وسنطبق القيمة الافتراضية <code>DEFAULT</code> التي مقدارها 10000، وأخيرًا يجب أن يكون العمود <code>Grade</code> مقيدًا بقيد التفرد <code>Unique</code> بما أننا لا نريد أكثر من راتب واحد لكل درجة وظيفية، رغم أن هذه الفكرة غير عملية، لأن الراتب يتغير بعوامل عدة، مثل مدة العمل والدرجة، لكننا سنتجاهل هذا التفصيل الآن لتبسيط الشرح، فلو كان هذا الجدول في حالة حقيقية لسميناه جدول الدرجات وليس الرواتب.
</p>

<p>
	ستبدو SQL المعدلة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_71" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> CREATE TABLE </span><span class="typ">Employee</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">EmpID</span><span class="pln"> INTEGER pRIMARY kEY</span><span class="pun">,</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">HireDate</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">Grade</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">ManagerID</span><span class="pln"> INTEGER
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="pun">);</span><span class="pln">

sqlite</span><span class="pun">&gt;</span><span class="pln"> CREATE TABLE </span><span class="typ">Salary</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">SalaryID</span><span class="pln"> INTEGER PRIMARY KEY</span><span class="pun">,</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">Grade</span><span class="pln">  UNIQUE</span><span class="pun">,</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="typ">Amount</span><span class="pln"> INTEGER DEFAULT </span><span class="lit">10000</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="pun">);</span></pre>

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

<p>
	الأمر الذي تجب الإشارة إليه هنا هو أن تعليمات <code>INSERT</code> التي استخدمناها من قبل لم تعد مناسبةً، فقد أدخلنا قيمنا الخاصة من قبل لحقول ID، أما الآن فهي تُملأ تلقائيًا، فينبغي أن نهملها من البيانات المدرجة، غير أن هذا يفتح الباب لصعوبة جديدة، فكيف نملأ حقل معرِّف المدير <code>managerID</code> إذا كنا لا نعرف المعرف التوظيفي <code>EmpID</code> له؟
</p>

<p>
	والإجابة هي أننا نستخدم تعليمة SELECT متشعبة، وقد رأينا أن ننفذ هذا على مرحلتين باستخدام حقول <code>NULL</code> أولًا، ثم استخدام تعليمة <code>update</code> بعد إنشاء جميع الصفوف، ولتجنب تكرار الكتابة قد وضعنا جميع الأوامر في بضعة ملفات، سميناها <code>employee.sql</code> لأوامر إنشاء الجداول، و<code>employee.dat</code> لتعليمات الإدراج، وهذا يشبه إنشاء ملف سكربت بايثون ذي الامتداد <code>‎.py</code> لتوفير كتابة كل الأوامر في محث <code>‎&gt;&gt;&gt;‎</code>.
</p>

<p>
	سيكون ملف <code>employee.sql</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_73" style=""><span class="pln">DROP TABLE IF EXISTS </span><span class="typ">Employee</span><span class="pun">;</span><span class="pln">
CREATE TABLE </span><span class="typ">Employee</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
</span><span class="typ">EmpID</span><span class="pln"> INTEGER PRIMARY KEY</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Name</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">HireDate</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Grade</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">ManagerID</span><span class="pln"> INTEGER
</span><span class="pun">);</span><span class="pln">

DROP TABLE IF EXISTS </span><span class="typ">Salary</span><span class="pun">;</span><span class="pln">
CREATE TABLE </span><span class="typ">Salary</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
</span><span class="typ">SalaryID</span><span class="pln"> INTEGER PRIMARY KEY</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Grade</span><span class="pln"> UNIQUE</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Amount</span><span class="pln"> INTEGER DEFAULT </span><span class="lit">10000</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	نلاحظ هنا أننا أسقطنا الجداول -أي حذفناها- قبل إنشائها، فأمر <code>DROP TABLE</code> الذي ذكرناه من قبل يحذف الجدول وأي بيانات موجودة فيه، وهذا يضمن أن قاعدة البيانات ستكون خاليةً نظيفةً قبل أن ننشئ جدولنا الجديد، كما أضفنا شرط <code>IF EXISTS</code> الذي يمنعنا من محاولة حذف جدول حذف سابقًا.
</p>

<p>
	أما ملف <code>employee.dat</code> فسيكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_75" style=""><span class="pln">INSERT INTO </span><span class="typ">Employee</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">HireDate</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ManagerID</span><span class="pun">)</span><span class="pln">
    VALUES </span><span class="pun">(</span><span class="str">'Hasan Saleh'</span><span class="pun">,</span><span class="str">'20030623'</span><span class="pun">,</span><span class="str">'Foreman'</span><span class="pun">,</span><span class="pln"> NULL</span><span class="pun">);</span><span class="pln">
INSERT INTO </span><span class="typ">Employee</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">HireDate</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ManagerID</span><span class="pun">)</span><span class="pln">
    VALUES </span><span class="pun">(</span><span class="str">'Amin Akbar'</span><span class="pun">,</span><span class="str">'20040302'</span><span class="pun">,</span><span class="str">'Labourer'</span><span class="pun">,</span><span class="pln">NULL</span><span class="pun">);</span><span class="pln">
INSERT INTO </span><span class="typ">Employee</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">HireDate</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ManagerID</span><span class="pun">)</span><span class="pln">
    VALUES </span><span class="pun">(</span><span class="str">'Ayat Othman'</span><span class="pun">,</span><span class="str">'19991125'</span><span class="pun">,</span><span class="str">'Labourer'</span><span class="pun">,</span><span class="pln">NULL</span><span class="pun">);</span><span class="pln">

UPDATE </span><span class="typ">Employee</span><span class="pln">
SET </span><span class="typ">ManagerID</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">SELECT </span><span class="typ">EmpID</span><span class="pln"> 
                 FROM </span><span class="typ">Employee</span><span class="pln"> 
                 WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hasan Saleh'</span><span class="pun">)</span><span class="pln">
WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Amin Akbar'</span><span class="pln"> OR 
      </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Ayat Othman'</span><span class="pun">;</span><span class="pln">

INSERT INTO </span><span class="typ">Salary</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Amount</span><span class="pun">)</span><span class="pln">
       VALUES</span><span class="pun">(</span><span class="str">'Foreman'</span><span class="pun">,</span><span class="str">'60000'</span><span class="pun">);</span><span class="pln">
INSERT INTO </span><span class="typ">Salary</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Amount</span><span class="pun">)</span><span class="pln">
       VALUES</span><span class="pun">(</span><span class="str">'Labourer'</span><span class="pun">,</span><span class="str">'35000'</span><span class="pun">);</span></pre>

<p>
	نلاحظ هنا استخدام تعليمة <code>SELECT</code> المضمنة في أمر <code>UPDATE</code>، وكذلك استخدامنا لأمر <code>UPDATE</code> واحد لتعديل صفَّي الموظف باستخدام شرط <code>OR</code> البولياني، ويمكن إضافة موظفين أكثر مع نفس المدير بسهولة بتوسيع شرط <code>OR</code>، وهذا مثال للمشاكل التي قد نواجهها عند ملء قاعدة بيانات للمرة الأولى، إذ سنحتاج إلى تخطيط ترتيب التعليمات بعناية لضمان توفير البيانات لكل صف يجب أن يحتوي على قيمة مرجعية إلى جدول آخر، وذلك من أجل الإشارة إليها، وهذا أشبه بالبدء من أوراق شجرة ما إلى جذعها، إذ يجب إنشاء وإدراج البيانات التي لا تحوي مراجع في البداية، ثم البيانات التي تشير مرجعيًا إلى تلك البيانات الأولى، وهكذا. فإذا أضفنا البيانات بعد الإنشاء الأولي فسنحتاج إلى استخدام استعلامات للتحقق من وجود البيانات التي نحتاج إليها، وإضافتها إن لم تكن موجودةً، وهنا تبرز أهمية لغة مثل بايثون.
</p>

<p>
	ثم نشغل هذه الملفات من محث sqlite كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_77" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">.</span><span class="pln">read employee</span><span class="pun">.</span><span class="pln">sql
sqlite</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">.</span><span class="pln">read employee</span><span class="pun">.</span><span class="pln">dat</span></pre>

<p>
	تأكد أولًا من حل أي مشاكل تتعلق بمسارات الملفات، إما بتشغيل Sqlite من نفس مجلد سكربتات SQL كما فعلنا هنا، أو بتوفير المسار الكامل إلى السكربت.
</p>

<p>
	والآن لنجرب استعلامًا للتحقق من عمل هذه الملفات كما يجب:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_79" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT </span><span class="typ">Name</span><span class="pln"> FROM </span><span class="typ">Employee</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE </span><span class="typ">Grade</span><span class="pln"> IN
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">SELECT </span><span class="typ">Grade</span><span class="pln"> FROM </span><span class="typ">Salary</span><span class="pln"> WHERE amount </span><span class="pun">&gt;</span><span class="lit">50000</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> </span><span class="pun">;</span><span class="pln">
</span><span class="typ">Hasan</span><span class="pln"> </span><span class="typ">Saleh</span></pre>

<p>
	يبدو أننا نجحنا هنا، إذ أن Hasan Saleh هو الموظف الوحيد الذي يتقاضى أكثر من 50000$، ونلاحظ أننا استخدمنا الشرط <code>IN</code> مع تعليمة <code>SELECT</code> مضمنة أخرى، وهذه صورة مختلفة عن استعلام مشابه أجريناه سابقًا باستخدام وصلة بين الجداول cross-table join، ورغم أن كلا التقنيتين ستعملان إلا أن طريقة الوصلة أسرع.
</p>

<h2>
	العلاقات التعددية بين الجداول
</h2>

<p>
	أحد السيناريوهات التي لم نتحدث عنها هو ربط جدولين معًا بعلاقات تعددية، أي يُربط صف في أحد الجدولين بعدة صفوف في الجدول الآخر، في نفس الوقت الذي يمكن ربط صف من الجدول الآخر بعدة صفوف من الجدول الأول، فمثلًا لنفرض أننا نكتب <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">قاعدة بيانات</a> لدعم دار نشر للكتب، حيث سيكون لدينا قائمة من المؤلفين وقائمة من الكتب، وسيكتب كل مؤلف كتابًا أو أكثر، وفي نفس الوقت قد يكون للكتاب الواحد عدة مؤلفين، فكيف نعبر عن هذه العلاقات في قاعدة بيانات؟
</p>

<p>
	الجواب هنا هو تمثيل العلاقة بين الكتب والمؤلفين في جدول مستقل بذاته، ويُدعى هذا الجدول بجدول التقاطع intersection table أو جدول الربط mapping table، وكل صف في ذلك الجدول يمثل علاقةً من النوع كتاب/مؤلف، فقد يكون لكل كتاب عدة علاقات كتاب/مؤلف، لكن لكل علاقة كتابًا واحدًا ومؤلفًا واحدًا، وبذلك نكون قد حولنا علاقة متعدد-متعدد إلى علاقتي واحد-متعدد، وبما أننا نعرف كيف نبني مثل هذه العلاقات باستخدام المعرِّفات، فلنر ذلك عمليًا:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_82" style=""><span class="pln">DROP TABLE IF EXISTS author</span><span class="pun">;</span><span class="pln">
CREATE TABLE author </span><span class="pun">(</span><span class="pln">
ID INTEGER PRIMARY KEY</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Name</span><span class="pln"> TEXT NOT NULL
</span><span class="pun">);</span><span class="pln">

DROP TABLE IF EXISTS book</span><span class="pun">;</span><span class="pln">
CREATE TABLE book </span><span class="pun">(</span><span class="pln">
ID INTEGER PRIMARY KEY</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Title</span><span class="pln"> TEXT NOT NULL
</span><span class="pun">);</span><span class="pln">

DROP TABLE IF EXISTS book_author</span><span class="pun">;</span><span class="pln">
CREATE TABLE book_author </span><span class="pun">(</span><span class="pln">
bookID INTEGER NOT NULL</span><span class="pun">,</span><span class="pln">
authorID INTEGER NOT NULL
</span><span class="pun">);</span><span class="pln">

INSERT INTO author </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'Jane Austin'</span><span class="pun">);</span><span class="pln">
INSERT INTO author </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'Grady Booch'</span><span class="pun">);</span><span class="pln">
INSERT INTO author </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'Ivar Jacobson'</span><span class="pun">);</span><span class="pln">
INSERT INTO author </span><span class="pun">(</span><span class="typ">Name</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'James Rumbaugh'</span><span class="pun">);</span><span class="pln">

INSERT INTO book </span><span class="pun">(</span><span class="typ">Title</span><span class="pun">)</span><span class="pln"> VALUES</span><span class="pun">(</span><span class="str">'Pride &amp; Prejudice'</span><span class="pun">);</span><span class="pln">
INSERT INTO book </span><span class="pun">(</span><span class="typ">Title</span><span class="pun">)</span><span class="pln"> VALUES</span><span class="pun">(</span><span class="str">'Emma'</span><span class="pun">);</span><span class="pln">
INSERT INTO book </span><span class="pun">(</span><span class="typ">Title</span><span class="pun">)</span><span class="pln"> VALUES</span><span class="pun">(</span><span class="str">'Sense &amp; Sensibility'</span><span class="pun">);</span><span class="pln">
INSERT INTO book </span><span class="pun">(</span><span class="typ">Title</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'Object Oriented Design with Applications'</span><span class="pun">);</span><span class="pln">
INSERT INTO book </span><span class="pun">(</span><span class="typ">Title</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="str">'The UML User Guide'</span><span class="pun">);</span><span class="pln">

INSERT INTO book_author </span><span class="pun">(</span><span class="typ">BookID</span><span class="pun">,</span><span class="typ">AuthorID</span><span class="pun">)</span><span class="pln"> values </span><span class="pun">(</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM book WHERE title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Pride &amp; Prejudice'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM author WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Jane Austin'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

INSERT INTO book_author </span><span class="pun">(</span><span class="typ">BookID</span><span class="pun">,</span><span class="typ">AuthorID</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM book WHERE title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Emma'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM author WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Jane Austin'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

INSERT INTO book_author </span><span class="pun">(</span><span class="typ">BookID</span><span class="pun">,</span><span class="typ">AuthorID</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM book WHERE title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Sense &amp; Sensibility'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM author WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Jane Austin'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

INSERT INTO book_author </span><span class="pun">(</span><span class="typ">BookID</span><span class="pun">,</span><span class="typ">AuthorID</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM book WHERE title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Object Oriented Design with Applications'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM author WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Grady Booch'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

INSERT INTO book_author </span><span class="pun">(</span><span class="typ">BookID</span><span class="pun">,</span><span class="typ">AuthorID</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM book WHERE title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'The UML User Guide'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM author WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Grady Booch'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

INSERT INTO book_author </span><span class="pun">(</span><span class="typ">BookID</span><span class="pun">,</span><span class="typ">AuthorID</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM book WHERE title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'The UML User Guide'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM author WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Ivar Jacobson'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

INSERT INTO book_author </span><span class="pun">(</span><span class="typ">BookID</span><span class="pun">,</span><span class="typ">AuthorID</span><span class="pun">)</span><span class="pln"> VALUES </span><span class="pun">(</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM book WHERE title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'The UML User Guide'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">(</span><span class="pln">SELECT ID FROM author WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'James Rumbaugh'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	يمكن أن نجرب الآن بعض الاستعلامات لنرى كيف ستعمل، فمثلًا لنبحث عما نشرته جين أوستن Jane Austin من كتب:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_84" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT title FROM book</span><span class="pun">,</span><span class="pln"> book_author
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE book_author</span><span class="pun">.</span><span class="pln">bookID </span><span class="pun">=</span><span class="pln"> book</span><span class="pun">.</span><span class="pln">ID
   </span><span class="pun">...&gt;</span><span class="pln"> AND book_author</span><span class="pun">.</span><span class="pln">authorID </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">SELECT ID FROM author 
   </span><span class="pun">...&gt;</span><span class="pln">                             WHERE name </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Jane Austin"</span><span class="pun">);</span></pre>

<p>
	لعل الأمر صار معقدًا قليلًا، لكن الفكرة ستتضح مع التكرار والتدريب، ولاحظ كيف نحتاج إلى إدراج كل من الجدولين المشار إليهما <code>book</code> و<code>book_author</code> في قائمة الجداول بعد <code>SELECT</code>، أما الجدول الثالث <code>author</code> فليس موجودًا هناك لأنه مدرج مقابل تعليمة <code>SELECT</code> الخاصة به.
</p>

<p>
	لنجرب الآن بالطريقة المعاكسة، أي لنر من ألف كتاب The UML User Guide:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_86" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT name FROM author</span><span class="pun">,</span><span class="pln"> book_author
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE book_author</span><span class="pun">.</span><span class="pln">authorID </span><span class="pun">=</span><span class="pln"> author</span><span class="pun">.</span><span class="pln">ID
   </span><span class="pun">...&gt;</span><span class="pln"> AND book_author</span><span class="pun">.</span><span class="pln">bookID </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">SELECT ID FROM book 
   </span><span class="pun">...&gt;</span><span class="pln">                           WHERE title </span><span class="pun">=</span><span class="pln"> </span><span class="str">"The UML User Guide"</span><span class="pun">);</span></pre>

<p>
	بالنظر إلى تلك الشيفرة سنجد تطابق هيكل الاستعلامين، فلم نغير إلا أسماء الحقل والجدول.
</p>

<p>
	سنعود الآن إلى مثال دليل جهات الاتصال الذي تركناه في مقال <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1334/" rel="">التعامل مع الملفات في البرمجة</a>، ويُفضل الرجوع لهذا المقال قبل متابعة القراءة لنرى كيف سنحوله من تخزين مبني على الملفات إلى قاعدة بيانات كاملة.
</p>

<h2>
	إعادة النظر في دليل جهات الاتصال
</h2>

<p>
	في دليل جهات الاتصال الذي كتبناه من قبل وبنيناه على الملفات، استخدمنا قاموسًا فيه اسم الشخص هو المفتاح، وعنوانه عنصر بيانات وحيد، ولا بأس بهذا إذا كنا نعرف الاسم الذي نريده، أو إذا أردنا تفاصيل العنوان كلها، لكن ماذا لو أردنا جميع الأسماء الموجودة في مدينة بعينها؟ أو كل من اسمه Hasan؟
</p>

<p>
	يمكننا كتابة شيفرة بايثون لكل استعلام، لكن مع زيادة عدد الاستعلامات الخاصة سيزيد الجهد المطلوب لكتابة تلك الشيفرات، وهنا يأتي دور قواعد البيانات حيث يمكننا فيها إنشاء استعلامات ديناميكيًا باستخدام <a href="https://academy.hsoub.com/programming/sql/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85-sql-%D8%A8%D8%A7%D9%84%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A9-r637/" rel="">SQL</a>، وسيبدو دليل جهات الاتصال قاعدة بيانات من جدول واحد، ويمكن تقسيم البيانات إلى عنوان وشخص، ثم ربطهما معًا، فقد يكون لدينا عدة أصدقاء يعيشون في نفس المنزل، لكننا سنلتزم بالتصميم الأصلي ونستخدم جدولًا بسيطًا، إلا أننا سنقسم البيانات إلى عدة حقول، حيث سنقسم الاسم إلى الاسم الأول والاسم الأخير، والعنوان إلى أجزائه المكونة له، بدلًا من أن يكون لدينا هيكل لاسم واحد وعنوان واحد، وعلى الرغم من كثرة الدراسات التي أجريت حول أفضل الطرق لتقسيم هذه البيانات إلا أننا لم نصل إلى إجابة محددة، لكنها جميعًا تتفق في أن حقل العنوان الواحد فكرة سيئة لأنها تفتقر للمرونة، وستكون حقول جدول قواعد البيانات والقيود التي نريد تطبيقها كما يلي:
</p>

<table>
	<thead>
		<tr>
			<th style="text-align:center">
				Field Name
			</th>
			<th style="text-align:center">
				Type
			</th>
			<th style="text-align:center">
				Constraint
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				First Name
			</td>
			<td style="text-align:center">
				String
			</td>
			<td style="text-align:center">
				Primary Key
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Last Name
			</td>
			<td style="text-align:center">
				String
			</td>
			<td style="text-align:center">
				Primary Key
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				House Number
			</td>
			<td style="text-align:center">
				String
			</td>
			<td style="text-align:center">
				NOT NULL
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Street
			</td>
			<td style="text-align:center">
				String
			</td>
			<td style="text-align:center">
				NOT NULL
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				District
			</td>
			<td style="text-align:center">
				String
			</td>
			<td style="text-align:center">
				 
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Town
			</td>
			<td style="text-align:center">
				String
			</td>
			<td style="text-align:center">
				NOT NULL
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Post Code
			</td>
			<td style="text-align:center">
				String
			</td>
			<td style="text-align:center">
				NOT NULL
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Phone Number
			</td>
			<td style="text-align:center">
				String
			</td>
			<td style="text-align:center">
				NOT NULL
			</td>
		</tr>
	</tbody>
</table>

<p>
	نلاحظ عدة أمور هنا:
</p>

<ol>
	<li>
		لدينا مفتاحان رئيسيان <code>primary keys</code> وهذا غير مسموح به، وسنتعامل معه بعد قليل.
	</li>
	<li>
		جميع البيانات من نوع <code>TEXT</code> رغم أن <code>House Number</code> قد يكون عددًا صحيحًا <code>INTEGER</code>، إلا أن أرقام المنازل تتضمن أحرفًا، لذا يجب استخدام <code>TEXT</code>.
	</li>
	<li>
		الحقل الاختياري الوحيد هو الحقل <code>district</code>.
	</li>
	<li>
		الرمز البريدي محدد الصيغة للغاية، لكنه يختلف وفقًا لكل دولة، وهذا يعني أن علينا أن نجعله من النوع <code>TEXT</code> ليناسب جميع الاحتمالات.
	</li>
	<li>
		رغم أن رقم الهاتف <code>Phone Number</code> قد يبدو مناسبًا لوضع قيد <code>UNIQUE</code> إلا أن هذا لن يسمح بوجود شخصين يتشاركان نفس رقم الهاتف، وهي حالة محتملة.
	</li>
</ol>

<p>
	بالعودة إلى النقطة الأولى -وجود مفتاحين رئيسيين- وهذا غير مسموح في SQL، لكن نستطيع جمع عمودين معًا في ما يسمى بالمفتاح المركب composite key، والذي يسمح بمعاملتهما مثل قيمة واحدة فيما يخص تعريف الصف، وعلى ذلك يمكن إضافة سطر في نهاية تعليمة <code>create table</code> ليجمع الاسم الأول <code>FirstName</code> و<code>LastName</code> في مفتاح رئيسي واحد، وسيبدو ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6187_90" style=""><span class="pln">CREATE TABLE address </span><span class="pun">(</span><span class="pln">
</span><span class="typ">FirstName</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">LastName</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="typ">PhoneNumber</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
PRIMARY KEY </span><span class="pun">(</span><span class="typ">FirstName</span><span class="pun">,</span><span class="typ">LastName</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	نلاحظ هنا السطر الأخير <code>PRIMARY KEY (FirstName,LastName)‎</code> الذي يحوي الأعمدة التي نريد استخدامها لتكون مفتاحًا مركبًا، وهو مثال على قيد قائم على الجدول table-based constraint، غير أن هذه الفكرة غير سديدة، فإذا كنا نعرف شخصين بنفس الاسم فلن نستطيع تخزينهما معًا، ولن نخزن إلا واحدًا فقط منهما، وسنتعامل مع هذا بتعريف حقل <code>integer primary key</code> لتعريف جهات اتصالاتنا تعريفًا فريدًا رغم أننا لن نستخدم ذلك في الاستعلامات إلا نادرًا.
</p>

<p>
	نعرف كيفية التصريح عن قيد <code>INTEGER PRIMARY KEY</code> حيث فعلنا ذلك في مثال الموظف، ونستطيع تحويل ذلك مباشرةً إلى سكربت إنشاء بيانات SQLite كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_92" style=""><span class="pun">--</span><span class="pln"> </span><span class="pun">احذف</span><span class="pln"> </span><span class="pun">الجداول</span><span class="pln"> </span><span class="pun">إذا</span><span class="pln"> </span><span class="pun">كانت</span><span class="pln"> </span><span class="pun">موجودة</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">قبل</span><span class="pln"> </span><span class="pun">وأعد</span><span class="pln"> </span><span class="pun">إنشاءها.</span><span class="pln">
</span><span class="pun">--</span><span class="pln"> </span><span class="pun">استخدم</span><span class="pln"> </span><span class="pun">القيود</span><span class="pln"> </span><span class="pun">لتحسين</span><span class="pln"> </span><span class="pun">كفاءة</span><span class="pln"> </span><span class="pun">البيانات.</span><span class="pln">
DROP TABLE IF EXISTS address</span><span class="pun">;</span><span class="pln">
CREATE TABLE address </span><span class="pun">(</span><span class="pln">
</span><span class="typ">ContactID</span><span class="pln"> INTEGER PRIMARY KEY</span><span class="pun">,</span><span class="pln">
</span><span class="typ">First</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Last</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">House</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Street</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">District</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Town</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">PostCode</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Phone</span><span class="pln"> NOT NULL
</span><span class="pun">);</span></pre>

<p>
	السطران الأولان في الشيفرة السابقة ما هما إلا تعليقات، فأي شيء متبوع بشرطتين <code>--</code> هنا يُعد تعليقًا في SQL، كما في حالة رمز <code>#</code> في <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r211/" rel="">بايثون</a>.
</p>

<p>
	نلاحظ أننا لم نعرّف النوع لأن <code>TEXT</code> هو النوع الافتراضي في SQLite، فإذا أردنا تحويل هذا المخطط أو تخطيط الجدول -أو نقله port بالاصطلاح الحاسوبي- إلى قاعدة بيانات أخرى فسيتوجب علينا إضافة بعض المعلومات.
</p>

<p>
	أما الخطوة التالية فهي تحميل بعض البيانات إلى الجدول لنبدأ تنفيذ الاستعلامات، وسنترك ذلك تدريبًا للقارئ -باستخدام رمز الإدراج أعلاه قالبًا-، لكن سنستخدم مجموعة البيانات التالية في الأمثلة أدناه:
</p>

<table>
	<thead>
		<tr>
			<th style="text-align:center">
				First
			</th>
			<th style="text-align:center">
				Last
			</th>
			<th style="text-align:center">
				House
			</th>
			<th style="text-align:center">
				Street
			</th>
			<th style="text-align:center">
				District
			</th>
			<th style="text-align:center">
				Town
			</th>
			<th style="text-align:center">
				PostCode
			</th>
			<th style="text-align:center">
				Phone
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				Mona
			</td>
			<td style="text-align:center">
				Akbar
			</td>
			<td style="text-align:center">
				42
			</td>
			<td style="text-align:center">
				Any Street
			</td>
			<td style="text-align:center">
				SomePlace
			</td>
			<td style="text-align:center">
				MyTown
			</td>
			<td style="text-align:center">
				ABC123
			</td>
			<td style="text-align:center">
				01234 567890
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Jamil
			</td>
			<td style="text-align:center">
				Masoud
			</td>
			<td style="text-align:center">
				17
			</td>
			<td style="text-align:center">
				Any Street
			</td>
			<td style="text-align:center">
				SomePlace
			</td>
			<td style="text-align:center">
				MyTown
			</td>
			<td style="text-align:center">
				ABC234
			</td>
			<td style="text-align:center">
				01234 543129
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Yousef
			</td>
			<td style="text-align:center">
				Mohammad
			</td>
			<td style="text-align:center">
				9
			</td>
			<td style="text-align:center">
				Crypt Drive
			</td>
			<td style="text-align:center">
				Hotspot
			</td>
			<td style="text-align:center">
				Metropolis
			</td>
			<td style="text-align:center">
				ABC345
			</td>
			<td style="text-align:center">
				01234 456459
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Yasein
			</td>
			<td style="text-align:center">
				Akbar
			</td>
			<td style="text-align:center">
				42
			</td>
			<td style="text-align:center">
				Any Street
			</td>
			<td style="text-align:center">
				SomePlace
			</td>
			<td style="text-align:center">
				MyTown
			</td>
			<td style="text-align:center">
				ABC123
			</td>
			<td style="text-align:center">
				01234 567890
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Yasein
			</td>
			<td style="text-align:center">
				Akbar
			</td>
			<td style="text-align:center">
				12A
			</td>
			<td style="text-align:center">
				Double Street
			</td>
			<td style="text-align:center">
				 
			</td>
			<td style="text-align:center">
				AnyTown
			</td>
			<td style="text-align:center">
				DEF174
			</td>
			<td style="text-align:center">
				01394 784310
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				Amal
			</td>
			<td style="text-align:center">
				Akbar
			</td>
			<td style="text-align:center">
				12A
			</td>
			<td style="text-align:center">
				Double Street
			</td>
			<td style="text-align:center">
				 
			</td>
			<td style="text-align:center">
				AnyTown
			</td>
			<td style="text-align:center">
				DEF174
			</td>
			<td style="text-align:center">
				01394 784310
			</td>
		</tr>
	</tbody>
</table>

<p>
	لدينا الآن بعض البيانات ونريد إجراء التجارب عليها، لنرى كيفية استخدام الإمكانيات الموجودة في SQL لاستخراج البيانات بطرق لم نكن لنحلم بها في مثال القاموس المبني على الملفات في بايثون.
</p>

<h3>
	من يعيش في هذا الشارع؟
</h3>

<p>
	هذا الاستعلام بسيط ومباشر نوعًا ما، لأننا قسمنا بيانات العنوان إلى حقول منفصلة، فلو لم نفعل ذلك لاحتجنا إلى كتابة شيفرة تحليل لاستخراج بيانات الشارع، وهذا أكثر تعقيدًا لا شك، وسيبدو استعلام SQL الذي نريده كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_95" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT </span><span class="typ">First</span><span class="pun">,</span><span class="typ">Last</span><span class="pln"> FROM </span><span class="typ">Address</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE </span><span class="typ">Street</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Any Street"</span><span class="pun">;</span></pre>

<h3>
	من يحمل اسم Akbar؟
</h3>

<p>
	هذا أيضًا تعبير <code>SELECT/WHERE</code> بسيط في SQL:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_97" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT </span><span class="typ">First</span><span class="pun">,</span><span class="typ">Last</span><span class="pln"> FROM </span><span class="typ">Address</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE </span><span class="typ">Last</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Akbar"</span><span class="pun">;</span></pre>

<h3>
	ما هو رقم هاتف Yasein؟
</h3>

<p>
	وهذا أيضًا استعلام بسيط إلا أننا سنحصل على عدة نتائج:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_99" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT </span><span class="typ">First</span><span class="pun">,</span><span class="typ">Last</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Phone</span><span class="pln"> FROM </span><span class="typ">Address</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE </span><span class="typ">First</span><span class="pln"> LIKE </span><span class="str">"Yas%"</span><span class="pun">;</span></pre>

<p>
	نلاحظ أننا استخدمنا <code>LIKE</code> في شرط <code>WHERE</code>، وهذا يستخدم أسلوب الموازنة الخاص بمحرف البدل wild card، ويتجاهل حالة الأحرف، لاحظ أن رمز محرف البدل في SQL هو <code>%</code> بدلًا من محرف <code>*</code> الشائع، ونتيجةً لهذا نحصل على مطابقة أكثر مرونةً من التساوي الذي يتطلب تطابقًا تامًا، ونلاحظ أننا لو استخدمنا <code>%Y</code> فقط في محرف البدل لحصلنا على <code>Yosef</code> في النتائج أيضًا.
</p>

<h3>
	ما هي الأسماء المتكررة؟
</h3>

<p>
	هذا استعلام أكثر تعقيدًا، وسنحتاج إلى اختيار مداخل الجدول التي تكررت أكثر من مرة، وهنا يبرز دور المفتاح <code>ContactID</code>:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_101" style=""><span class="pln">sqlite</span><span class="pun">&gt;</span><span class="pln"> SELECT DISTINCT A</span><span class="pun">.</span><span class="typ">First</span><span class="pun">,</span><span class="pln"> A</span><span class="pun">.</span><span class="typ">Last</span><span class="pln"> 
   </span><span class="pun">...&gt;</span><span class="pln"> FROM </span><span class="typ">Address</span><span class="pln"> AS A</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Address</span><span class="pln"> AS B
   </span><span class="pun">...&gt;</span><span class="pln"> WHERE A</span><span class="pun">.</span><span class="typ">First</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> B</span><span class="pun">.</span><span class="typ">First</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> AND A</span><span class="pun">.</span><span class="typ">Last</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> B</span><span class="pun">.</span><span class="typ">Last</span><span class="pln">
   </span><span class="pun">...&gt;</span><span class="pln"> AND NOT A</span><span class="pun">.</span><span class="typ">ContactID</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> B</span><span class="pun">.</span><span class="typ">ContactID</span><span class="pun">;</span></pre>

<p>
	نستخدم هنا بعض المزايا الجديدة، حيث نضيف <code>A</code> و<code>B</code> -وهما اسمان بديلان aliases- إلى الجداول في شرط <code>FROM</code>، كما نضيف أسماءً بديلةً للقيم الناتجة أيضًا لتقليل الكتابة، ونستخدم هذه الأسماء عند الإشارة إلى الحقول الناتجة باستخدام الصيغة النقطية المعتادة، يمكن استخدام الاسم البديل في أي استعلام، لكننا مجبرون على استخدامه هنا لأننا نستخدم نفس الجدول <code>Address</code> في المرتين -ومن ثم نضمه إلى نفسه-، لذا نحتاج إلى اسمين بديلين للتمييز بين النسختين في شرط <code>where</code>، كما نضيف الكلمة المفتاحية <code>DISTINCT</code> التي تحذف أي نتائج مكررة.
</p>

<p>
	وخلاصة الفقرات السابقة أن الاستعلام يبحث عن الصفوف التي لها نفس الاسم الأول والأخير، لكن لها معرِّف جهة اتصال <code>ContactID</code> مختلف، ثم يحذف الصفوف المتشابهة قبل عرض النتائج.
</p>

<p>
	لمحث SQLite التفاعلي نفس قوة محث بايثون من حيث القدرة على تطوير استعلامات معقدة مثل هذا، فقد نبدأ باستعلام بسيط ثم نزيد التعقيد لاحقًا، فمثلًا آخر جزء أضفناه إلى الاستعلام الأخير كان كلمة <code>DISTINCT</code>، على الرغم من أنها الكلمة الثانية فيه.
</p>

<h2>
	الوصول إلى SQL من بايثون
</h2>

<p>
	توفر SQLite واجهة برمجة تطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> تتكون من عدد من الدوال القياسية التي تسمح للمبرمجين بتنفيذ جميع العمليات الممكنة في محث SQL، وقد كُتبت <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel=""><abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> الخاصة بـ SQLite بلغة C، لكن توجد مغلِّفات لها للغات الأخرى، بما في ذلك بايثون.
</p>

<h3>
	الاتصالات Connections
</h3>

<p>
	أول ما نحتاج إليه للتعامل مع قواعد البيانات هو الاتصالات، ويأتي الاسم من حقيقة أن أغلب قواعد البيانات ما هي إلا برامج مخدمات server programs تعمل على حاسوب مركزي في مكان ما في الشبكة، ونريد أن نتصل بها، عادةً بواسطة التسجيل باسم مستخدم وكلمة مرور.
</p>

<p>
	ورغم أن SQLite ما هي إلا ملف موجود في نظام الملفات لدينا، إلا أن <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> تطلب الاتصال به -أي فتحه- للحفاظ على اتساق العمليات.
</p>

<h3>
	المؤشرات Cursors
</h3>

<p>
	من المهم عند استخدام قاعدة بيانات من داخل برنامج ما أن نعرف كيفية الوصول إلى الصفوف المتعددة التي يُحتمل أن تعيدها تعليمة <code>SELECT</code>، وذلك باستخدام ما يُعرف بمؤشرات SQL أي SQL cursors، والمؤشر هنا يشبه تسلسل بايثون في القدرة على الوصول فيه إلى صف واحد في كل مرة، وعليه فإن استخراج بياناتنا إلى مؤشر ثم استخدام حلقة تكرارية loop للوصول إليه يمكّننا من معالجة تجميعات كبيرة من البيانات.
</p>

<p>
	ولا يخزن المؤشر كل البيانات الناتجة، وإنما يخزن مرجعًا إليها يُحفظ في جدول مؤقت داخل قاعدة البيانات، وهذا أقل أهميةً بالنسبة لـ SQLite التي تكون في الغالب على نفس الحاسوب الذي عليه البرنامج، لكنه مهم عند التعامل مع قاعدة بيانات متصلة بشبكة العميل/الخادم.
</p>

<p>
	يسمح المؤشر بجلب البيانات بكميات صغيرة، وهذا أسرع وأوفر للذاكرة من نسخ جميع البيانات الناتجة إلى البرنامج مرةً واحدةً، وتبرز أهمية ذلك عند العمل على قواعد بيانات كبيرة جدًا أحجامها بالجيجابايت، لكن هذا يعني أننا عندما نعالج جزءًا من البيانات الناتجة في وقت ما، فيجب ألا ننفذ أي استعلامات أخرى باستخدام نفس المؤشر، وإلا فسنفقد الوصول إلى مجموعة النتائج الأصلية، لذا يجب إنشاء مؤشر جديد للاستعلام الجديد.
</p>

<p>
	أما في البرامج الصغيرة -مثل التي لدينا- فنستطيع نسخ جميع البيانات إلى هيكل بيانات بايثون لحل المشكلة، لكن يجب الانتباه إلى أننا قد نحتاج إلى عدة مؤشرات في البرامج الكبيرة.
</p>

<h2>
	الواجهة البرمجية لقواعد البيانات DB <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	يمكن قراءة توثيق الإصدار الأخير من واجهة برمجة التطبيقات لقواعد البيانات DB <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> في بايثون على <a href="http://www.python.org/peps/pep-0249.html" rel="external nofollow">موقع بايثون في قسم Database Topic Guide</a>، ويجب قراءته بعناية خاصةً عند برمجة قواعد بيانات ذات أهمية باستخدام بايثون.
</p>

<h3>
	تثبيت تعريفات SQLite
</h3>

<p>
	تأتي تعريفات SQLite في مكتبة بايثون القياسية افتراضيًا، فإذا أردنا استخدام قاعدة بيانات أخرى، مثل SQL Server الخاصة بمايكروسوفت أو <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">MySQL</a> أو Oracle، فسنحتاج إلى تنزيل الوحدات المناسبة لكل منها وتثبيتها، ويمكن الحصول على تعريفات أغلب قواعد البيانات المشهورة من <code>pip</code> أو في ملفات تنفيذية.
</p>

<p>
	سيكون أمر استيراد SQLite كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_105" style=""><span class="pln">   </span><span class="kwd">import</span><span class="pln"> sqlite3</span></pre>

<h3>
	استخدام DBI الأساسي
</h3>

<p>
	لن نغطي جميع المزايا الموجودة في DBI، لكننا سنذكر ما يكفي ليمكننا من الاتصال بقاعدة بياناتنا، وتنفيذ بعض الاستعلامات، ومعالجة النتائج، وسنختم بإعادة كتابة برنامج دليل جهات الاتصال ليستخدم قاعدة بيانات جهات الاتصال بدلًا من ملف نصي.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_107" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> db </span><span class="pun">=</span><span class="pln"> sqlite3</span><span class="pun">.</span><span class="pln">connect</span><span class="pun">(</span><span class="str">'address.db'</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cur </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">cursor</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> cur</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="str">'SELECT * FROM address'</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> cur</span><span class="pun">.</span><span class="pln">fetchall</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	ستكون النتيجة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_109" style=""><span class="pun">[(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Mona'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Akbar'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'42'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Any Street'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'SomePlace'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'MyTown'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ABC123'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'01234 567890'</span><span class="pun">),</span><span class="pln"> 
 </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Jamil'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Masoud'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'17'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Any Street'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'SomePlace'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'MyTown'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ABC234'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'01234 543129'</span><span class="pun">),</span><span class="pln"> 
 </span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Yousef'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Mohammad'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'9'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Crypt Drive'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hotspot'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Metropolis'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ABC345'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'01234 456459'</span><span class="pun">),</span><span class="pln">
 </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Yasein'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Akbar'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'42'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Any Street'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'SomePlace'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'MyTown'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ABC123'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'01234 567890'</span><span class="pun">),</span><span class="pln"> 
 </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Yasein'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Akbar'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'12A'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Double Street'</span><span class="pun">,</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln"> </span><span class="str">'AnyTown'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'DEF174'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'01394 784310'</span><span class="pun">)]</span></pre>

<p>
	تعيد <code>cursor.fetchball()‎</code> قائمةً من الصفوف tuples، وهذا مشابه لما بدأنا به في مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r1287/" rel="">مدخل إلى البيانات وأنواعها: أنواع البيانات الأساسية</a>، ونستطيع استخدام هذه القائمة في برنامجنا كما لو قرأناها من ملف مستخدمين قاعدة البيانات آليةً ثابتةً، غير أن قوة قواعد البيانات الحقيقية تكمن في قدرتها على تنفيذ استعلامات معقدة باستخدام <code>SELECT</code>.
</p>

<h2>
	دليل جهات الاتصال
</h2>

<p>
	لا زال برنامج دليل جهات الاتصال الخاص بنا يعتمد على سطر الأوامر وليست له واجهة رسومية، فإذا أردنا إضافة واجهة مستخدم فيجب أن نعيد هيكلة الشيفرة refactoring لفصل الوظائف عن العرض، على كل سنضيف واجهة ويب للبرنامج.
</p>

<p>
	لن نشرح كل تفصيل في الشيفرة هنا، فيجب أن يستطيع القارئ في هذا المستوى أن يفهمها بنفسه، لكننا سنركز على بعض النقاط ونناقشها.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_6187_111" style=""><span class="com">###############################</span><span class="pln">
</span><span class="com"># Addressbook.py</span><span class="pln">
</span><span class="com">#</span><span class="pln">
</span><span class="com"># Author: A J Gauld</span><span class="pln">
</span><span class="com">#</span><span class="pln">
</span><span class="str">''' 
    Build a simple addressbook using 
    the SQLite database and Python 
    DB-<abbr title="Application Programming Interface | واجهة برمجية">API</abbr>.
'''</span><span class="pln">
</span><span class="com">###############################</span><span class="pln">

</span><span class="com"># set up the database and cursor</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> sqlite3
dbpath </span><span class="pun">=</span><span class="pln"> </span><span class="str">"D:/DOC/Homepage/Tutor2/sql/"</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> initDB</span><span class="pun">(</span><span class="pln">path</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln"> 
        db </span><span class="pun">=</span><span class="pln"> sqlite3</span><span class="pun">.</span><span class="pln">connect</span><span class="pun">(</span><span class="pln">path</span><span class="pun">)</span><span class="pln">
        cursor </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">cursor</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> sqlite3</span><span class="pun">.</span><span class="typ">OperationalError</span><span class="pun">:</span><span class="pln"> 
        </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Failed to connect to database:"</span><span class="pun">,</span><span class="pln"> path </span><span class="pun">)</span><span class="pln">
        db</span><span class="pun">,</span><span class="pln">cursor </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">None</span><span class="pun">,</span><span class="kwd">None</span><span class="pln">
        </span><span class="kwd">raise</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> db</span><span class="pun">,</span><span class="pln">cursor

</span><span class="com"># Driver functions</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> addEntry</span><span class="pun">(</span><span class="pln">book</span><span class="pun">):</span><span class="pln">
    first </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'First name: '</span><span class="pun">)</span><span class="pln"> 
    </span><span class="kwd">last</span><span class="pln"> </span><span class="pun">=</span><span class="pln">  input</span><span class="pun">(</span><span class="str">'Last name: '</span><span class="pun">)</span><span class="pln"> 
    house </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'House number: '</span><span class="pun">)</span><span class="pln"> 
    street </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Street name: '</span><span class="pun">)</span><span class="pln"> 
    district </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'District name: '</span><span class="pun">)</span><span class="pln"> 
    town </span><span class="pun">=</span><span class="pln">  input</span><span class="pun">(</span><span class="str">'City name: '</span><span class="pun">)</span><span class="pln"> 
    code </span><span class="pun">=</span><span class="pln">  input</span><span class="pun">(</span><span class="str">'Postal Code: '</span><span class="pun">)</span><span class="pln"> 
    phone </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Phone Number: '</span><span class="pun">)</span><span class="pln"> 
    query </span><span class="pun">=</span><span class="pln"> </span><span class="str">'''INSERT INTO Address 
               (First,Last,House,Street,District,Town,PostCode,Phone)
               VALUES (?,?,?,?,?,?,?,?)'''</span><span class="pln">

    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
       book</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="pln">query</span><span class="pun">,(</span><span class="pln">first</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">last</span><span class="pun">,</span><span class="pln"> house</span><span class="pun">,</span><span class="pln"> street</span><span class="pun">,</span><span class="pln"> district</span><span class="pun">,</span><span class="pln"> town</span><span class="pun">,</span><span class="pln"> code</span><span class="pun">,</span><span class="pln"> phone</span><span class="pun">))</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> sqlite3</span><span class="pun">.</span><span class="typ">OperationalError</span><span class="pun">:</span><span class="pln">  
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Insert failed"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">raise</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> removeEntry</span><span class="pun">(</span><span class="pln">book</span><span class="pun">):</span><span class="pln">
    name  </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Enter a name: "</span><span class="pun">)</span><span class="pln">
    names </span><span class="pun">=</span><span class="pln"> name</span><span class="pun">.</span><span class="pln">split</span><span class="pun">()</span><span class="pln">
    first </span><span class="pun">=</span><span class="pln"> names</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln"> </span><span class="kwd">last</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> names</span><span class="pun">[-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
       book</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="str">'''DELETE FROM Address 
                    WHERE First LIKE ? 
                    AND Last LIKE ?'''</span><span class="pun">,(</span><span class="pln">first</span><span class="pun">,</span><span class="kwd">last</span><span class="pun">))</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> sqlite3</span><span class="pun">.</span><span class="typ">OperationalError</span><span class="pun">:</span><span class="pln"> 
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Remove failed"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">raise</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> findEntry</span><span class="pun">(</span><span class="pln">book</span><span class="pun">):</span><span class="pln">
    validFields </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">'first'</span><span class="pun">,</span><span class="str">'last'</span><span class="pun">,</span><span class="str">'house'</span><span class="pun">,</span><span class="str">'street'</span><span class="pun">,</span><span class="pln">
                   </span><span class="str">'district'</span><span class="pun">,</span><span class="str">'town'</span><span class="pun">,</span><span class="str">'postcode'</span><span class="pun">,</span><span class="str">'phone'</span><span class="pun">)</span><span class="pln">
    field </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Enter a search field: "</span><span class="pun">)</span><span class="pln">
    value </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Enter a search value: "</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> field</span><span class="pun">.</span><span class="pln">lower</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> validFields</span><span class="pun">:</span><span class="pln">
       query </span><span class="pun">=</span><span class="pln"> </span><span class="str">'''SELECT first,last,house,street,district,town,postcode,phone
                  FROM Address WHERE %s LIKE ?'''</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> field
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">ValueError</span><span class="pun">(</span><span class="str">"invalid field name"</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        book</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="pln">query</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">,)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
        result </span><span class="pun">=</span><span class="pln"> book</span><span class="pun">.</span><span class="pln">fetchall</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> sqlite3</span><span class="pun">.</span><span class="typ">OperationalError</span><span class="pun">:</span><span class="pln"> 
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Sorry search failed"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">raise</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> result</span><span class="pun">:</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> result</span><span class="pun">:</span><span class="pln">
               </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> line </span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">"No matching data"</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">


</span><span class="kwd">def</span><span class="pln"> testDB</span><span class="pun">(</span><span class="pln">database</span><span class="pun">):</span><span class="pln">
    database</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="str">"SELECT * FROM Address"</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> database</span><span class="pun">.</span><span class="pln">fetchall</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> closeDB</span><span class="pun">(</span><span class="pln">database</span><span class="pun">,</span><span class="pln"> cursor</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
       cursor</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
       database</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span><span class="pln">
       database</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> sqlite3</span><span class="pun">.</span><span class="typ">OperationalError</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"problem closing database..."</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">raise</span><span class="pln">

</span><span class="com"># User Interface functions</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> getChoice</span><span class="pun">(</span><span class="pln">menu</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> menu </span><span class="pun">)</span><span class="pln">
    choice </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Select a choice(1-4): "</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> choice

</span><span class="kwd">def</span><span class="pln"> main</span><span class="pun">():</span><span class="pln">
    theMenu </span><span class="pun">=</span><span class="pln"> </span><span class="str">'''
    1) Add Entry
    2) Remove Entry
    3) Find Entry
    4) Test database connection

    9) Quit and save
    '''</span><span class="pln">

    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
       theDB</span><span class="pun">,</span><span class="pln"> theBook </span><span class="pun">=</span><span class="pln"> initDB</span><span class="pun">(</span><span class="pln">dbpath </span><span class="pun">+</span><span class="pln"> </span><span class="str">'address.db'</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
           choice </span><span class="pun">=</span><span class="pln"> getChoice</span><span class="pun">(</span><span class="pln">theMenu</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="str">'9'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> choice</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'Q'</span><span class="pun">:</span><span class="pln">
              </span><span class="kwd">break</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="str">'1'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> choice</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'A'</span><span class="pun">:</span><span class="pln">
               addEntry</span><span class="pun">(</span><span class="pln">theBook</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">elif</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="str">'2'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> choice</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'R'</span><span class="pun">:</span><span class="pln">
               removeEntry</span><span class="pun">(</span><span class="pln">theBook</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">elif</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="str">'3'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> choice</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'F'</span><span class="pun">:</span><span class="pln">
               </span><span class="kwd">try</span><span class="pun">:</span><span class="pln"> findEntry</span><span class="pun">(</span><span class="pln">theBook</span><span class="pun">)</span><span class="pln">
               </span><span class="kwd">except</span><span class="pun">:</span><span class="pln"> </span><span class="typ">ValueError</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">"No such field name"</span><span class="pun">))</span><span class="pln">
           </span><span class="kwd">elif</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="str">'4'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> choice</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'T'</span><span class="pun">:</span><span class="pln">
               testDB</span><span class="pun">(</span><span class="pln">theBook</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Invalid choice, try again"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">except</span><span class="pln"> sqlite3</span><span class="pun">.</span><span class="typ">OperationalError</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Database error, exiting program."</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
        </span><span class="com"># raise</span><span class="pln">
    </span><span class="kwd">finally</span><span class="pun">:</span><span class="pln"> 
        closeDB</span><span class="pun">(</span><span class="pln">theDB</span><span class="pun">,</span><span class="pln">theBook</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> __name__ </span><span class="pun">==</span><span class="pln"> </span><span class="str">'__main__'</span><span class="pun">:</span><span class="pln"> main</span><span class="pun">()</span></pre>

<p>
	نلاحظ عدة أمور هي:
</p>

<ol>
	<li>
		استخدمنا الشرط <code>try/except</code> لالتقاط أي أخطاء في قاعدة البيانات، وبما أن الخطأ هو نوع مخصص معرَّف داخل وحدة <code>sqlite3</code>، فسنحتاج إلى سبقه باسم الوحدة.
	</li>
	<li>
		استخدمنا الكلمة المفتاحية <code>raise</code> بعد طباعة رسالة الخطأ، فنتج عن ذلك رفع الاستثناء الأصلي إلى المستوى التالي، والذي هو <code>main</code> في حالتنا، حيث التقط وطُبعت رسالة أخرى.
	</li>
	<li>
		استخدمنا كذلك محرف البدل <code>?</code> في سلاسل الاستعلامات لتحمل متغيرات البيانات، وهذا يشبه محدِّدات <code>%</code> المستخدمة في صياغة السلاسل النصية، لكن تُدخل القيم هنا جزءًا من تنفيذ الاستعلام بواسطة <code>book.execute</code>، حيث نمرر صف القيم المدرجة وسيطًا ثانيًا، وميزة هذا تكمن في التحقق الأمني من قيم الدخل مما يحسِّن من أمان الشيفرة، فإذا لم نتحقق من الدخل، أو استخدمنا الصياغة القياسية للسلاسل النصية؛ فقد يكتب أحد المستخدمين شيفرةً بدلًا من قيمة الدخل، لتدخل تلك الشيفرة إلى الاستعلام وتخرب قاعدة البيانات، وهذا يُعرف بهجمات الحقن injection attack في دوائر <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">الأمن الرقمي</a>، وهو أحد أكثر الاختراقات الأمنية شهرةً في الويب هذه الأيام.
	</li>
	<li>
		نستخدم كلًا من اسم الحقل وقيمة البحث حقول إدراج في الدالة <code>findEntry</code>، مما يجعل دالة البحث أكثر تنوعًا، ولولاه لاحتجنا إلى دالة بحث لكل معيار بحث criteria وهذا أمر مرهق جدًا. لكن توجد مشكلة هنا سببها أن آلية معامِلات SQLite تعمل للقيم فقط، وليس لعناصر SQL، مثل أسماء الحقول أو الجداول، ولحل هذا نحتاج إلى استخدام صياغة السلاسل النصية في بايثون لإدراج اسم الحقل، ونحتاج إلى التحقق من أن اسم الحقل هو أحد الأسماء المعرّفة قبل إدراجه في الاستعلام، لنضمن أن الاستعلام آمن، فإذا لم يكن الحقل صالحًا فسنرفع <a href="https://wiki.hsoub.com/Python/exceptions" rel="external">استثناء بايثون</a> قياسي من النوع <code>ValueError</code>، ثم نحتاج إلى التقاط ذلك في دالة <code>main()‎</code>، ونلاحظ أن الاستعلام يستخدم تعبير البحث <code>LIKE</code> الذي يسمح لنا باستغلال خيار محرف البدل <code>%</code> في SQL في سلسلة البحث الخاصة بنا.
	</li>
	<li>
		تحتوي الدالة <code>closeDB</code> على استدعاء <code>commit</code>، وهذا يجبر قاعدة البيانات على كتابة جميع التغييرات في الجلسة الحالية إلى الملف، ويمكن النظر إليها على أنها تشبه التابع <code>file.flush</code>، فهي تنهي العملية transaction نوعًا ما.
	</li>
	<li>
		تغلف الدالة <code>main</code> كل شيء داخل بنية <code>try/except/finally</code>، ويلتقط الشرط <code>except</code> الاستثناءات التي رفعتها دوال المستوى الأدنى كما ذكرنا أعلاه، لكن نلاحظ أنه يحوي تعليمة <code>raise</code> التي أُخرجت من التنفيذ بوضع علامة تعليق قبلها، لأن التعقب الخلفي الكامل للخطأ مفيد جدًا في تنقيح الأخطاء رغم كونه غير مفضل للمستخدم من حيث قابلية القراءة، لذلك يمكن إلغاء التعليق من <code>raise</code> التي في المستوى الأعلى أثناء التطوير لنحصل على تعقب خلفي كامل على الشاشة، وبعد حلّ جميع الزلات البرمجية bugs نعيد التعليق إلى تعليمة <code>raise</code> مرةً أخرى لاستعادة العرض النهائي للبرنامج، وهذا الأسلوب ليس مقصورًا على قواعد البيانات وحدها، بل يمكن استخدامه في أي برنامج يحتمل رفع أخطاء كثيرة فيه ولا نريد إظهار ذلك للمستخدمين، لكننا نحن المكورون نريد أن نراها.
	</li>
	<li>
		يُستخدم الشرط <code>finally</code> في دالة <code>main</code> لضمان إغلاق قاعدة البيانات بأناقة بغض النظر قابلنا أخطاءً أم لا، وهذا يقلل خطر تخريب البيانات.
	</li>
</ol>

<h3>
	ملاحظة عن الأمن الرقمي
</h3>

<p>
	ذكرنا أعلاه أن استخدام DB <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> لمحددات <code>?</code> بدلًا من استخدام <code>%</code> المعتادة كان بداعي الأمان، ويمكن استخدام صياغة السلاسل النصية المعتادة في الشيفرة، وسنجد أنها ستعمل، مما يغري باستخدامها، غير أنه يُفضل عدم فعل ذلك لما نعلم من كثرة الهجمات السيبرانية، فيجب هنا اتباع هذه الإرشادات لتصبح عادات للمبرمج للحفاظ على أمان الشيفرة.
</p>

<p>
	ورغم أنها حل غير كامل وقد نخسر معها رؤية استعلامات SQL الحقيقية المرسَلة إلى قاعدة البيانات، والذي كنا سنستفيد منه في تنقيح الأخطاء، لكن هذه أفضل طريقة للتغلب على احتمال أن يُدخل المستخدم بيانات شاذةً.
</p>

<h2>
	كلمة أخيرة
</h2>

<p>
	استخدمنا SQLite في أمثلتنا لأنها متاحة مجانًا، وسهلة التثبيت والاستخدام، ومرنة في مدى الأخطاء التي تسمح بها، غير أن هذه البساطة تعني أن المزايا الأكثر تقدمًا والموجودة في الحزم الأقوى غير موجودة فيها، فإمكانيات معالجة النصوص ومجال القيود المتاحة محدود للغاية، ويجب قضاء وقت كافٍ في قراءة الوثائق المرجعية عند التعامل مع قواعد بيانات مثل Oracle أو قاعدة بيانات DB2 من IBM، لأن استخدام المزايا التي توفرها قاعدة البيانات يقلل من كم الشيفرات المخصصة التي ستُكتب، ويحسن الأداء أيضًا.
</p>

<h2>
	المزايا المتقدمة لقواعد البيانات
</h2>

<h3>
	المفاتيح الخارجية
</h3>

<p>
	تحتوي أغلب قواعد البيانات -بما فيها SQLite- على مفاتيح خارجية foreign keys، تسمح لنا بتحديد الروابط أو العلاقات بين الجداول، بحيث تتكون هذه المفاتيح من مفاتيح رئيسية لجداول أخرى، وأحيانًا في قواعد بيانات أخرى. ورغم أننا لم نتحدث كثيرًا عن الروابط بين الجداول إلا أنها من أكثر المزايا شيوعًا في قواعد البيانات العلائقية خاصةً عند زيادة حجم البرامج.
</p>

<h3>
	التكامل المرجعي
</h3>

<p>
	التكامل المرجعي Referential integrity هو القدرة على عدم السماح بقيم بيانات في عمود إلا إذا كانت موجودةً في مكان آخر، ففي قاعدة بيانات الموظفين مثلًا، كان بإمكاننا تقييد القيمة في حقل <code>Employee.Grade</code> لتسمح بالقيم المعرَّفة في جدول <code>Salary.Grade</code> فقط، وهذه أداة بالغة القوة في الحفاظ على اتساق البيانات عبر قاعدة البيانات، خاصةً عندما تُستخدم القيم مفاتيح لربط جدولين، كما هو الحال في أعمدة <code>grade</code>.
</p>

<p>
	تدعم SQLite صورةً محدودةً من التكامل المرجعي في صورة قيد، لكنها تتطلب بعض المعالجة الخاصة، وهي أقل شموليةً من قواعد البيانات الأقوى.
</p>

<h3>
	الإجراءات المخزنة
</h3>

<p>
	الإجراءات المخزنة Stored Procedures هي دوال مكتوبة بلغة برمجة خاصة proprietary programming language يوفرها مزود قاعدة البيانات، وتُخزَّن في قاعدة البيانات، ومزيتها أنها إجراءات مصرَّفة compiled، وبالتالي أسرع كثيرًا من استخدام أوامر SQL المكافئة، كما أنها توفر من استهلاك الإنترنت وحجم البيانات المطلوب، من خلال طلب اسم الدالة والوسطاء فقط ليرسلها برنامج العميل، ولكونها مبنيةً داخل الخادم فهي تسمح لنا ببناء سلوكيات مشتركة -مثل قواعد العمل المعقدة- في قاعدة البيانات حيث يمكن تشاركها بواسطة جميع التطبيقات باستمرار، لكن عيبها أنها خاصة ومغلقة، فإذا أردنا تغيير مزود قاعدة البيانات لدينا فيجب إعادة كتابة جميع الإجراءات المخزنة، في حين أن SQL القياسية ستعمل دون تغيير على أي قاعدة بيانات، ولا تدعم SQLite أي إجراءات مخزنة.
</p>

<h3>
	العروض
</h3>

<p>
	<a href="https://wiki.hsoub.com/SQL#.D8.A7.D9.84.D8.AA.D8.B9.D8.A7.D9.85.D9.84_.D9.85.D8.B9_.D8.A7.D9.84.D8.B9.D8.B1.D8.B6" rel="external">العروض Views</a> هي جداول افتراضية مكونة من جداول حقيقية أخرى، وقد تكون مجموعةً فرعيةً من البيانات في جدول آخر من أجل تبسيط التصفح، وفي الحالة الأشهر تكون بعض الأعمدة من جدول وبعضها من جدول آخر بحيث يكون الجدولان مرتبطين معًا بمفتاح ما.
</p>

<p>
	ويمكن النظر إليها على أنها استعلام SQL يُنفّذ باستمرار وتُخزن النتيجة في العرض، وسيتغير العرض مع تغير البيانات التي فيه، وقد تسمح بعض قواعد البيانات بقراءة البيانات في العرض، غير أنها جميعًا تسمح بالتحديثات.
</p>

<p>
	تُستخدم العروض في الغالب لتقسيم البيانات بحيث يستطيع المستخدم الواحد أن يرى مجموعة البيانات المتعلقة به فقط، وتدعم SQLite العروض، لكننا لم نشرحها هنا.
</p>

<h3>
	عمليات الحذف المتتالية
</h3>

<p>
	إذا أجرينا حذفًا متتاليًا cascaded delete بين عنصري بيانات فهذا يعني أنه عند حذف العنصر الرئيسي فستُحذف العناصر الثانوية أيضًا، وأحد أشهر الأمثلة على ذلك هو الطلبات orders، حيث يتكون الطلب عادةً من الطلب نفسه بالإضافة إلى العناصر المطلوبة، ويُخزن كل منها عادةً في جدول منفصل، فإذا حذفنا الطلب فإننا نرغب بالتأكيد في حذف عناصره، وتُهيأ عمليات الحذف المتتالية في تعليمات DDL لقواعد البيانات المستخدمة لإنشاء مخططات قواعد البيانات، وهي أحد أنواع القيود، ولا تدعم SQLite عمليات الحذف المتكررة.
</p>

<h3>
	المحفزات
</h3>

<p>
	تشبه المحفزات Triggers الأحداث إلى حد ما، فهي جزء من SQL يُنفَّذ عند وقوع حدث معين، كما في حالة إدراج صف جديد في جدول ما مثلًا، وهي مفيدة في التحقق من صلاحية البيانات تحققًا أعمق من مجرد النوع والقيم، كما تكون مفيدةً للغاية عند ربطها بالإجراءات المخزنة.
</p>

<p>
	أما عيبها فهو إمكانية إساءة استخدامها، وشرهها الزائد للموارد، مما يؤدي لإبطاء قاعدة البيانات كثيرًا، لذا يجب استخدامها بحذر، وتدعم SQLite محفزات SQL الأساسية والخالصة.
</p>

<h3>
	أنواع البيانات المتقدمة
</h3>

<p>
	تسمح بعض قواعد البيانات بتخزين مجموعات متنوعة من أنواع البيانات، فقد يكون لدينا عناوين شبكية network addresses وكائنات ثنائية binary كبيرة يشار إليها اختصارًا باسم BLOBS لملفات الصور وغيرها، إضافةً إلى البيانات العددية وبيانات المحارف والتاريخ والوقت المعتادة، ومن أنواع البيانات المشهورة أيضًا نوع يسمى بالنوع العشري ذي الدقة الثابتة fixed precision decimal type، وهو يُستخدم في البيانات المالية لتجنب أخطاء التقريب الموجودة في أعداد الفاصلة العائمة التقليدية، وتدعم SQLite بيانات BLOB لكنها لا تدعم بقية الأنواع المتقدمة، وللاطلاع على المزيد من الاستخدامات المعقدة لـ SQLite يمكن العودة إلى <a href="http://www.sqlitetutorial.net/" rel="external nofollow">موقع sqlitetutorial</a> الذي يحتوي على شرح ممتاز يسهل تعلم ما فيه بناءً على ما شرحنا هنا.
</p>

<h2>
	خاتمة
</h2>

<p>
	في نهاية هذا المقال نرجو أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		قواعد البيانات تنظم البيانات في جداول.
	</li>
	<li>
		تتكون السجلات من حقول، وتشمل صفوف الجداول.
	</li>
	<li>
		SQL هي لغة تُستخدم في إدارة البيانات.
	</li>
	<li>
		الأوامر الأساسية في لغة SQL هي: CREATE وINSERT وSELECT وUPDATE.
	</li>
	<li>
		توفر لغات البرمجة مغلِّفات SQL للوصول إلى البيانات من البرامج.
	</li>
	<li>
		تخزن المؤشرات نتائج استعلامات SQL في صورة مؤقتة، لكن يمكن الوصول إليها.
	</li>
	<li>
		تُستخدم محدِّدات DB <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> لإدراج قيم في الاستعلامات، ولا تُستخدم صيغة السلاسل النصية القياسية.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutdbms.htm" rel="external nofollow">للفصل الرابع والعشرين: Working with Databases</a> من كتاب Learn To Program لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%B5%D9%84-%D9%85%D8%B9-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%B9%D8%A8%D8%B1-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1520/" rel="">التواصل مع نظام التشغيل عبر بايثون</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D8%AF%D8%B1%D8%A7%D8%B3%D8%A9-%D8%AD%D8%A7%D9%84%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1392/" rel="">دراسة حالة برمجية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A5%D8%AF%D8%AE%D8%A7%D9%84%D8%8C-%D8%A7%D9%84%D8%AD%D8%B0%D9%81-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D9%81%D9%8A-sql-r587/" rel="">التعامل مع البيانات (الإدخال، الحذف والتعديل) في SQL</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-sql-r855/" rel="">دوال التعامل مع البيانات في SQL</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%d9%85%d9%82%d8%a7%d8%b1%d9%86%d8%a9-%d8%a8%d9%8a%d9%86-%d8%a3%d9%86%d8%b8%d9%85%d8%a9-%d8%a5%d8%af%d8%a7%d8%b1%d8%a9-%d9%82%d9%88%d8%a7%d8%b9%d8%af-%d8%a7%d9%84%d8%a8%d9%8a%d8%a7%d9%86%d8%a7%d8%aa-%d8%a7%d9%84%d8%b9%d9%84%d8%a7%d9%82%d9%8a%d8%a9-sqlite-%d9%85%d8%b9-mysql-%d9%85%d8%b9-postgresql-r72/" rel="">مقارنة بين أنظمة إدارة قواعد البيانات العلاقية: SQLite مع MySQL مع PostgreSQL</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">602</guid><pubDate>Sat, 02 Apr 2022 16:03:00 +0000</pubDate></item><item><title>&#x623;&#x645;&#x62B;&#x644;&#x629; &#x639;&#x645;&#x644;&#x64A;&#x629; &#x639;&#x646; &#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62A;&#x635;&#x645;&#x64A;&#x645; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%B9%D9%86-%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r597/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_03/623aa7bd434ea_.png.9126f4395d0f27e3783363885a5b56a3.png" /></p>

<p>
	سنوضح في هذا المقال مثالًا عمليًا عن خطوات تصميم قاعدة بيانات لجامعة، كما سنضع أمثلةً عمليةً تشرح كيفية إنشاء مخططات ERD، إذ يشرح المثال الأول مثالًا عن مخطط ERD لشركة تصنيع، ويشرح المثال الثاني مثالًا عن مخطط ERD لوكيل سيارات، كما يقدم خطوات لحل تمرين باستخدام <a href="https://wiki.hsoub.com/SQL" rel="external">لغة SQL</a> وعباراتها.
</p>

<h2>
	مثال عملي عن تصميم قاعدة بيانات لجامعة
</h2>

<p>
	فيما يلي متطلبات البيانات لمنتج من أجل دعم تسجيل وتقديم المساعدة لطلاب جامعة تعليم إلكتروني وهمية.
</p>

<p>
	تحتاج جامعة تعليم إلكتروني إلى الاحتفاظ بتفاصيل طلابها وموظفيها، والمقررات التي تقدمها وأداء الطلاب الذين يدرسون فيها. تدار الجامعة في أربع مناطق جغرافية (إنجلترا واسكتلندا وويلز وأيرلندا الشمالية).
</p>

<p>
	يجب تسجيل معلومات كل طالب في البداية عند التسجيل، ويتضمن ذلك رقم تعريف الطالب الصادر في الوقت والاسم وسنة التسجيل والمنطقة الموجود فيها الطالب. ليس الطالب ملزمًا بالتسجيل في أي مقرر عند التسجيل، فيمكنه التسجيل في مقررٍ ما في وقتٍ لاحق.
</p>

<p>
	يجب أن تتضمن المعلومات المسجلة لكل عضو في القسم التعليمي وقسم الإرشاد رقمَ الموظف والاسم والمنطقة التي يوجد بها. قد يعمل كل موظف كمرشد counselor لطالبٍ أو أكثر، وقد يعمل كمدرس tutor لطالبٍ أو أكثر في مقررٍ أو أكثر. قد لا يُخصَّص لأحد الموظفين أي طالب كمدرس أو كمرشد في أي وقتٍ معين.
</p>

<p>
	يملك كل طالب مرشدًا واحدًا يخصَّص له عند التسجيل، ويقدّم الدعم للطالب طوال حياته الجامعية. يُخصَّص للطالب مدرسٌ منفصلٌ لكل مقرر سجّل فيه الطالب. يُسمَح للموظف فقط العمل كمرشد أو كمدرّس لطالبٍ مقيم في نفس منطقته.
</p>

<p>
	يجب أن يكون لكل مقرر متوفر للدراسة رمز مقرر وعنوان وقيمة من حيث نقاط الائتمان، حيث يكون للمقرر إما 15 نقطة أو 30 نقطة. قد يكون للمقرر حصة quota لعدد الطلاب المسجلين فيه في أي عرض. لا يحتاج المقرر إلى أي طالب مسجل فيه (مثل المقرر الذي كُتِب للتو ثم عُرِض للدراسة).
</p>

<p>
	يُقيَّد الطلاب في عدد المقررات التي يمكنهم التسجيل فيها في نفس الوقت، فقد لا يأخذون المقررات في نفس الوقت إذا تجاوز مجموع النقاط المدمَجة للمقررات المسجلين فيها 180 نقطة.
</p>

<p>
	قد يكون للمقرر ذي الـ 15 نقطة ما يصل إلى ثلاث وظائف لكل عرض، ويكون للمقرر ذي الـ 30 نقطة ما يصل إلى خمس وظائف لكل عرض. تُسجَّل درجة الوظيفة في أي مقرر كعلامةٍ من 100.
</p>

<p>
	<a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة بيانات</a> الجامعة التالية نموذج بيانات محتمل يصِف مجموعة المتطلبات المذكورة أعلاه. يحتوي النموذج على عدة أجزاء، بدءًا من مخطط ERD ويليه وصفٌ لأنواع الكيانات والقيود والافتراضات.
</p>

<h3>
	عملية التصميم
</h3>

<ol>
<li>
		الخطوة الأولى هي تحديد النوى والتي هي عادة أسماء: الموظفين Staff والمقرر Course والطالب Student والوظيفة Assignment.
	</li>
	<li>
		الخطوة التالية هي توثيق جميع السمات attributes لكل كيان entity. هذا هو المكان الذي تحتاج فيه إلى التأكد من توحيد normalized جميع الجداول توحيدًا صحيحًا.
	</li>
	<li>
		أنشئ مخطط ERD الأولي وراجعه مع المستخدمين.
	</li>
	<li>
		أجرِ تغييرات إن لزم الأمر بعد مراجعة مخطط ERD.
	</li>
	<li>
		تحقق من <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D8%A9-er-%D9%84%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r543/" rel="">نموذج ER</a> مع المستخدمين لوضع اللمسات الأخيرة على التصميم.
	</li>
</ol>
<p>
	يوضّح الشكل التالي مخطط ERD للجامعة الذي يمثّل نموذج بيانات لنظام سجلات الطلاب والموظفين
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2022_09/UniversityERD.png.a4ee74f342024df358c842d2349a590a.png" data-fileid="107555" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="107555" data-unique="gpa4ur7gl" src="https://academy.hsoub.com/uploads/monthly_2022_09/UniversityERD.thumb.png.221f4275596344355853c02de16edba5.png" style="width: 580px; height: auto;" alt="UniversityERD.png"></a>
</p>

<p>
	الكيان Entity
</p>

<ul>
<li>
		Student (StudentID, Name, Registered, Region, StaffNo).
	</li>
	<li>
		Staff (StaffNo, Name, Region): يحتوي هذا الجدول على مدرّسين وغيرهم من الموظفين.
	</li>
	<li>
		Course (CourseCode, Title, Credit, Quota, StaffNo).
	</li>
	<li>
		Enrollment (StudentlD, CourseCode, DateEnrolled, FinalGrade).
	</li>
	<li>
		Assignment (StudentID, CourseCode, AssignmentNo, Grade).
	</li>
</ul>
<h4>
	القيود Constraints
</h4>

<ul>
<li>
		يجوز لأحد الموظفين أن يدرّس أو يرشد الطلاب المتواجدين في نفس منطقتهم فقط.
	</li>
	<li>
		قد لا يسجّل الطلاب في مقررات لا تزيد قيمتها عن أكثر من 180 نقطة في نفس الوقت.
	</li>
	<li>
		للسمة Credit (ضمن المقرر Course) قيمة هي 15 أو 30 نقطة.
	</li>
	<li>
		قد يكون للمقرر الذي له 30 نقطة ما يصل إلى خمس وظائف، بينما يكون للمقرر الذي له 15 نقطة ما يصل إلى ثلاث وظائف.
	</li>
	<li>
		للسمة Grade (ضمن الوظيفة Assignment) قيمة هي علامة من 100.
	</li>
</ul>
<h4>
	الافتراضات Assumptions
</h4>

<ul>
<li>
		يستطيع الطالب أن يسجّل مرة واحدة للمقرر حيث تُسجَّل عمليات التسجيل الحالية فقط.
	</li>
	<li>
		تُقدَّم الوظيفة مرة واحدة فقط.
	</li>
</ul>
<h4>
	العلاقات Relationships (تشمل عددية العلاقة cardinality)
</h4>

<p>
	لاحظ في الشكل الآتي أن سجل الطالب مرتبط مع مقررات مُسجَّلة بحد أدنى مقرر واحد إلى مقررات متعددة كحد أقصى.
</p>

<p>
	يجب أن يكون لكل تسجيل enrollment طالب صالح.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: بما أن معرّف الطالب StudentID هو جزء من المفتاح الرئيسي PK، فلا يمكن أن يكون فارغًا null، لذلك يجب وجود معرّف طالب StudentID مُدخَل في جدول الطالب مرة واحدة على الأقل كحد أقصى، لأن المفتاح الرئيسي PK يجب ألّا يتكرّر.
		</p>
	</div>
</blockquote>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93252" href="https://academy.hsoub.com/uploads/monthly_2022_03/StudentOneToManyEnrollment.png.26f6ee662552c90ffbd9dd4ccbd7fa55.png" rel=""><img alt="StudentOneToManyEnrollment.png" class="ipsImage ipsImage_thumbnailed" data-fileid="93252" data-unique="eemf6td9e" src="https://academy.hsoub.com/uploads/monthly_2022_03/StudentOneToManyEnrollment.thumb.png.892efad5c5ed7a47a6583ed044254c92.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	يوضح الشكل الآتي ارتباط سجل الموظفين (المدرّس هنا) بحد أدنى 0 طالب وبطلاب متعددين كحد أقصى.
</p>

<p>
	قد يكون لسجل الطالب مدرسٌ tutor أو قد يكون بدون مدرس.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93251" href="https://academy.hsoub.com/uploads/monthly_2022_03/StaffToStudent.png.647dc2744ce378dd2cf7161218a9e606.png" rel=""><img alt="StaffToStudent.png" class="ipsImage ipsImage_thumbnailed" data-fileid="93251" data-unique="s59gh471f" src="https://academy.hsoub.com/uploads/monthly_2022_03/StaffToStudent.thumb.png.89f1c0ca407277d3b92720608ba63d0c.png" style="width: 500px; height: auto;"></a>
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: يسمح الحقل StaffNo الموجود في جدول الطلاب Student بالقيم الفارغة التي تُمثَّل بالقيمة 0 على الجانب الأيسر من الشكل السابق. لكن في حالة وجود الحقل StaffNo في جدول الطلاب Student، فيجب أن يكون موجودًا في جدول الموظفين Staff بحد أقصى مرة واحدة (المُمثَّل بالقيمة 1 في الشكل السابق).
		</p>
	</div>
</blockquote>

<p>
	يرتبط سجل الموظفين Staff (المدرّس هنا) بعدد لا يقل عن 0 مقرّر كحد أدنى وبمقررات متعددة كحد أقصى.
</p>

<p>
	قد يكون المقرر course مرتبطًا بمدرّس instructor أو غير مرتبط بمدرس.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: الحقل StaffNo الموجود في جدول Course هو المفتاح الخارجي FK الذي يمكن أن يكون فارغًا، ويُمثَّل ذلك من خلال القيمة 0 على الجانب الأيسر من العلاقة في الشكل الآتي. إذا احتوى الحقل StaffNo على بيانات، فيجب أن يكون في جدول الموظفين Staff بحد أقصى مرة واحدة، ويُمثَّل ذلك بالقيمة 1 على الجانب الأيسر من العلاقة.
		</p>
	</div>
</blockquote>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93250" href="https://academy.hsoub.com/uploads/monthly_2022_03/StaffToCourse.png.0b4211ae356f403b3104d60f7d1fba61.png" rel=""><img alt="StaffToCourse.png" class="ipsImage ipsImage_thumbnailed" data-fileid="93250" data-unique="k5v0hmxk8" src="https://academy.hsoub.com/uploads/monthly_2022_03/StaffToCourse.thumb.png.f58cd54bcadf70ced6f23eca22938946.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	يجب توفير المقرر (في عملية التسجيل enrollment) مرة واحدة على الأقل ومرات متعددة كحد أقصى، كما يجب أن يحتوي جدول التسجيل Enrollment على مقرر واحد صالح على الأقل إلى مقررات متعددة كحد أقصى.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93248" href="https://academy.hsoub.com/uploads/monthly_2022_03/CourseToEnrollment.png.c862224b34c201f77c091c6f6d0934dc.png" rel=""><img alt="CourseToEnrollment.png" class="ipsImage ipsImage_thumbnailed" data-fileid="93248" data-unique="u3ish6ukc" src="https://academy.hsoub.com/uploads/monthly_2022_03/CourseToEnrollment.thumb.png.667f947a45704e1cbed5705e0843cf03.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	يمكن أن تحتوي عملية التسجيل على 0 مهمة كحد أدنى أو مهام متعددة كحد أقصى. يجب أن ترتبط الوظيفة assignment بتسجيل واحد على الأقل وبتسجيلٍ واحد كحد أقصى.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: يجب أن يحتوي كل سجل في جدول الوظائف على سجل تسجيل صالح، ويمكن ربط سجل تسجيل واحد بمهام متعددة.
		</p>
	</div>
</blockquote>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93249" href="https://academy.hsoub.com/uploads/monthly_2022_03/EnrollmentToAssignment.png.b2160403fbe1aea80f163b8d62fb6bc0.png" rel=""><img alt="EnrollmentToAssignment.png" class="ipsImage ipsImage_thumbnailed" data-fileid="93249" data-unique="6whlll9np" src="https://academy.hsoub.com/uploads/monthly_2022_03/EnrollmentToAssignment.thumb.png.1827cda5046a47e983d356393d5592b3.png" style="width: 500px; height: auto;"></a>
</p>

<h2>
	أمثلة عملية عن إنشاء مخططات ERD
</h2>

<p>
	سنعرض في هذه الجزئية مثالين عن عملية إنشاء مخططات ERD.
</p>

<h3>
	التمرين الأول: شركة تصنيع Manufacturer
</h3>

<p>
	تنتج شركة تصنيع منتجات، وتخزّن معلومات المنتج التالية: اسم المنتج product name ومعرّف المنتج product name والكمية المتوفرة quantity. تتكون هذه المنتجات من مكونات متعددة، ويوفّرموِّردٌ أو أكثر كلَّ مكون. تُحفَظ معلومات المكوّن التالية: معرّف المكون component ID واسمه name ووصف عنه description الموّردون suppliers الذين يوفرونه والمنتجات products التي تستخدم هذا المكوّن (استخدم الشكل الآتي لحل هذا التمرين).
</p>

<ol>
<li>
		أنشِئ مخطط ERD لإظهار كيفية تتبع هذه المعلومات.
	</li>
	<li>
		اعرض أسماء الكيانات entity names والمفاتيح الرئيسية primary keys وسمات attributes كل كيان والعلاقات بين الكيانات وعددية العلاقة cardinality.
	</li>
</ol>
<h4>
	الافتراضات Assumptions
</h4>

<ul>
<li>
		يمكن وجود الموّرد دون أن يوفّر مكونات.
	</li>
	<li>
		ليس واجبًا أن يرتبط مكونٌ بموّرد.
	</li>
	<li>
		ليس واجبًا أن يرتبط مكوّنٌ مع منتج، فليست جميع المكونات مستخدمَةً في المنتجات.
	</li>
	<li>
		لا يمكن أن يوجد منتج بدون مكونات.
	</li>
</ul>
<h4>
	جواب مخطط ERD
</h4>

<ul>
<li>
		Component(CompID, CompName, Description) PK=CompID.
	</li>
	<li>
		Product(ProdID, ProdName, QtyOnHand) PK=ProdID.
	</li>
	<li>
		Supplier(SuppID, SuppName) PK = SuppID.
	</li>
	<li>
		CompSupp(CompID, SuppID) PK = CompID, SuppID.
	</li>
	<li>
		Build(CompID, ProdID, QtyOfComp) PK= CompID, ProdID.
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93255" href="https://academy.hsoub.com/uploads/monthly_2022_03/ComponentProductERDAnswer-(1).png.38b5cbf482a2541df69a0a5d914094b8.png" rel=""><img alt="ComponentProductERDAnswer-(1).png" class="ipsImage ipsImage_thumbnailed" data-fileid="93255" data-unique="xthzl3qju" src="https://academy.hsoub.com/uploads/monthly_2022_03/ComponentProductERDAnswer-(1).thumb.png.e28b6b26bb138b8cd328e33834f6899c.png" style="width: 500px; height: auto;"></a>
</p>

<h3>
	التمرين الثاني: وكيل سيارات Car Dealership
</h3>

<p>
	أنشئ مخطط ERD لوكيل سيارات، حيث يبيع هذا الوكيل كلًا من السيارات الجديدة والمستعملة، ويشغّل قسمًا للخدمات. ابنِ تصميمك على قواعد الأعمال التالية:
</p>

<ul>
<li>
		قد يبيع مندوب المبيعات salesperson سيارات متعددة، ولكن تُباع كل سيارة بواسطة مندوب مبيعات واحد فقط.
	</li>
	<li>
		يمكن أن يشتري العميل customer سيارات متعددة، ولكن تُشترى كل سيارة بواسطة عميل واحد فقط.
	</li>
	<li>
		يكتب مندوب المبيعات فاتورةً invoice واحدة لكل سيارة يبيعها.
	</li>
	<li>
		يحصل العميل على فاتورة لكل سيارة يشتريها.
	</li>
	<li>
		قد يأتي العميل من أجل الحصول على خدماتٍ لسيارته فقط، وهذا يعني أن العميل لا يحتاج إلى شراء سيارة لكي يُصنَّف كعميل.
	</li>
	<li>
		إذا جلب العميل سيارةً أو أكثر لإصلاحها أو للحصول على خدمة، فستُكتَب تذكرة خدمة service ticket لكل سيارة.
	</li>
	<li>
		يحتفظ وكيل السيارات بتاريخ خدمة لكل من السيارات المُخدَّمة، ويُشار إلى سجلات الخدمة عن طريق رقم السيارة التسلسلي.
	</li>
	<li>
		يمكن أن يعمل على السيارة التي تُجلَب للحصول على خدمة ميكانيكيون متعددون، وقد يعمل كل ميكانيكي على سيارات متعددة.
	</li>
	<li>
		قد تحتاج السيارة التي تحصل على خدمة إلى قِطع أو قد لا تحتاج إلى قطع (مثل عملية ضبط المفحّم carburetor أو تنظيف فوهة حاقن الوقود التي لا تتطلب توفير قِطعٍ جديدة).
	</li>
</ul>
<h4>
	جواب مخطط ERD
</h4>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93254" href="https://academy.hsoub.com/uploads/monthly_2022_03/CarDealership.png.558ae682c0b895303d44ed44474a420b.png" rel=""><img alt="CarDealership.png" class="ipsImage ipsImage_thumbnailed" data-fileid="93254" data-unique="b0bhb9kna" src="https://academy.hsoub.com/uploads/monthly_2022_03/CarDealership.thumb.png.848a2a4b488aaa81c9a1094fbce6665a.png"></a>
</p>

<h2>
	حل تمرين باستخدام لغة SQL
</h2>

<p>
	نزّل السكريبت التالي: <a href="https://opentextbc.ca/dbdesign01/wp-content/uploads/sites/11/2014/06/ordersanddata.txt" rel="external nofollow">OrdersAndData.sql</a>.
</p>

<h3>
	الجزء الأول: استخدم لغة DDL
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93247" href="https://academy.hsoub.com/uploads/monthly_2022_03/ERDForOrdersAndData-(1).png.ba0cb15301f921e338d32fcea7db0efd.png" rel=""><img alt="ERDForOrdersAndData-(1).png" class="ipsImage ipsImage_thumbnailed" data-fileid="93247" data-unique="eih7w0s3j" src="https://academy.hsoub.com/uploads/monthly_2022_03/ERDForOrdersAndData-(1).thumb.png.d291b829eda5a1b9da7ce879703e5150.png" style="width: 650px; height: auto;"></a>
</p>

<ol>
<li>
		استخدم السكريبت orderData.sql الذي ينشئ جداولًا ويضيف بيانات مخطط ERD للطلبات والبيانات في الشكل السابق.
	</li>
	<li>
		أنشئ قاعدة بيانات تسمّى Orders، وعدّل السكريبت لدمج المفتاح الرئيسي PK والسلامة المرجعية referential integrity. استخدم عبارات <code>CREATE TABLE</code> مع التعديلات بما في ذلك القيود الموجودة في الخطوة 3.
	</li>
	<li>
		أضف القيود التالية:
	</li>
</ol>
<ul>
<li>
		tblCustomers table: Country (Canada قيمته الافتراضية هي)
	</li>
	<li>
		tblOrderDetails: Quantity – &gt; 0
	</li>
	<li>
		tblShippers: CompanyName (يجب أن يكون فريدًا)
	</li>
	<li>
		tblOrders: ShippedDate (order date يجب أن يكون أكبر تاريخ الطلب)
	</li>
</ul>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_263_19" style="">
<span class="pln">CREATE DATABASE </span><span class="typ">Orders</span><span class="pln">
</span><span class="typ">Go</span><span class="pln">
</span><span class="typ">Use</span><span class="pln"> </span><span class="typ">Orders</span><span class="pln">
</span><span class="typ">Go</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_263_21" style="">
<span class="typ">Use</span><span class="pln"> </span><span class="typ">Orders</span><span class="pln">
</span><span class="typ">Go</span><span class="pln">
CREATE TABLE </span><span class="pun">[</span><span class="pln">dbo</span><span class="pun">].[</span><span class="pln">tblCustomers</span><span class="pun">]</span><span class="pln">
</span><span class="pun">[</span><span class="typ">CustomerID</span><span class="pun">]</span><span class="pln">       nvarchar</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">CompanyName</span><span class="pun">]</span><span class="pln">      nvarchar</span><span class="pun">(</span><span class="lit">40</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ContactName</span><span class="pun">]</span><span class="pln">      nvarchar</span><span class="pun">(</span><span class="lit">30</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ContactTitle</span><span class="pun">]</span><span class="pln">     nvarchar</span><span class="pun">(</span><span class="lit">30</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Address</span><span class="pun">]</span><span class="pln">          nvarchar</span><span class="pun">(</span><span class="lit">60</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">City</span><span class="pun">]</span><span class="pln">             nvarchar</span><span class="pun">(</span><span class="lit">15</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Region</span><span class="pun">]</span><span class="pln">           nvarchar</span><span class="pun">(</span><span class="lit">15</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">PostalCode</span><span class="pun">]</span><span class="pln">       nvarchar</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Country</span><span class="pun">]</span><span class="pln">          nvarchar</span><span class="pun">(</span><span class="lit">15</span><span class="pun">)</span><span class="pln"> NULL
</span><span class="typ">Constraint</span><span class="pln">     df_country DEFAULT </span><span class="pun">‘</span><span class="typ">Canada</span><span class="pun">’,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Phone</span><span class="pun">]</span><span class="pln">            nvarchar</span><span class="pun">(</span><span class="lit">24</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Fax</span><span class="pun">]</span><span class="pln">              nvarchar</span><span class="pun">(</span><span class="lit">24</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Primary</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">CustomerID</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_263_23" style="">
<span class="pln">CREATE TABLE </span><span class="pun">[</span><span class="pln">dbo</span><span class="pun">].[</span><span class="pln">tblSupplier</span><span class="pun">]</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
</span><span class="pun">[</span><span class="typ">SupplierID</span><span class="pun">]</span><span class="pln">     </span><span class="kwd">int</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Name</span><span class="pun">]</span><span class="pln">           nvarchar</span><span class="pun">(</span><span class="lit">50</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Address</span><span class="pun">]</span><span class="pln">        nvarchar</span><span class="pun">(</span><span class="lit">50</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">City</span><span class="pun">]</span><span class="pln">           nvarchar</span><span class="pun">(</span><span class="lit">50</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Province</span><span class="pun">]</span><span class="pln">       nvarchar</span><span class="pun">(</span><span class="lit">50</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Primary</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">SupplierID</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_263_25" style="">
<span class="pln">CREATE TABLE </span><span class="pun">[</span><span class="pln">dbo</span><span class="pun">].[</span><span class="pln">tblShippers</span><span class="pun">]</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ShipperID</span><span class="pun">]</span><span class="pln">       </span><span class="kwd">int</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">CompanyName</span><span class="pun">]</span><span class="pln">     nvarchar</span><span class="pun">(</span><span class="lit">40</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Primary</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">ShipperID</span><span class="pun">),&lt;</span><span class="pln">
CONSTRAINT uc_CompanyName UNIQUE </span><span class="pun">(</span><span class="typ">CompanyName</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_263_27" style="">
<span class="pln">CREATE TABLE </span><span class="pun">[</span><span class="pln">dbo</span><span class="pun">].[</span><span class="pln">tblProducts</span><span class="pun">]</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ProductID</span><span class="pun">]</span><span class="pln">           </span><span class="kwd">int</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">SupplierID</span><span class="pun">]</span><span class="pln">          </span><span class="kwd">int</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">CategoryID</span><span class="pun">]</span><span class="pln">          </span><span class="kwd">int</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ProductName</span><span class="pun">]</span><span class="pln">         nvarchar</span><span class="pun">(</span><span class="lit">40</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">EnglishName</span><span class="pun">]</span><span class="pln">         nvarchar</span><span class="pun">(</span><span class="lit">40</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">QuantityPerUnit</span><span class="pun">]</span><span class="pln">     nvarchar</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">UnitPrice</span><span class="pun">]</span><span class="pln">           money NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">UnitsInStock</span><span class="pun">]</span><span class="pln">        smallint NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">UnitsOnOrder</span><span class="pun">]</span><span class="pln">        smallint NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ReorderLevel</span><span class="pun">]</span><span class="pln">        smallint NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Discontinued</span><span class="pun">]</span><span class="pln">        bit NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Primary</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">ProductID</span><span class="pun">),</span><span class="pln">
</span><span class="typ">Foreign</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">SupplierID</span><span class="pun">)</span><span class="pln"> </span><span class="typ">References</span><span class="pln"> tblSupplier
</span><span class="pun">);</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_263_29" style="">
<span class="pln">CREATE TABLE </span><span class="pun">[</span><span class="pln">dbo</span><span class="pun">].[</span><span class="pln">tblOrders</span><span class="pun">]</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
</span><span class="pun">[</span><span class="typ">OrderID</span><span class="pun">]</span><span class="pln">            </span><span class="kwd">int</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">CustomerID</span><span class="pun">]</span><span class="pln">         nvarchar</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">EmployeeID</span><span class="pun">]</span><span class="pln">         </span><span class="kwd">int</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ShipName</span><span class="pun">]</span><span class="pln">           nvarchar</span><span class="pun">(</span><span class="lit">40</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ShipAddress</span><span class="pun">]</span><span class="pln">        nvarchar</span><span class="pun">(</span><span class="lit">60</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ShipCity</span><span class="pun">]</span><span class="pln">           nvarchar</span><span class="pun">(</span><span class="lit">15</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ShipRegion</span><span class="pun">]</span><span class="pln">         nvarchar</span><span class="pun">(</span><span class="lit">15</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ShipPostalCode</span><span class="pun">]</span><span class="pln">     nvarchar</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ShipCountry</span><span class="pun">]</span><span class="pln">        nvarchar</span><span class="pun">(</span><span class="lit">15</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ShipVia</span><span class="pun">]</span><span class="pln">            </span><span class="kwd">int</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">OrderDate</span><span class="pun">]</span><span class="pln">          smalldatetime NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">RequiredDate</span><span class="pun">]</span><span class="pln">       smalldatetime NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ShippedDate</span><span class="pun">]</span><span class="pln">        smalldatetime NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Freight</span><span class="pun">]</span><span class="pln">            money NULL
</span><span class="typ">Primary</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">OrderID</span><span class="pun">),</span><span class="pln">
</span><span class="typ">Foreign</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">CustomerID</span><span class="pun">)</span><span class="pln"> </span><span class="typ">References</span><span class="pln"> tblCustomers</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Foreign</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">ShipVia</span><span class="pun">)</span><span class="pln"> </span><span class="typ">References</span><span class="pln"> tblShippers</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Constraint</span><span class="pln"> valid_ShipDate CHECK </span><span class="pun">(</span><span class="typ">ShippedDate</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">OrderDate</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_263_31" style="">
<span class="pln">CREATE TABLE </span><span class="pun">[</span><span class="pln">dbo</span><span class="pun">].[</span><span class="pln">tblOrderDetails</span><span class="pun">]</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
</span><span class="pun">[</span><span class="typ">OrderID</span><span class="pun">]</span><span class="pln">       </span><span class="kwd">int</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">ProductID</span><span class="pun">]</span><span class="pln">     </span><span class="kwd">int</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">UnitPrice</span><span class="pun">]</span><span class="pln">     money NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Quantity</span><span class="pun">]</span><span class="pln">      smallint NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Discount</span><span class="pun">]</span><span class="pln">      real NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Primary</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">OrderID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ProductID</span><span class="pun">),</span><span class="pln">
</span><span class="typ">Foreign</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">OrderID</span><span class="pun">)</span><span class="pln"> </span><span class="typ">References</span><span class="pln"> tblOrders</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Foreign</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">ProductID</span><span class="pun">)</span><span class="pln"> </span><span class="typ">References</span><span class="pln"> tblProducts</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Constraint</span><span class="pln"> </span><span class="typ">Valid_Qty</span><span class="pln"> </span><span class="typ">Check</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Quantity</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">
</span><span class="typ">Go</span></pre>

<h3>
	الجزء الثاني: إنشاء عبارات لغة SQL
</h3>

<ol>
<li>
		اعرض قائمة العملاء customers والطلبات orders المُنشَأة خلال عام 2014. أظهر الحقول customer ID و order ID و order date و date ordered.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_263_33" style="">
<span class="typ">Use</span><span class="pln"> </span><span class="typ">Orders</span><span class="pln">
</span><span class="typ">Go</span><span class="pln">
SELECT </span><span class="typ">CompanyName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">OrderID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">RequiredDate</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">order date</span><span class="pun">’,</span><span class="pln"> </span><span class="typ">OrderDate</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">date ordered</span><span class="pun">’</span><span class="pln">
FROM tblcustomers  JOIN tblOrders on tblOrders</span><span class="pun">.</span><span class="typ">CustomerID</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> tblCustomers</span><span class="pun">.</span><span class="typ">CustomerID</span><span class="pln">
WHERE </span><span class="typ">Year</span><span class="pun">(</span><span class="typ">OrderDate</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2014</span></pre>

<ol start="2">
<li>
		أضف حقلًا جديدًا (نشطًا) في جدول tblCustomer باستخدام عبارة <code>ALTER TABLE</code>، حيث تكون قيمته الافتراضية True.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_263_35" style="">
<span class="pln">ALTER TABLE tblCustomers
ADD </span><span class="typ">Active</span><span class="pln"> bit DEFAULT </span><span class="pun">(‘</span><span class="typ">True</span><span class="pun">’)</span></pre>

<ol start="3">
<li>
		اعرض جميع الطلبات التي جرى شراؤها قبل 1 سبتمبر 2012 (اعرض الحقول company name و date ordered وكلفة الطلب الإجمالية (بما في ذلك تكلفة الشحن freight).
	</li>
</ol>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_263_37" style="">
<span class="pln">SELECT tblOrders</span><span class="pun">.</span><span class="typ">OrderID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">OrderDate</span><span class="pln"> as </span><span class="pun">‘</span><span class="typ">Date</span><span class="pln"> </span><span class="typ">Ordered</span><span class="pun">’,</span><span class="pln"> sum</span><span class="pun">(</span><span class="pln">unitprice</span><span class="pun">*</span><span class="pln">quantity</span><span class="pun">*(</span><span class="lit">1</span><span class="pun">-</span><span class="pln">discount</span><span class="pun">))+</span><span class="pln"> freight as </span><span class="pun">‘</span><span class="typ">Total</span><span class="pln"> </span><span class="typ">Cost</span><span class="pun">’</span><span class="pln">
FROM tblOrderDetails join tblOrders on tblOrders</span><span class="pun">.</span><span class="pln">orderID </span><span class="pun">=</span><span class="pln"> tblOrderDetails</span><span class="pun">.</span><span class="typ">OrderID</span><span class="pln">
WHERE </span><span class="typ">OrderDate</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">September</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2012</span><span class="pun">’</span><span class="pln">
GROUP BY tblOrders</span><span class="pun">.</span><span class="typ">OrderID</span><span class="pun">,</span><span class="pln"> freight</span><span class="pun">,</span><span class="pln"> </span><span class="typ">OrderDate</span></pre>

<ol start="4">
<li>
		اعرض جميع الطلبات المشحونة عبر شركة Federal Shipping (اعرض الحقول OrderID و ShipName و ShipAddress و CustomerID).
	</li>
</ol>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_263_40" style="">
<span class="pln">SELECT </span><span class="typ">OrderID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ShipName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ShipAddress</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CustomerID</span><span class="pln">
FROM tblOrders join tblShippers on tblOrders</span><span class="pun">.</span><span class="typ">ShipVia</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> tblShippers</span><span class="pun">.</span><span class="typ">ShipperID</span><span class="pln">
WHERE </span><span class="typ">CompanyName</span><span class="pun">=</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Federal</span><span class="pln"> </span><span class="typ">Shipping</span><span class="pun">’</span></pre>

<ol start="5">
<li>
		اعرض جميع العملاء الذين لم يشتروا في عام 2011.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_263_42" style="">
<span class="pln">SELECT </span><span class="typ">CompanyName</span><span class="pln">
FROM tblCustomers
WHERE </span><span class="typ">CustomerID</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln">
</span><span class="pun">(</span><span class="pln">  SELECT </span><span class="typ">CustomerID</span><span class="pln">
FROM  tblOrders
WHERE </span><span class="typ">Year</span><span class="pun">(</span><span class="typ">OrderDate</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2011</span><span class="pln">
</span><span class="pun">)</span></pre>

<ol start="6">
<li>
		اعرض جميع المنتجات التي لم تُطلَب أبدًا.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_263_44" style="">
<span class="pln">SELECT </span><span class="typ">ProductID</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> tblProducts
</span><span class="typ">Except</span><span class="pln">
SELECT </span><span class="typ">ProductID</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> tblOrderDetails</span></pre>

<p>
	أو يمكن حل ذلك بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_263_46" style="">
<span class="pln">SELECT </span><span class="typ">Products</span><span class="pun">.</span><span class="typ">ProductID</span><span class="pun">,</span><span class="typ">Products</span><span class="pun">.</span><span class="typ">ProductName</span><span class="pln">
FROM </span><span class="typ">Products</span><span class="pln"> LEFT JOIN </span><span class="pun">[</span><span class="typ">Order</span><span class="pln"> </span><span class="typ">Details</span><span class="pun">]</span><span class="pln">
ON </span><span class="typ">Products</span><span class="pun">.</span><span class="typ">ProductID</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="typ">Order</span><span class="pln"> </span><span class="typ">Details</span><span class="pun">].</span><span class="typ">ProductID</span><span class="pln">
WHERE </span><span class="pun">[</span><span class="typ">Order</span><span class="pln"> </span><span class="typ">Details</span><span class="pun">].</span><span class="typ">OrderID</span><span class="pln"> IS NULL</span></pre>

<ol start="7">
<li>
		اعرض معرّفات الطلبات OrderID للزبائن الذين يقيمون في لندن باستخدام استعلام فرعي (اعرض الحقول CustomerID و CustomerName و OrderID).
	</li>
</ol>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_263_48" style="">
<span class="pln">SELECT </span><span class="typ">Customers</span><span class="pun">.</span><span class="typ">CompanyName</span><span class="pun">,</span><span class="typ">Customers</span><span class="pun">.</span><span class="typ">CustomerID</span><span class="pun">,</span><span class="typ">OrderID</span><span class="pln">
FROM </span><span class="typ">Orders</span><span class="pln">
LEFT JOIN </span><span class="typ">Customers</span><span class="pln"> ON </span><span class="typ">Orders</span><span class="pun">.</span><span class="typ">CustomerID</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Customers</span><span class="pun">.</span><span class="typ">CustomerID</span><span class="pln">
WHERE </span><span class="typ">Customers</span><span class="pun">.</span><span class="typ">CompanyName</span><span class="pln"> IN
</span><span class="pun">(</span><span class="pln">SELECT </span><span class="typ">CompanyName</span><span class="pln">
FROM </span><span class="typ">Customers</span><span class="pln">
WHERE </span><span class="typ">City</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">London</span><span class="pun">’)</span></pre>

<ol start="8">
<li>
		اعرض المنتجات التي يوفّرها الموّرد A والموّرد B (اعرض الحقول product name و supplier name).
	</li>
</ol>
<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_263_50" style="">
<span class="pln">SELECT </span><span class="typ">ProductName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Name</span><span class="pln">
FROM tblProducts JOIN tblSupplier on tblProducts</span><span class="pun">.</span><span class="typ">SupplierID</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> tblSupplier</span><span class="pun">.</span><span class="typ">SupplierID</span><span class="pln">
WHERE </span><span class="typ">Name</span><span class="pln"> </span><span class="typ">Like</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Supplier</span><span class="pln"> A</span><span class="pun">’</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"> </span><span class="typ">Like</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Supplier</span><span class="pln"> B</span><span class="pun">’</span></pre>

<ol start="9">
<li>
		اعرض جميع المنتجات التي تأتي ضمن صناديق (اعرض الحقول product name و QuantityPerUnit).
	</li>
</ol>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_263_52" style="">
<span class="pln">SELECT </span><span class="typ">EnglishName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ProductName</span><span class="pun">,</span><span class="pln">  </span><span class="typ">QuantityPerUnit</span><span class="pln">
FROM tblProducts
WHERE </span><span class="typ">QuantityPerUnit</span><span class="pln"> like </span><span class="pun">‘%</span><span class="pln">box</span><span class="pun">%’</span><span class="pln">
ORDER BY </span><span class="typ">EnglishName</span></pre>

<h3>
	الجزء الثالث: الإدخال Insert والتعديل Update والحذف Delete والفهارس Indexes
</h3>

<ol>
<li>
		أنشئ جدول الموظفين Employee. يجب أن يكون المفتاح الرئيسي هو معرّف الموظف EmployeeID وهو حقل ترقيم تلقائي autonumber. أضف الحقول التالية: LastName و FirstName و Address و City و Province و Postalcode و Phone و Salary. استخدم عبارة إنشاء جدول <code>CREATE TABLE</code> وعبارات إدخال <code>INSERT</code> خمسة موظفين. ضم جدول الموظفين employee إلى الجدول Tblorders. اعرض السكريبت لإنشاء الجدول وإعداد القيود وإضافة الموظفين.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_263_54" style="">
<span class="typ">Use</span><span class="pln"> </span><span class="typ">Orders</span><span class="pln">
CREATE TABLE </span><span class="pun">[</span><span class="pln">dbo</span><span class="pun">].[</span><span class="pln">tblEmployee</span><span class="pun">](</span><span class="pln">
</span><span class="typ">EmployeeID</span><span class="pln"> </span><span class="typ">Int</span><span class="pln"> IDENTITY NOT NULL </span><span class="pun">,</span><span class="pln">
</span><span class="typ">FirstName</span><span class="pln"> varchar </span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">LastName</span><span class="pln"> varchar </span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Address</span><span class="pln"> varchar </span><span class="pun">(</span><span class="lit">50</span><span class="pun">),</span><span class="pln">
</span><span class="typ">City</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">20</span><span class="pun">),</span><span class="pln"> </span><span class="typ">Province</span><span class="pln"> varchar </span><span class="pun">(</span><span class="lit">50</span><span class="pun">),</span><span class="pln">
</span><span class="typ">PostalCode</span><span class="pln"> </span><span class="kwd">char</span><span class="pun">(</span><span class="lit">6</span><span class="pun">),</span><span class="pln">
</span><span class="typ">Phone</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> </span><span class="pun">(</span><span class="lit">10</span><span class="pun">),</span><span class="pln">
</span><span class="typ">Salary</span><span class="pln"> </span><span class="typ">Money</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln">
</span><span class="typ">Primary</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">EmployeeID</span><span class="pun">)</span></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_263_58" style="">
<span class="typ">Go</span><span class="pln">
INSERT into tblEmployees
</span><span class="typ">Values</span><span class="pln"> </span><span class="pun">(‘</span><span class="typ">Jim</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Smith</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">123</span><span class="pln"> </span><span class="typ">Fake</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Terrace</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">BC</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">V8G5J6</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">2506155989</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">20.12</span><span class="pun">’),</span><span class="pln">
</span><span class="pun">(‘</span><span class="typ">Jimmy</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Smithy</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">124</span><span class="pln"> </span><span class="typ">Fake</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Terrace</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">BC</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">V8G5J7</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">2506155984</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">21.12</span><span class="pun">’),</span><span class="pln">
</span><span class="pun">(‘</span><span class="typ">John</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Smore</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">’</span><span class="lit">13</span><span class="pln"> </span><span class="typ">Fake</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Terrace</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">BC</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">V4G5J6</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">2506115989</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">19.12</span><span class="pun">’),</span><span class="pln">
</span><span class="pun">(‘</span><span class="typ">Jay</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Sith</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">’</span><span class="lit">12</span><span class="pln"> </span><span class="typ">Fake</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Terrace</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">BC</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">V8G4J6</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">2506155939</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">25.12</span><span class="pun">’),</span><span class="pln">
</span><span class="pun">(‘</span><span class="typ">Jig</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Mith</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">’</span><span class="lit">23</span><span class="pln"> </span><span class="typ">Fake</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="typ">Terrace</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">BC</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">V8G5J5</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">2506455989</span><span class="pun">’,</span><span class="pln"> </span><span class="pun">‘</span><span class="lit">18.12</span><span class="pun">’);</span><span class="pln">
</span><span class="typ">Go</span></pre>

<ol start="2">
<li>
		أضف حقلًا يسمّى Totalsales إلى جدول Tblorders. استخدم تعليمات لغة DDL وعبارة <code>ALTER TABLE</code>.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_263_60" style="">
<span class="pln">ALTER TABLE tblOrders
ADD </span><span class="typ">Foreign</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">(</span><span class="typ">EmployeeID</span><span class="pun">)</span><span class="pln"> references tblEmployees </span><span class="pun">(</span><span class="typ">EmployeeID</span><span class="pun">)</span></pre>

<ol start="3">
<li>
		استخدم عبارة <code>UPDATE</code> لإضافة مجموع مبيعات كل طلب بناءً على جدول تفاصيل الطلب order details.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_263_62" style="">
<span class="pln">UPDATE tblOrders
</span><span class="typ">Set</span><span class="pln"> </span><span class="typ">TotalSales</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">select sum</span><span class="pun">(</span><span class="pln">unitprice</span><span class="pun">*</span><span class="pln">quantity</span><span class="pun">*(</span><span class="lit">1</span><span class="pun">-</span><span class="pln">discount</span><span class="pun">))</span><span class="pln">
FROM tblOrderDetails
WHERE tblOrderDetails</span><span class="pun">.</span><span class="typ">OrderID</span><span class="pun">=</span><span class="pln"> tblOrders</span><span class="pun">.</span><span class="typ">OrderID</span><span class="pln">
GROUP BY </span><span class="typ">OrderID</span></pre>

<p>
	ترجمة -وبتصرف- للمقالات:
</p>

<ul>
<li>
		<a href="https://opentextbc.ca/dbdesign01/back-matter/appendix-a-university-registration-data-model-example/" rel="external nofollow">Appendix A University Registration Data Model Example</a>
	</li>
	<li>
		<a href="https://opentextbc.ca/dbdesign01/back-matter/appendix-b-erd-exercises/" rel="external nofollow">Appendix B Sample ERD Exercises</a>
	</li>
	<li>
		<a href="https://opentextbc.ca/dbdesign01/back-matter/appendix-d-sql-lab-with-solution/" rel="external nofollow">Appendix C SQL Lab with Solution</a> 
	</li>
</ul>
<p>
	لـ Adrienne Watt و Nelson Eng
</p>

<h2>
	اقرأ أيضًا:
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/sql/%D9%84%D8%BA%D8%A9-%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-dml-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-sql-r1369/" rel="">لغة معالجة البيانات DML الخاصة بلغة SQL</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D9%84%D8%BA%D8%A9-%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-dml-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-sql-r1369/" rel="">لغة معالجة البيانات DML الخاصة بلغة SQL</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D9%8A-er-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r545/" rel="">نمذجة الكيان العلاقي ER عند تصميم قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B3%D8%B1%D9%8A%D8%B9%D8%A9-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%87%D9%8A%D9%83%D9%84%D9%8A%D8%A9-sql-r1368/" rel="">نظرة سريعة على لغة الاستعلامات الهيكلية </a><a href="https://academy.hsoub.com/programming/sql/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B3%D8%B1%D9%8A%D8%B9%D8%A9-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%87%D9%8A%D9%83%D9%84%D9%8A%D8%A9-sql-r1368/" rel="">SQL</a>
	</li>
	<li>
		النسخة العربية الكاملة لكتاب <a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تصميم قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">597</guid><pubDate>Mon, 28 Mar 2022 16:03:00 +0000</pubDate></item><item><title>&#x639;&#x645;&#x644;&#x64A;&#x629; &#x62A;&#x637;&#x648;&#x64A;&#x631; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; Database Development</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database-development-r553/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/618a0afb01324_---.png.5dfc7677d248a272d6c1cd3ae1993945.png" /></p>

<p>
	يتمثل أحد الجوانب الأساسية لهندسة البرمجيات في تقسيم عملية التطوير إلى سلسلة من المراحل أو الخطوات، حيث تركِّز كل مرحلة منها على جانب واحد من جوانب التطوير.
</p>

<p>
	يشار أحيانًا إلى مجموعة هذه الخطوات بدورة حياة تطوير البرمجيات software development life cycle -أو SDLC اختصارًا-، حيث ينتقل المنتج البرمجي عبر مراحل دورة الحياة هذه -في بعض الأحيان بصورة متكررة أثناء ضبطه أو إعادة تطويره- حتى يتوقف استخدامه في النهاية، كما يمكن التحقق من كل مرحلة في دورة الحياة للتأكد من صحتها قبل الانتقال إلى المرحلة التالية في الحالة المثالية.
</p>

<h2>
	دورة حياة تطوير البرمجيات: نموذج الشلال Waterfall
</h2>

<p>
	لنبدأ بإلقاء نظرة عامة على نموذج الشلال waterfall model الذي هو أحد نماذج تمثيل دورة حياة عملية تطوير البرمجيات Software Development Life Cycle كما ستجده في معظم كتب هندسة البرمجيات.
</p>

<p>
	يوضح هذا الشكل الشلالي الموجود في الشكل الآتي نموذج شلال عام يمكن تطبيقه على أية عملية تطوير لنظام حاسوبي، حيث يُظهِر هذا النموذج العملية على أساس تسلسل صارم من الخطوات بأن يكون خرج خطوة واحدة دخلًا للخطوة التالية، كما يجب إكمال كل خطوة قبل الانتقال إلى الخطوة التالية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="94001" href="https://academy.hsoub.com/uploads/monthly_2022_03/WaterfallModel-1.thumb.png.645685aa90159eaf96d08f951ad1b85e.png" rel=""><img alt="WaterfallModel-1.thumb.png" class="ipsImage ipsImage_thumbnailed" data-fileid="94001" data-unique="zrn2sqt28" src="https://academy.hsoub.com/uploads/monthly_2022_03/WaterfallModel-1.thumb.thumb.png.3f88e3976874c433a77ff8236a0ceb0c.png" style="width: 400px; height: auto;"></a>
</p>

<p>
	يمكننا استخدام عملية نموذج الشلال على أساس وسيلة لتحديد المهام المطلوبة مع دخل وخرج كل نشاط activity.
</p>

<p>
	المهم هنا هو مجالات الأنشطة التي يمكن تلخيصها على النحو التالي:
</p>

<ul>
<li>
		تتضمن مرحلة إنشاء المتطلبات Establishing requirements التشاور والاتفاق مع أصحاب المصلحة حول ما يريدونه من النظام، ويُعبَّر عنها بما يسمَّى وثيقة المتطلبات statement of requirements.
	</li>
	<li>
		تبدأ مرحلة التحليل Analysis بالنظر في وثيقة المتطلبات وتنتهي من خلال إنتاج مواصفات النظام system specification، حيث تُعَدّ المواصفات تمثيلًا رسميًا لما يجب على النظام فعله، ويُعبَّر عنها بعبارات مستقلة عن كيفية تطبيقها.
	</li>
	<li>
		تبدأ مرحلة التصميم Design بمواصفات النظام وينتج عنها وثائق التصميم، كما تقدِّم هذه المرحلة وصفًا تفصيليًا لكيفية بناء النظام.
	</li>
	<li>
		مرحلة التطبيق Implementation هي بناء نظام حاسوبي وفقًا لوثيقة تصميم معينة مع مراعاة البيئة التي سيعمل فيها النظام، مثل العتاد، والبرمجيات المتاحة للتطوير؛ كما قد تُنفَّذ مرحلة التطبيق على مراحل باستخدام نظام أولي يمكن التحقق من صحته واختباره قبل إصدار النظام النهائي للاستخدام.
	</li>
	<li>
		توازن مرحلة الاختبار Testing النظام المُطبَّق مع وثائق التصميم ومواصفات المتطلبات، وتنتج هذه المرحلة تقرير قبول، أو قائمةً بالأخطاء والزلات البرمجية bugs التي تتطلب مراجعة عمليات التحليل، والتصميم، والتطبيق لتصحيحها، أي تُعَدّ مرحلة الاختبار عادةً المَهمة التي تؤدي إلى تكرار نموذج الشلال خلال دورة الحياة.
	</li>
	<li>
		تتضمن مرحلة الصيانة Maintenance التعامل مع تغيرات المتطلبات، أو بيئة التطبيق، أو إصلاح الزلات البرمجية، أو نقل النظام إلى بيئات جديدة مثل ترحيل نظام من حاسوب مستقل إلى محطة عمل يونكس أو بيئة متصلة <a href="https://academy.hsoub.com/devops/networking/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8%D9%8A%D8%A9-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%B9%D8%A7%D9%84%D9%85%D9%8A%D8%A9-r548/" rel="">بالشبكة</a>، كما سيعاد النظر في دورة حياة الشلال بصورة متكررة بسبب احتواء مرحلة الصيانة على تحليل التغيرات المطلوبة، وتصميم حل، وتطبيقه، واختباره على مدى حياة نظام برمجي جرت صيانته.
	</li>
</ul>
<h2>
	دورة حياة قاعدة البيانات Database Life Cycle
</h2>

<p>
	يمكننا استخدام دورة الشلال مثل أساس لنموذج تطوير <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">قاعدة البيانات</a> الذي يتضمن ثلاثة افتراضات، هي:
</p>

<ol>
<li>
		يمكننا فصل تطوير قاعدة البيانات عن عمليات المستخدم التي تستخدم قاعدة البيانات، أي تحديد وإنشاء تخطيط schema لتعريف البيانات في <a href="https://academy.hsoub.com/devops/servers/databases/%D8%AE%D8%B5%D8%A7%D8%A6%D8%B5-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D8%B2%D8%A7%D9%8A%D8%A7-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D9%82%D8%AF%D9%85%D9%87%D8%A7-r520/" rel="">قاعدة البيانات</a>.
	</li>
	<li>
		يمكننا استخدام معمارية التخطيطات الثلاثة three-schema architecture مثل أساس لتمييز الأنشطة المرتبطة بالتخطيط.
	</li>
	<li>
		يمكننا تمثيل القيود constraints لفرض دلالات semantics البيانات مرةً واحدةً في قاعدة البيانات عوضًا عن فرضها على كل عملية مستخدِم تستخدِم البيانات.
	</li>
</ol>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="94002" href="https://academy.hsoub.com/uploads/monthly_2022_03/AWaterfallModelOfTheActivitiesAndTheirOutputsForDatabaseDevelopment.thumb.png.png.6466c417a65d54a3b255a0fb2290ef1c.png" rel=""><img alt="AWaterfallModelOfTheActivitiesAndTheirOutputsForDatabaseDevelopment.thumb.png.png" class="ipsImage ipsImage_thumbnailed" data-fileid="94002" data-unique="9ni4ekik7" src="https://academy.hsoub.com/uploads/monthly_2022_03/AWaterfallModelOfTheActivitiesAndTheirOutputsForDatabaseDevelopment.thumb.png.thumb.png.83ef00992a97a79a78b99272172bd09e.png" style="width: 400px; height: auto;"></a>
</p>

<p>
	يمكننا باستخدام هذه الافتراضات والشكل السابق رؤية أنّ هذا المخطط يمثِّل نموذجًا للأنشطة وخرجها لتطوير قاعدة البيانات، فهذا المخطط ليس قابلًا للتطبيق على النهج العلائقي فقط وإنما يُطبَّق على أية صنف class من نظم إدارة قواعد البيانات DBMS أيضًا.
</p>

<p>
	يُعَدّ تطوير تطبيقات قواعد البيانات عمليةً للحصول على متطلبات العالم الحقيقي real-world، وتحليل المتطلبات، وتصميم البيانات ووظائف النظام، ثم تطبيق العمليات في النظام.
</p>

<h2>
	جمع المتطلبات Requirements Gathering
</h2>

<p>
	تُعَدّ مرحلة جمع المتطلبات requirements gathering الخطوة الأولى في نموذج الشلال، ويجب على مصممي قاعدة البيانات خلال هذه الخطوة إجراء مقابلات مع العملاء -أي مستخدمي قاعدة البيانات- لفهم النظام المقترح والحصول على البيانات والمتطلبات الوظيفية، وتوثيقها، كما تكون نتيجة هذه الخطوة وثيقةً تتضمن المتطلبات التفصيلية التي قدمها المستخدِمون.
</p>

<p>
	تتضمن مرحلة إنشاء المتطلبات Establishing requirements التشاور والاتفاق بين جميع المستخدِمين بشأن البيانات الثابتة persistent data التي يرغبون في تخزينها مع الاتفاق على معنى عناصر البيانات وتفسيرها، كما يلعب مسؤول البيانات دورًا رئيسيًا في هذه العملية لأنه يستعرِض القضايا التجارية، والقانونية، والأخلاقية داخل المؤسسة التي تؤثِّر على متطلبات البيانات.
</p>

<p>
	تُستخدَم وثيقة متطلبات البيانات data requirements document لتأكيد فهم المتطلبات مع المستخدِمين، فلا ينبغي أن تكون رسميةً أو مشفرةً بمستوى عالٍ لضمان سهولة فهمها.
</p>

<p>
	يجب أن تقدِّم هذه الوثيقة ملخصًا موجزًا لمتطلبات جميع المستخدِمين -أي ليس مجرد مجموعة من الأفراد فقط-، وذلك لأنّ الهدف هو تطوير قاعدة بيانات مشتركة واحدة.
</p>

<p>
	يجب ألا تصِف المتطلبات كيفية معالجة البيانات، بل تصف عناصر البيانات، والسِمات attributes التي تمتلكها، والقيود المطبَّقة، والعلاقات التي تربط بين عناصر البيانات.
</p>

<h2>
	التحليل Analysis
</h2>

<p>
	تبدأ مرحلة تحليل البيانات Data analysis بوثيقة متطلبات البيانات، ثم ينتج عنها نموذج بيانات مفاهيمي conceptual data model. الهدف من التحليل هو الحصول على وصف تفصيلي للبيانات التي ستناسب متطلبات المستخدِم، بحيث يجري التعامل مع خصائص البيانات ذات المستوى العالي والمنخفض واستخدامها. تتضمن هذه الخصائص المجال المحتمل من القيم التي يمكن السماح بها للسمات، مثل: رمز مقررات الطالب student course code، وعنوان المقرر course title، ونقاط الائتمان credit points في قاعدة بيانات المدرسة على سبيل المثال.
</p>

<p>
	يوفِّر نموذج البيانات المفاهيمي تمثيلًا رسميًا مشتركًا لما يجري توصيله بين العملاء والمطورين أثناء تطوير قاعدة البيانات، فهذا النموذج يركز على البيانات في قاعدة البيانات، بغض النظر عن الاستخدام النهائي لتلك البيانات في عمليات المستخدِم، أو تطبيق البيانات في بيئات حاسوبية محدَّدة، لذلك يهتم نموذج البيانات المفاهيمي بمعنى البيانات وبنيتها، وليس بالتفاصيل التي تؤثر على كيفية تطبيقها.
</p>

<p>
	إذًا يُعَدّ نموذج البيانات المفاهيمي تمثيلًا رسميًا للبيانات التي يجب أن تحتويها قاعدة البيانات، والقيود التي يجب على البيانات تلبيتها، كما يجب التعبير عن ذلك بمصطلحات مستقلة عن كيفية تنفيذ النموذج، لذلك يركِّز التحليل على الأسئلة التي تحتوي عبارات مثل عبارة "ما هو المطلوب؟" وليس على الأسئلة التي تحتوي عبارات مثل عبارة "كيف يتحقق ذلك؟".
</p>

<h2>
	التصميم المنطقي Logical Design
</h2>

<p>
	تبدأ مرحلة تصميم قاعدة البيانات بنموذج بيانات مفاهيمي وينتج عنها مواصفات التخطيط المنطقي logical schema الذي سيحدِّد نوع نظام قاعدة البيانات المطلوب -أي نوع شبكي، أو علائقي، أو كائني التوجه-.
</p>

<p>
	لا يزال التمثيل العلائقي relational representation مستقلًا عن أي نظام إدارة قواعد البيانات DBMS، فهو نموذج بيانات مفاهيمي آخر.
</p>

<p>
	يمكننا استخدام التمثيل العلائقي لنموذج البيانات المفاهيمي على أساس دخلٍ لعملية التصميم المنطقي، وخرج هذه المرحلة هو <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D8%A9-er-%D9%84%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r543/" rel="">مواصفات علائقية</a> مفصَّلة أي تخطيط منطقي لجميع الجداول والقيود اللازمة لتلبية وصف البيانات في نموذج البيانات المفاهيمي.
</p>

<p>
	تُختار الجداول الأكثر ملاءمة أثناء نشاط التصميم لتمثيل البيانات في قاعدة بيانات، ولكن يجب أخذ هذه الاختيارات في الحسبان معايير التصميم المختلفة بما في ذلك على سبيل المثال مرونة التغيير، والتحكم في التضاعف أو الاستنساخ duplication، وأفضل طريقة لتمثيل القيود. تحدِّد الجداول المحدَّدة بالتخطيط المنطقي البيانات المخزَّنة وكيفية معالجتها في قاعدة البيانات.
</p>

<p>
	يتجه مصممو قواعد البيانات الملمّون ب<a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D9%8A-er-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r545/" rel="">قواعد البيانات العلائقية</a> و<a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D9%85%D8%AA%D9%82%D8%AF%D9%85-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-sql-r961/" rel="">لغة الاستعلامات الهيكلية SQL</a> للذهاب مباشرةً إلى مرحلة التطبيق بعد إنتاج نموذج البيانات المفاهيمي، لكن لا يؤدي مثل هذا التحول المباشر<a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D8%A7%D8%AA-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D9%81%D9%8A-sql-r590/" rel=""> للتمثيل العلائقي إلى جداول SQL</a> بالضرورة إلى قاعدة بيانات تحتوي على جميع الخصائص المرغوبة، مثل: الكمال completeness، والسلامة integrity، والمرونة flexibility، والكفاءة efficiency، وقابلية الاستخدام usability.
</p>

<p>
	يُعَدّ نموذج البيانات المفاهيمي الجيد خطوةً أولى أساسية نحو قاعدة بيانات لها هذه الخصائص، لكن لا يعني هذا أنّ التحول المباشر إلى <a href="https://academy.hsoub.com/programming/sql/%D8%AA%D8%AD%D8%AF%D9%8A%D8%AB-%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D9%81%D9%8A-sql-r850/" rel="">جداول SQL</a> ينتج قاعدة بيانات جيدة تلقائيًا.
</p>

<p>
	ستمثل هذه الخطوة الأولى بدقة الجداول والقيود اللازمة لتلبية وصف نموذج البيانات المفاهيمي، وبالتالي ستلبي متطلبات الكمال والسلامة، ولكنها قد تكون غير مرنة، أو قد تقدِّم قابلية استخدام ضعيفة، يُثنَى flexed التصميم الأول بعد ذلك لتحسين جودة تصميم قاعدة البيانات، ويهدف مصطلح الثني Flexing إلى أخذ الأفكار المتزامنة من شيء مثني لغرض مختلف وتشذيب جوانب من هذا الشيء- أي الوصول إلى الغاية نفسها بطريقة وفكرة أخرى تحقق المقصود-.
</p>

<p>
	يلخص الشكل الآتي الخطوات التكرارية الموجودة في تصميم قاعدة البيانات بناءً على النظرة العامة المقدَّمة، كما يكون الغرض الرئيسي من هذا الشكل هو التمييز بين الهدف العام للجداول التي يجب استخدامها عن التعريف المفصَّل للأجزاء المكوِّنة لكل جدول، حيث تُدرَس هذه الجداول واحدًا تلو الآخر رغم أنها ليست مستقِلةً عن بعضها البعض، كما سيؤدي كل تكرار يتضمّن مراجعةً للجداول إلى تصميم جديد، ويشار إلى هذه التصاميم الجديدة معًا باسم تصاميم القطع الثاني second-cut designs حتى لو تكررت العملية لأكثر من حلقةٍ واحدة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="94003" href="https://academy.hsoub.com/uploads/monthly_2022_03/CourseToEnrollment.thumb.png.18c54e79ac507c6a72631d766dc6f850.png" rel=""><img alt="CourseToEnrollment.thumb.png" class="ipsImage ipsImage_thumbnailed" data-fileid="94003" data-unique="l29wokaqg" src="https://academy.hsoub.com/uploads/monthly_2022_03/CourseToEnrollment.thumb.thumb.png.e6f69955dcf7826118cba57f192bf940.png" style="width: 600px; height: auto;"></a>
</p>

<p>
	أولًا، ليس من الضروري تلبية جميع متطلبات المستخدم التي يمثلها نموذج بيانات مفاهيمي معين بواسطة قاعدة بيانات واحدة، كما يوجد أسباب مختلفة لتطوير أكثر من قاعدة بيانات، مثل: الحاجة إلى عملية مستقِلة في مواقع مختلفة، أو التحكم الإداري ببيانات قواعد البيانات، لكن إذا احتوت مجموعة قواعد البيانات على بيانات مضاعَفة وكان المستخدِمون بحاجة للوصول إلى البيانات في أكثر من قاعدة بيانات، فهناك أسباب محتملة لتلبِّي قاعدة بيانات واحدة متطلبات متعددة، وإلا فيجب فحص المشاكل المتعلقة بمضاعَفة البيانات وتوزيعها.
</p>

<p>
	ثانيًا، أحد الافتراضات حول تطوير قاعدة البيانات هو أنه يمكننا فصل تطوير قاعدة البيانات عن تطوير عمليات المستخدم التي تستفيد منها، ويستند ذلك إلى توقّع تحديد جميع البيانات المطلوبة بواسطة عمليات المستخدِم المحدَّدة حاليًا، وإمكانية الوصول إليها بمجرد تطبيق قاعدة البيانات، لكننا نطلب أيضًا المرونة للسماح بتلبية تغيرات المتطلبات المستقبلية، كما يمكن التنبؤ بالطلبات الشائعة التي ستُقدَّم إلى قاعدة البيانات عند تطوير قاعدة بيانات لبعض التطبيقات، وبالتالي يمكننا تحسين تصميمنا للطلبات الأكثر شيوعًا.
</p>

<p>
	ثالثًا، تعتمد العديد من جوانب تصميم قاعدة البيانات وتطبيقها في المستوى التفصيلي على نظام إدارة قاعدة البيانات DBMS المستخدَم، فإذا كان اختيار نظام إدارة قواعد البيانات ثابتًا أو أُجرِي قبل مهمة التصميم، فيمكن استخدام هذا الاختيار لتحديد معايير التصميم بدلًا من الانتظار حتى مرحلة التطبيق، أي يمكن دمج قرارات التصميم لنظام إدارة قاعدة البيانات DBMS معين عوضًا عن إنتاج تصميم عام، ثم تكييفه مع نظام إدارة قاعدة البيانات DBMS أثناء التطبيق.
</p>

<p>
	ليس غريبًا العثور على تصميم مفرد لا يمكنه تلبية جميع خصائص قاعدة البيانات الجيدة في الوقت نفسه، لذلك من المهم أن يعطي المصمم الأولوية لهذه الخصائص، ويكون ذلك عادةً باستخدام معلومات من مواصفات المتطلبات، مثل: تحديد ما إذا كانت السلامة أهم من الكفاءة، وما إذا كانت قابلية الاستخدام أهم من المرونة في تطوير معيَّن.
</p>

<p>
	ستحدِّد تعليمات لغة تعريف البيانات data definition language -أو DDL اختصارًا- الخاصة بلغة SQL التخطيط المنطقي في نهاية مرحلة التصميم، حيث تصف لغة DDL قاعدة البيانات التي يجب تطبيقها لتلبية متطلبات المستخدِم.
</p>

<h2>
	التطبيق Implementation
</h2>

<p>
	تتضمن مرحلة التنفيذ أو التطبيق Implementation بناء قاعدة بيانات وفقًا لمواصفات التخطيط المنطقي، والذي سيتضمّن مواصفات تخطيط التخزين storage schema المناسب، وفرض الأمان، والتخطيط الخارجي، وما إلى ذلك، كما يتأثر التطبيق بشدة باختيار نظم إدارة قواعد البيانات المتاحة، وأدوات قواعد البيانات، وبيئة التشغيل.
</p>

<p>
	هناك مهام إضافية تتجاوز مجرد إنشاء تخطيط قاعدة بيانات database schema وتطبيق القيود، إذ يجب إدخال البيانات في الجداول، ومعالجة القضايا المتعلقة بالمستخدِمين وعمليات المستخدِم، كما يجب دعم الأنشطة الإدارية المرتبطة بالجوانب الأوسع لإدارة بيانات الشركة.
</p>

<p>
	نريد معالجة أكبر عدد ممكن من هذه القضايا الموضَّحة أدناه داخل نظام إدارة قواعد البيانات تماشيًا مع نهج نظم إدارة قواعد البيانات.
</p>

<p>
	يتطلب تطبيق التخطيط المنطقي عمليًا في نظام إدارة قواعد البيانات DBMS معرفةً مفصلةً للغاية بالميزات والفوائد المحددة التي يجب تقديمها من قِبَل نظام إدارة قواعد البيانات.
</p>

<p>
	ستشمل المرحلة الأولى من التطبيق انسجامَ متطلبات التصميم مع أفضل أدوات التطبيق المتاحة ثم استخدام تلك الأدوات للتطبيق، وذلك مثاليًا وتماشيًا مع الممارسة الجيدة لهندسة البرمجيات، كما قد يتضمن ذلك في قواعد البيانات على اختيار منتجات البائعِين ذات متغيرات من نظام إدارة قواعد البيانات DBMS و<a href="https://academy.hsoub.com/files/16-%D9%85%D9%84%D8%A7%D8%AD%D8%B8%D8%A7%D8%AA-%D9%84%D9%84%D8%B9%D8%A7%D9%85%D9%84%D9%8A%D9%86-%D8%A8%D9%84%D8%BA%D8%A9-sql/" rel="">لغة SQL</a> الأكثر ملاءمة لقاعدة البيانات التي نحتاج إلى تطبيقها، لكننا لا نعيش في عالم مثالي، كما ستُتخَذ في كثير من الأحيان قرارات اختيار العتاد والقرارات المتعلقة بنظام إدارة قواعد البيانات DBMS قبل النظر في تصميم قاعدة البيانات بوقت طويل، وبالتالي، يمكن أن يتضمن التطبيق ثنيًا إضافيًا للتصميم للتغلب على محدوديات البرمجيات أو العتاد.
</p>

<h2>
	تحقيق التصميم Realizing the Design
</h2>

<p>
	نحتاج إلى إنشاء قاعدة بياناتنا بعد إنشاء التصميم المنطقي وفقًا للتعريفات التي أنتجناها، كما يُحتمَل أن يتضمن التطبيق مع نظام إدارة قواعد البيانات DBMS العلائقي استخدام لغة SQL لإنشاء جداول وقيود تلبي وصف التخطيط المنطقي واختيار تخطيط التخزين المناسب -إذا كان نظام إدارة قواعد البيانات DBMS يسمح بهذا المستوى من التحكم-.
</p>

<p>
	تتمثل إحدى طرق تحقيق ذلك في كتابة تعليمات لغة SQL DDL المناسبة في ملف يمكن لنظام إدارة قواعد البيانات DBMS تنفيذه، بحيث يكون هناك سجل مستقل أو ملف نصي من تعليمات لغة SQL التي تعرِّف قاعدة البيانات؛ أما الطريقة الأخرى فهي العمل تفاعليًا باستخدام أداة قاعدة بيانات مثل الأداتين SQL Server Management Studio أو Microsoft Access.
</p>

<p>
	مهما كانت الآلية المستخدَمة لتطبيق التخطيط المنطقي، فالنتيجة هي أن قاعدة البيانات -مع الجداول والقيود- معرَّفة ولكنها لن تحتوي على بيانات لعمليات المستخدِم.
</p>

<h2>
	ملء قاعدة البيانات Populating the Database
</h2>

<p>
	يوجد طريقتان لملء الجداول بعد إنشاء قاعدة البيانات؛ إما من بيانات موجودة أو من خلال استخدام تطبيقات المستخدِم المطوَّرة لقاعدة البيانات.
</p>

<p>
	قد تكون هناك بيانات موجودة من قاعدة بيانات أخرى أو من ملفات بيانات وذلك بالنسبة لبعض الجداول، فمثلًا، نتوقع عند إنشاء قاعدة بيانات لمستشفى وجود بعض السجلات بالفعل لجميع الموظفين الذين يجب تضمينهم في قاعدة البيانات، كما يمكن أيضًا إحضار البيانات من وكالة خارجية مثل قوائم العناوين التي تُجلَب بصورة متكررة من شركات خارجية، أو يمكن إنتاجها أثناء مهمة إدخال بيانات كبيرة -أي يمكن إجراء تحويل السجلات اليدوية المطبوعة إلى ملفات حاسوبية بواسطة وكالة إدخال بيانات-، ويُعَدّ استخدام وسائل الاستيراد والتصدير الموجودة في نظام إدارة قواعد البيانات DBMS أبسط طريقة لملء قاعدة البيانات في مثل هذه الحالات.
</p>

<p>
	تتوفر عادةً وسائل لاستيراد وتصدير البيانات بتنسيقات قياسية مختلفة، وتُعرَف هذه الوظائف أيضًا في بعض الأنظمة باسم تحميل loading البيانات وتفريغها unloading، كما يتيح الاستيراد إمكانية نسخ ملف البيانات مباشرةً إلى جدول.
</p>

<p>
	إذا جرى الاحتفاظ بالبيانات بتنسيق ملف غير مناسب لاستخدام عملية الاستيراد، فيجب إعداد برنامج تطبيقي يقرأ البيانات القديمة، ويحوّلها حسب الضرورة، ثم يدخلها في قاعدة البيانات باستخدام شيفرة لغة SQL الذي أُنتجِت خصيصًا من أجل هذا الهدف.
</p>

<p>
	يُسمّى نقل كميات كبيرة من البيانات الموجودة إلى قاعدة بيانات بالتحميل المجمَّع bulk load، وقد يتضمن التحميل المجمَّع للبيانات كميات كبيرةً جدًا من البيانات المُحمَّلة أي تحميل جدول في نفس الوقت، لذلك قد تجد وسائل في نظام إدارة قواعد البيانات DBMS لتأجيل فحص قيد حتى نهاية التحميل المجمَّع.
</p>

<h2>
	إرشادات لتطوير مخطط ER
</h2>

<p>
	ملاحظة: ستساعد هذه الإرشادات العامة في تطوير أساس قوي لتصميم قاعدة البيانات الفعلية أي النموذج المنطقي:
</p>

<ol>
<li>
		وثّق جميع الكيانات المكتشَفة خلال مرحلة جمع المعلومات.
	</li>
	<li>
		وثّق جميع السمات التي تنتمي إلى كل كيان، وحدّد المفاتيح المرشَّحة candidate keys، والمفاتيح الرئيسية primary keys، كما تأكد من اعتمادية جميع السمات التي ليست مفاتيحًا non-key attributes لكل كيان بصورة كاملة على المفتاح الرئيسي.
	</li>
	<li>
		طوِّر مخطط ER الأولي وراجعه مع الأشخاص المناسبين، وتذكَّر أن هذه عملية تكرارية.
	</li>
	<li>
		أنشِئ كيانات -أي جداول- جديدة للسمات متعددة القيم والمجموعات المكرَّرة، ثم ضمِّن هذه الكيانات- أي الجداول- الجديدة في مخطط ER، وراجع ذلك مع الأشخاص المناسبين.
	</li>
	<li>
		تحقَّق من نمذجة الكيان العلائقي ER عن طريق تطبيق عملية <a href="https://academy.hsoub.com/devops/servers/databases/%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AD%D9%8A%D8%AF-normalization-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r551/" rel="">التوحيد normalizing</a> على الجداول.
	</li>
</ol>
<p>
	ترجمة -وبتصرّف- للمقال <a href="https://opentextbc.ca/dbdesign01/chapter/chapter-13-database-development-process/" rel="external nofollow">Database Development Process</a> لصاحبته Adrienne Watt.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/sql/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B3%D8%B1%D9%8A%D8%B9%D8%A9-%D8%B9%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%87%D9%8A%D9%83%D9%84%D9%8A%D8%A9-sql-r1368/" rel="">نظرة سريعة على لغة الاستعلامات الهيكلية SQL</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AD%D9%8A%D8%AF-normalization-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r551/" rel="">فهم عملية التوحيد Normalization المستخدمة عند تصميم قاعدة البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r546/" rel="">الاعتماديات الوظيفية المستخدمة في تصميم قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D9%88%D9%82%D9%8A%D9%88%D8%AF%D9%87%D8%A7-%D9%84%D8%B6%D9%85%D8%A7%D9%86-%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r544/" rel="">قواعد السلامة وقيودها لضمان سلامة البيانات في قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%81%D8%B1%D8%B9%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%A5%D8%AC%D8%B1%D8%A7%D8%A1%D8%A7%D8%AA-%D9%81%D9%8A-sql-r858/" rel="">الاستعلامات الفرعية والإجراءات في SQL</a>
	</li>
	<li>
		النسحة الكاملة من كتاب <a href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">553</guid><pubDate>Tue, 02 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x641;&#x647;&#x645; &#x639;&#x645;&#x644;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x648;&#x62D;&#x64A;&#x62F; Normalization &#x627;&#x644;&#x645;&#x633;&#x62A;&#x62E;&#x62F;&#x645;&#x629; &#x639;&#x646;&#x62F; &#x62A;&#x635;&#x645;&#x64A;&#x645; &#x642;&#x627;&#x639;&#x62F;&#x629; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AD%D9%8A%D8%AF-normalization-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r551/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/61790900a877e_------.png.6043cf9f3f19f0ac46f83b7f8394f799.png" /></p>

<p>
	يجب أن يكون التوحيد Normalization جزءًا من عملية تصميم قاعدة البيانات، ولكن من الصعب فصل عملية التوحيد عن عملية <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D9%8A-er-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r545/" rel="">نمذجة الكيان العلائقي ER modelling</a>، لذلك يجب استخدام الطريقتين بصورةٍ متزامنة.
</p>

<p>
	يُستخدَم <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D8%A9-er-%D9%84%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r543/" rel="">مخطط الكيان والعلاقة</a> entity relation diagram -أو ERD اختصارًا- لتوفير الرؤية الكبيرة أو الشاملة لمتطلبات بيانات المؤسسة وعملياتها، إذ يَنشأ ذلك من خلال عملية تكرارية تتضمن تحديد الكيانات المرتبطة، وسماتها، وعلاقاتها؛ بينما يركِّز إجراء التوحيد على خصائص كيانات محددَّة، كما يمثِّل رؤيةً مُصغَّرةً للكيانات داخل مخطط ERD.
</p>

<h2>
	ما هو التوحيد Normalization؟
</h2>

<p>
	التوحيد هو فرع من فروع النظرية العلائقية الذي يوفر رؤى التصميم، وهو عملية تحديد مقدار التكرار redundancy الموجود في الجدول.
</p>

<p>
	أهداف التوحيد هي:
</p>

<ul>
<li>
		القدرة على وصف مستوى التكرار في مخطط علائقي.
	</li>
	<li>
		توفير آليات لتغيير المخططات بهدف إزالة التكرار.
	</li>
</ul>
<p>
	تعتمد نظرية التوحيد على نظرية الاعتماديات الوظيفية اعتمادًا كبيرًا، وتحدِّد هذه النظرية ستة نماذج موحَّدة normal forms -أو NF اختصارًا-، حيث يتضمن كل نموذج موحَّد مجموعةً من خصائص الاعتمادية التي يجب أن يفي المخطط بها، كما يعطي كل نموذج موحَّد ضمانات حول وجود / أو عدم وجود حالات تحديث شاذة update anomalies، وهذا يعني احتواء النماذج الموحدة الأعلى على عدد أقل من التكرار، وبالتالي، مشاكل تحديث أقل.
</p>

<h2>
	النماذج الموحدة Normal Forms
</h2>

<p>
	يمكن أن تكون جميع الجداول الموجودة في قواعد البيانات ضمن أحد النماذج الموحَّدة التي سنناقشها الآن. نريد الحد الأدنى من التكرار بين المفتاح الرئيسي PK، والمفتاح الخارجي FK من الناحية المثالية، كما يجب اشتقاق كل شيء آخر من جداول أخرى.
</p>

<p>
	هناك ستة نماذج موحَّدة، ولكننا سنلقي نظرة على النماذج الأربعة الأولى فقط، وهي:
</p>

<ul>
<li>
		النموذج الموحَّد الأول First normal form، أو 1NF اختصارًا.
	</li>
	<li>
		النموذج الموحَّد الثاني Second normal form، أو 2NF اختصارًا.
	</li>
	<li>
		النموذج الموحَّد الثالث Third normal form، أو 3NF اختصارًا.
	</li>
	<li>
		نموذج بويس-كود الموحَّد Boyce-Codd normal form، أو BCNF اختصارًا، وهو نادر الاستخدام.
	</li>
</ul>
<h2>
	النموذج الموحد الأول 1NF
</h2>

<p>
	يُسمَح فقط بقيم غير مكرَّرة في النموذج الموحد الأول عند تقاطع كل صف وعمود، وهذا يؤدي إلى عدم وجود مجموعات مكرَّرة repeating group، حيث يجب إزالة المجموعة المكرَّرة، وتشكيل علاقتين جديدتين لتوحيد علاقة تحتوي على مجموعة مكرَّرة، ويكون <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r546/" rel="">المفتاح الرئيسي PK</a> للعلاقة الجديدة هو تركيب من المفتاح الرئيسي PK للعلاقة الأصلية بالإضافة إلى سمة من العلاقة المنشَأة حديثًا للحصول على تعريف فريد.
</p>

<h3>
	عملية نموذج 1NF
</h3>

<p>
	سنستخدم جدول تقرير درجات الطالب Student_Grade_Report أدناه، من قاعدة بيانات المدرسة School على أساس مثال لشرح عملية نموذج 1NF.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7266_11" style="">
<span class="typ">Student_Grade_Report</span><span class="pln"> </span><span class="pun">(</span><span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">StudentName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Major</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorLocation</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">)</span></pre>

<p>
	تكون المجموعة المكرَّرة في جدول تقرير درجات الطالب Student Grade Report هي معلومات المقرر الدراسي course، إذ يمكن للطالب أخذ مقررات متعددة.
</p>

<ul>
<li>
		أزِل المجموعة المكررَّة، حيث تكون المجموعة المكرَّرة في هذه الحالة هي معلومات المقرر لكل طالب.
	</li>
	<li>
		حدِّد المفتاح الرئيسي PK لجدولك الجديد.
	</li>
	<li>
		يجب أن يحدِّد المفتاح الرئيسي PK قيمةَ السمة StudentNo وCourseNo تحديدًا فريدًا.
	</li>
	<li>
		يتبقى لك جدول مقررات الطلاب StudentCourse بعد إزالة جميع السمات المتعلِّقة بالمقرر والطالب.
	</li>
	<li>
		أصبح جدول الطالب Student الآن بصيغة النموذج الموحَّد الأول مع إزالة المجموعة المكرَّرة.
	</li>
	<li>
		الجدولان الجديدان موضَّحان كما يلي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_15" style="">
<span class="typ">Student</span><span class="pln"> </span><span class="pun">(</span><span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">StudentName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Major</span><span class="pun">)</span></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_17" style="">
<span class="typ">StudentCourse</span><span class="pln"> </span><span class="pun">(</span><span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorLocation</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">)</span></pre>

<h3>
	تحديث حالات نموذج 1NF الشاذة
</h3>

<p>
	بالنظر إلى الجدول السابق والذي يسبقه:
</p>

<ul>
<li>
		نحتاج طالبًا لإضافة مقرَّر جديد.
	</li>
	<li>
		قد يكون لدينا تناقضات عندما تحتاج معلومات المقرَّر إلى تحديث.
	</li>
	<li>
		قد نحذف أيضًا معلومات هامة حول مقرر عند حذف طالب.
	</li>
</ul>
<h2>
	النموذج الموحد الثاني 2NF
</h2>

<p>
	يجب أن تكون العلاقة أولًا بصيغة نموذج 1NF للانتقال إلى النموذج الموحَّد الثاني 2NF، حيث تكون العلاقة تلقائيًا بصيغة نموذج 2NF إذا وفقط إذا اشتمل <a href="https://academy.hsoub.com/questions/618-%D9%85%D8%A7%D9%87%D9%88-%D8%A7%D9%84%D9%81%D8%B1%D9%82-%D8%A8%D9%8A%D9%86-primary-key-%D9%88-unique-key-%D9%81%D9%89-mysql-%D8%9F/" rel="">المفتاح الرئيسي PK</a> على سمة واحدة.
</p>

<p>
	إذا احتوت العلاقة على مفتاح رئيسي مركّب composite PK، فيجب أن تعتمد كل سمةٍ ليست مفتاحًا على المفتاح الرئيسي PK بأكمله اعتمادًا كاملًا، ولا تعتمد على مجموعة فرعية من المفتاح الرئيسي PK، أي لا يجب وجود اعتمادية جزئية partial dependency، أو ما يُسمَّى بالزيادة augmentation.
</p>

<h3>
	عملية نموذج 2NF
</h3>

<p>
	يجب أولًا أن يكون الجدول بصيغة نموذج 1NF للانتقال إلى النموذج 2NF.
</p>

<ul>
<li>
		جدول الطالب Student موجود بالفعل بصيغة نموذج 2NF لأنه يحتوي على عمود مفتاح رئيسي واحد.
	</li>
	<li>
		ليست كل السمات -وتحديدًا جميع معلومات المقرر course information- معتمدةً بالكامل على المفتاح الرئيسي عند فحص جدول مقررات الطلاب Student Course، إذ تكون السمة الوحيدة المعتمدة بالكامل على المفتاح الرئيسي هي الدرجة grade.
	</li>
	<li>
		عرِّف الجدول الجديد الذي يحتوي على معلومات المقرَّر.
	</li>
	<li>
		عرِّف المفتاح الرئيسي PK للجدول الجديد.
	</li>
	<li>
		الجداول الثلاثة الجديدة موضَّحة أدناه.
	</li>
</ul>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_21" style="">
<span class="typ">Student</span><span class="pln"> </span><span class="pun">(</span><span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">StudentName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Major</span><span class="pun">)</span></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_23" style="">
<span class="typ">CourseGrade</span><span class="pln"> </span><span class="pun">(</span><span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">)</span></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_25" style="">
<span class="typ">CourseInstructor</span><span class="pln"> </span><span class="pun">(</span><span class="typ">CourseNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorLocation</span><span class="pun">)</span></pre>

<h3>
	تحديث حالات نموذج 2NF الشاذة
</h3>

<p>
	بالنظر إلى الجداول السابقة:
</p>

<ul>
<li>
		نحتاج إلى مقرَّر course عند إضافة مدرِّس جديد.
	</li>
	<li>
		قد يؤدي تحديث معلومات المقرر إلى وجود تناقضات في معلومات المدرِّس.
	</li>
	<li>
		قد يؤدي حذف المقرر أيضًا إلى حذف معلومات المدرِّس.
	</li>
</ul>
<h2>
	النموذج الموحد الثالث 3NF
</h2>

<p>
	يجب أن تكون العلاقة بصيغة النموذج الموحَّد الثاني 2NF للانتقال إلى النموذج الموحَّد الثالث 3NF، كما يجب إزالة جميع الاعتماديات المتعدية transitive dependencies أيضًا، فقد لا تعتمد السمة التي ليست مفتاحًا اعتمادًا وظيفيًا على سمة أخرى ليست مفتاحًا.
</p>

<h3>
	عملية نموذج 3NF
</h3>

<ul>
<li>
		أزِل كافة السمات الاعتمادية dependent attributes في العلاقة، أو في العلاقات المتعدية من كل جدول من الجداول التي لها علاقة متعدية.
	</li>
	<li>
		أنشِئ جدولًا، أو جداولًا جديدةً مع إزالة الاعتمادية.
	</li>
	<li>
		تحقق من الجدول، أو الجداول الجديدة، كما تحقق من الجدول، أو الجداول المعدَّلة أيضًا، وذلك للتأكد من احتواء كل جدول على محدِّد determinant، ومن عدم وجود جدول يحتوي على اعتماديات غير مناسبة.
	</li>
	<li>
		الجداول الأربعة الجديدة موضَّحة أدناه.
	</li>
</ul>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_27" style="">
<span class="typ">Student</span><span class="pln"> </span><span class="pun">(</span><span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">StudentName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Major</span><span class="pun">)</span></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_31" style="">
<span class="typ">CourseGrade</span><span class="pln"> </span><span class="pun">(</span><span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">)</span></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_29" style="">
<span class="typ">Course</span><span class="pln"> </span><span class="pun">(</span><span class="typ">CourseNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorNo</span><span class="pun">)</span></pre>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_33" style="">
<span class="typ">Instructor</span><span class="pln"> </span><span class="pun">(</span><span class="typ">InstructorNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorLocation</span><span class="pun">)</span></pre>

<p>
	يجب ألا تكون هناك حالات شاذة في النموذج الموحَّد الثالث في هذه المرحلة.
</p>

<p>
	لنلقِ نظرةً على مخطط الاعتمادية الموضَّح في الشكل الآتي لهذا المثال، حيث تتمثل الخطوة الأولى في إزالة المجموعات المكرَّرة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_35" style="">
<span class="typ">Student</span><span class="pln"> </span><span class="pun">(</span><span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">StudentName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Major</span><span class="pun">)</span><span class="pln">
</span><span class="typ">StudentCourse</span><span class="pln"> </span><span class="pun">(</span><span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CourseName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InstructorLocation</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">)</span></pre>

<p>
	تلخِّص الاعتماديات الموضَّحة في الشكل التالي عملية توحيد normalization قاعدة بيانات المدرسة School database:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93999" href="https://academy.hsoub.com/uploads/monthly_2022_03/DependencyDiagramSchool.png.ac251712928177b4a04b02b6228025eb.png" rel=""><img alt="DependencyDiagramSchool.png" class="ipsImage ipsImage_thumbnailed" data-fileid="93999" data-unique="tn8bqanxv" src="https://academy.hsoub.com/uploads/monthly_2022_03/DependencyDiagramSchool.thumb.png.9399ca3360ed553a1333a168fcb2f3fd.png" style="width: 550px; height: auto;"></a>
</p>

<p>
	الاختصارات المستخدمة في الشكل السابق هي كما يلي:
</p>

<ul>
<li>
		PD: الاعتمادية الجزئية partial dependency.
	</li>
	<li>
		TD: الاعتمادية المتعدية transitive dependency.
	</li>
	<li>
		FD: الاعتمادية الكاملة full dependency، إذ يشير الاختصار FD إلى الاعتمادية الوظيفية functional dependency عادةً، ولكن استخدمنا الاختصار FD على أساس اختصار للاعتمادية الكاملة full dependency في الشكل السابق فقط.
	</li>
</ul>
<h2>
	نموذج بويس-كود الموحد BCNF 
</h2>

<p>
	قد تنتج حالات شاذة عندما يحتوي الجدول على أكثر من مفتاح مرشَّح candidate key على الرغم من أن العلاقة بصيغة نموذج 3NF، حيث يُعَدّ نموذج بويس-كود الموحَّد حالةً خاصةً من النموذج 3NF، وتكون العلاقة ضمن نموذج BCNF إذا وفقط إذا كان كل محدّد determinant مفتاحًا مرشَحًا candidate key.
</p>

<h3>
	المثال الأول عن نموذج BCNF
</h3>

<p>
	ضع في بالك الجدول التالي St_Maj_Adv:
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
<thead><tr>
<th>
				Student_id
			</th>
			<th>
				Major
			</th>
			<th>
				Advisor
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				111
			</td>
			<td>
				Physics
			</td>
			<td>
				Smith
			</td>
		</tr>
<tr>
<td>
				111
			</td>
			<td>
				Music
			</td>
			<td>
				Chan
			</td>
		</tr>
<tr>
<td>
				320
			</td>
			<td>
				Math
			</td>
			<td>
				Dobbs
			</td>
		</tr>
<tr>
<td>
				671
			</td>
			<td>
				Physics
			</td>
			<td>
				White
			</td>
		</tr>
<tr>
<td>
				803
			</td>
			<td>
				Physics
			</td>
			<td>
				Smith
			</td>
		</tr>
</tbody>
</table>
<p>
	تكون القواعد الدلالية semantic rules -أي قواعد العمل المطبَّقة على قاعدة البيانات- لهذا الجدول هي:
</p>

<ol>
<li>
		يجوز لكل طالب Student التخصص في عدة مواد.
	</li>
	<li>
		يكون لكل طالب معين مدرِّسًا واحدًا فقط لكل تخصص Major.
	</li>
	<li>
		لكل تخصص عدة مدرِّسين.
	</li>
	<li>
		يدرِّس كل مدرِّس تخصصًا واحدًا فقط.
	</li>
	<li>
		يدرِّس كل مدرِّس عدة طلاب في تخصص واحد.
	</li>
</ol>
<p>
	الاعتماديات الوظيفية لهذا الجدول مذكورة أدناه، فالأولى هي مفتاح مرشَّح candidate key، والثانية ليست كذلك.
</p>

<pre class="ipsCode">
Student_id, Major ——&gt;  Advisor
Advisor  ——&gt;  Major
</pre>

<p>
	تشمل الحالات الشاذة لهذا الجدول ما يلي:
</p>

<ol>
<li>
		الحذف Delete: مثل حالة حذف الطالب معلومات المدرِّس.
	</li>
	<li>
		الإدخال Insert: مثل حالة احتياج المدرِّس الجديد إلى وجود طالب.
	</li>
	<li>
		التحديث Update: مثل الحالات المتناقضة.
	</li>
</ol>
<p>
	<strong>ملاحظة</strong>: ليست السمة المُفرَدة single attribute مفتاحًا مرشَحًا.
</p>

<p>
	يمكن أن يكون المفتاح الرئيسي PK هو Student_id, Major، أو Student_id, Advisor.
</p>

<p>
	يمكنك إنشاء جدولين جديدين، لتقليل العلاقة St_Maj_Adv إلى النموذج BCNF كما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_37" style="">
<span class="typ">St_Adv</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Student_id</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Advisor</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Adv_Maj</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Advisor</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Major</span><span class="pun">)</span></pre>

<p>
	جدول <strong>St_Adv</strong>:
</p>

<table>
<thead><tr>
<th>
				Student_id
			</th>
			<th>
				Advisor
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				111
			</td>
			<td>
				Smith
			</td>
		</tr>
<tr>
<td>
				111
			</td>
			<td>
				Chan
			</td>
		</tr>
<tr>
<td>
				320
			</td>
			<td>
				Dobbs
			</td>
		</tr>
<tr>
<td>
				671
			</td>
			<td>
				White
			</td>
		</tr>
<tr>
<td>
				803
			</td>
			<td>
				Smith
			</td>
		</tr>
</tbody>
</table>
<p>
	جدول <strong>Adv_Maj</strong>:
</p>

<table>
<thead><tr>
<th>
				Advisor
			</th>
			<th>
				Major
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				Smith
			</td>
			<td>
				Physics
			</td>
		</tr>
<tr>
<td>
				Chan
			</td>
			<td>
				Music
			</td>
		</tr>
<tr>
<td>
				Dobbs
			</td>
			<td>
				Math
			</td>
		</tr>
<tr>
<td>
				White
			</td>
			<td>
				Physics
			</td>
		</tr>
</tbody>
</table>
<h3>
	المثال الثاني عن نموذج BCNF
</h3>

<p>
	انظر الجدول التالي Client_Interview:
</p>

<table>
<thead><tr>
<th>
				ClientNo
			</th>
			<th>
				InterviewDate
			</th>
			<th>
				InterviewTime
			</th>
			<th>
				StaffNo
			</th>
			<th>
				RoomNo
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				CR76
			</td>
			<td>
				13-May-02
			</td>
			<td>
				10.30
			</td>
			<td>
				SG5
			</td>
			<td>
				G101
			</td>
		</tr>
<tr>
<td>
				CR56
			</td>
			<td>
				13-May-02
			</td>
			<td>
				12.00
			</td>
			<td>
				SG5
			</td>
			<td>
				G101
			</td>
		</tr>
<tr>
<td>
				CR74
			</td>
			<td>
				13-May-02
			</td>
			<td>
				12.00
			</td>
			<td>
				SG37
			</td>
			<td>
				G102
			</td>
		</tr>
<tr>
<td>
				CR56
			</td>
			<td>
				1-July-02
			</td>
			<td>
				10.30
			</td>
			<td>
				SG5
			</td>
			<td>
				G102
			</td>
		</tr>
</tbody>
</table>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5275_39" style="">
<span class="pln">FD1 </span><span class="pun">–</span><span class="pln"> </span><span class="typ">ClientNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">InterviewDate</span><span class="pln"> </span><span class="pun">–&gt;</span><span class="pln"> </span><span class="typ">InterviewTime</span><span class="pun">,</span><span class="pln"> </span><span class="typ">StaffNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">RoomNo</span><span class="pln">  </span><span class="pun">(</span><span class="pln">PK</span><span class="pun">)</span><span class="pln">

FD2 </span><span class="pun">–</span><span class="pln"> staffNo</span><span class="pun">,</span><span class="pln"> interviewDate</span><span class="pun">,</span><span class="pln"> interviewTime </span><span class="pun">–&gt;</span><span class="pln"> clientNO      </span><span class="pun">(</span><span class="pln">candidate key</span><span class="pun">:</span><span class="pln"> CK</span><span class="pun">)</span><span class="pln">

FD3 </span><span class="pun">–</span><span class="pln"> roomNo</span><span class="pun">,</span><span class="pln"> interviewDate</span><span class="pun">,</span><span class="pln"> interviewTime </span><span class="pun">–&gt;</span><span class="pln"> staffNo</span><span class="pun">,</span><span class="pln"> clientNo    </span><span class="pun">(</span><span class="pln">CK</span><span class="pun">)</span><span class="pln">

FD4 </span><span class="pun">–</span><span class="pln"> staffNo</span><span class="pun">,</span><span class="pln"> interviewDate </span><span class="pun">–&gt;</span><span class="pln"> roomNo</span></pre>

<p>
	تكون العلاقة بصيغة نموذج BCNF إذا وفقط إذا كان كل محدّد determinant مفتاحًا مرشَّحًا.
</p>

<p>
	نحن بحاجة إلى إنشاء جدول يتضمن أول ثلاثة اعتماديات كاملة FD -أي جدول Client_Interview2-، وإنشاء جدول آخر -أي جدول StaffRoom- للاعتمادية الكاملة FD الرابعة.
</p>

<p>
	جدول <strong>Client_Interview2</strong>:
</p>

<table>
<thead><tr>
<th>
				ClientNo
			</th>
			<th>
				InterviewDate
			</th>
			<th>
				InterViewTime
			</th>
			<th>
				StaffNo
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				CR76
			</td>
			<td>
				13-May-02
			</td>
			<td>
				10.30
			</td>
			<td>
				SG5
			</td>
		</tr>
<tr>
<td>
				CR56
			</td>
			<td>
				13-May-02
			</td>
			<td>
				12.00
			</td>
			<td>
				SG5
			</td>
		</tr>
<tr>
<td>
				CR74
			</td>
			<td>
				13-May-02
			</td>
			<td>
				12.00
			</td>
			<td>
				SG37
			</td>
		</tr>
<tr>
<td>
				CR56
			</td>
			<td>
				1-July-02
			</td>
			<td>
				10.30
			</td>
			<td>
				SG5
			</td>
		</tr>
</tbody>
</table>
<p>
	جدول <strong>StaffRoom</strong>:
</p>

<table>
<thead><tr>
<th>
				StaffNo
			</th>
			<th>
				StaffNo
			</th>
			<th>
				RoomNo
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				SG5
			</td>
			<td>
				13-May-02
			</td>
			<td>
				G101
			</td>
		</tr>
<tr>
<td>
				SG37
			</td>
			<td>
				13-May-02
			</td>
			<td>
				G102
			</td>
		</tr>
<tr>
<td>
				SG5
			</td>
			<td>
				1-July-02
			</td>
			<td>
				G102
			</td>
		</tr>
</tbody>
</table>
<h2>
	التوحيد وتصميم قواعد البيانات
</h2>

<p>
	تأكَّد أثناء عملية توحيد تصميم قاعدة البيانات من توافق الكيانات المقترحة للنموذج الموحَّد المطلوب قبل إنشاء بُنى الجدول.
</p>

<p>
	صُمِّمت العديد من <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">قواعد البيانات</a> واقعيًا بصورة غير سليمة، أو أُثقِل كاهلها بحالات شاذة عند تعديلها بصورة غير سليمة خلال فترة زمنية، وقد يُطلب منك إعادة تصميم قواعد البيانات الحالية، وتعديلها، كما يمكن أن يكون ذلك مهمةً كبيرةً إذا أجريت عملية التوحيد على الجداول بصورةٍ غير صحيحة.
</p>

<h2>
	تمارين
</h2>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong> أكمل هذا المقال و<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r546/" rel="">المقال السابق</a> قبل حل هذه التمارين.
		</p>
	</div>
</blockquote>

<ol>
<li>
		ما هو التوحيد normalization؟
	</li>
	<li>
		متى يكون جدول ما في نموذج 1NF؟ 3.متى يكون جدول ما في نموذج 2NF؟
	</li>
	<li>
		متى يكون جدول ما في نموذج 3NF؟
	</li>
	<li>
		عرِّف وناقش كل من الاعتماديات المشار إليها في مخطط الاعتمادية الموضَّح في الشكل التالي:
	</li>
</ol>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="94000" href="https://academy.hsoub.com/uploads/monthly_2022_03/ForQuestion5.png.20664065ee4fef21fb5ddb54f6c18afb.png" rel=""><img alt="ForQuestion5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="94000" data-unique="pp02h67sa" src="https://academy.hsoub.com/uploads/monthly_2022_03/ForQuestion5.thumb.png.2378e70b247b1214c418d361167bbb8f.png" style="width: 550px; height: auto;"></a>
</p>

<ol start="6">
<li>
		تستخدم كليّة جامعية college جديدة بنية الجدول الموضَّحة في الشكل التالي، وذلك لتتبع الطلاب والمقرَّرات، وبالتالي، ارسم مخطط الاعتمادية لهذا الجدول.
	</li>
</ol>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
<thead><tr>
<th>
				Attribute Name
			</th>
			<th>
				Sample Value
			</th>
			<th>
				Sample Value
			</th>
			<th>
				Sample Value
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				StudentID
			</td>
			<td>
				1
			</td>
			<td>
				2
			</td>
			<td>
				3
			</td>
		</tr>
<tr>
<td>
				StudentName
			</td>
			<td>
				John Smith
			</td>
			<td>
				Sandy Law
			</td>
			<td>
				Sue Rogers
			</td>
		</tr>
<tr>
<td>
				CourselD
			</td>
			<td>
				2
			</td>
			<td>
				2
			</td>
			<td>
				3
			</td>
		</tr>
<tr>
<td>
				CourseName
			</td>
			<td>
				Programming Level 1
			</td>
			<td>
				Programming Level 1
			</td>
			<td>
				Business
			</td>
		</tr>
<tr>
<td>
				Grade
			</td>
			<td>
				75%
			</td>
			<td>
				61%
			</td>
			<td>
				81%
			</td>
		</tr>
<tr>
<td>
				CourseDate
			</td>
			<td>
				Jan 5th, 2014
			</td>
			<td>
				Jan 5th, 2014
			</td>
			<td>
				Jan 7th, 2014
			</td>
		</tr>
</tbody>
</table>
<ol start="7">
<li>
		اعرض الجداول بصيغة النموذج الموحَّد الثالث التي ستنشئها لإصلاح المشكلات التي واجهتها باستخدام مخطط الاعتمادية الذي رسمته للتو، ثم ارسم مخطط الاعتمادية للجدول الثابت.
	</li>
	<li>
		توفر الوكالة التي تسمى Instant Cover موظفِين بدوام جزئي / مؤقت للفنادق في اسكتلندا، إذ يوضِّح الشكل الآتي الوقت الذي يقضيه موظفو الوكالة في العمل في فنادق مختلفة، حيث يكون رقم التأمين الوطني NIN -أي national insurance number- فريدًا لكل موظف.
	</li>
</ol>
<p>
	استخدم الشكل التالي للإجابة على السؤالين الآتيين:
</p>

<table>
<thead><tr>
<th>
				NIN
			</th>
			<th>
				ContractNo
			</th>
			<th>
				Hours
			</th>
			<th>
				eName
			</th>
			<th>
				hNo
			</th>
			<th>
				hLoc
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				1135
			</td>
			<td>
				C1024
			</td>
			<td>
				16
			</td>
			<td>
				Smith J.
			</td>
			<td>
				H25
			</td>
			<td>
				East Killbride
			</td>
		</tr>
<tr>
<td>
				1057
			</td>
			<td>
				C1024
			</td>
			<td>
				24
			</td>
			<td>
				Hocine D.
			</td>
			<td>
				H25
			</td>
			<td>
				East Killbride
			</td>
		</tr>
<tr>
<td>
				1068
			</td>
			<td>
				C1025
			</td>
			<td>
				28
			</td>
			<td>
				White T.
			</td>
			<td>
				H4
			</td>
			<td>
				Glasgow
			</td>
		</tr>
<tr>
<td>
				1135
			</td>
			<td>
				C1025
			</td>
			<td>
				15
			</td>
			<td>
				Smith J.
			</td>
			<td>
				H4
			</td>
			<td>
				Glasgow
			</td>
		</tr>
</tbody>
</table>
<ul>
<li>
		هذا الجدول عرضة لحالات تحديث شاذة، لذلك قدّم أمثلةً على حالات شاذة للإدخال، والحذف، والتحديث.
	</li>
	<li>
		طَبّق عملية التوحيد على هذا الجدول ليصبح له صيغة النموذج الموحّد الثالث، مع ذكر أي افتراضات.
	</li>
</ul>
<ol start="9">
<li>
		إملأ الفراغات:
		<ul>
<li>
				ينتج عن __ نموذجًا موحّدًا أقل.
			</li>
			<li>
				تسمى السمة التي تحدِّد قيمتها قيمًا أخرى داخل صف __.
			</li>
			<li>
				السمة التي لا يمكن تقسيمها توصف بأنها ___.
			</li>
			<li>
				يشير __ إلى مستوى التفاصيل الذي تمثِّله القيم المخزَّنة في صف الجدول.
			</li>
			<li>
				يجب ألا يحتوي الجدول العلائقي على مجموعات ___.
			</li>
		</ul>
</li>
</ol>
<p>
	ترجمة -وبتصرف- للمقال <a href="https://opentextbc.ca/dbdesign01/chapter/chapter-12-normalization/" rel="external nofollow">Normalization</a> لصاحبته Adrienne Watt.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/devops/servers/databases/%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database-development-r553/" rel="">عملية تطوير قواعد البيانات Database Development</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r546/" rel="">الاعتماديات الوظيفية المستخدمة في تصميم قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D8%A9-er-%D9%84%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r543/" rel="">نموذج الكيان والعلاقة ER لتمثيل البيانات وتخزينها في قاعدة البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">المفاهيم الأساسية في قواعد البيانات وتصميمها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D8%A9-er-%D9%84%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r543/" rel="">نموذج الكيان والعلاقة ER لتمثيل البيانات وتخزينها في قاعدة البيانات</a>
	</li>
	<li>
		النسخة العربية الكاملة لكتاب <a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تصميم قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">551</guid><pubDate>Tue, 26 Oct 2021 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x627;&#x639;&#x62A;&#x645;&#x627;&#x62F;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x638;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x644;&#x645;&#x633;&#x62A;&#x62E;&#x62F;&#x645;&#x629; &#x641;&#x64A; &#x62A;&#x635;&#x645;&#x64A;&#x645; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r546/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/616521cae826c_------.png.7dc0fc76641f151a5eb8a49543b9318a.png" /></p>

<p>
	الاعتمادية الوظيفية functional dependency -أو FD اختصارًا- هي علاقة بين سمتَين attributes، حيث تكون عادةً بين <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%88%D8%A7%D8%B6%D9%8A%D8%B9-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-sql-r853/" rel="">المفتاح الرئيسي PK</a> والسمات الأخرى التي ليست مفاتيحًا non-key attributes داخل الجدول، إذ تعتمد السمة Y وظيفيًا على السمة X -والتي تُعَد مفتاحًا رئيسيًا PK- في علاقة R إذا حدّدت قيمةُ السمة X قيمةَ السمة Y بصورةٍ فريدة لكل نسخةٍ صالحة من السمة X، ويشار إلى هذه العلاقة من خلال التمثيل التالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_27" style="">
<span class="pln">X </span><span class="pun">———–&gt;</span><span class="pln"> Y</span></pre>

<p>
	يسمى الجانب الأيسر من مخطط الاعتمادية الوظيفية FD السابق بالمحدِّد determinant، ويسمى الجانب الأيمن بالاعتمادي dependent، وفيما يلي بعض الأمثلة على ذلك.
</p>

<p>
	تحدِّد السمة SIN الاسم Name، والعنوان Address، وتاريخ الميلاد Birthdate في المثال الأول أدناه، حيث يمكننا تحديد أي من السمات الأخرى داخل الجدول باستخدام السمة SIN.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_11" style="">
<span class="pln">SIN   </span><span class="pun">———–&gt;</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Address</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Birthdate</span></pre>

<p>
	تحدِّد السمتان SIN، وCourse تاريخ الانتهاء DateCompleted في المثال الثاني، حيث يجب أن يعمل هذا أيضًا مع مفتاح رئيسي مركّّب composite PK.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_30" style="">
<span class="pln">SIN</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Course</span><span class="pln">  </span><span class="pun">———–&gt;</span><span class="pln">    </span><span class="typ">DateCompleted</span></pre>

<p>
	يشير المثال الثالث إلى أن السمة ISBN تحدّد العنوان Title.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_33" style="">
<span class="pln">ISBN  </span><span class="pun">———–&gt;</span><span class="pln">  </span><span class="typ">Title</span></pre>

<h2>
	قواعد الاعتماديات الوظيفية
</h2>

<p>
	انظر إلى جدول البيانات (r(R لمخطط العلاقة (R(ABCDE الموضَّح في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="78960" href="https://academy.hsoub.com/uploads/monthly_2021_10/FunctionalDependencyExample.png.135243994c14ed09eac65ebb045071d7.png" rel=""><img alt="FunctionalDependencyExample.png" class="ipsImage ipsImage_thumbnailed" data-fileid="78960" data-unique="mr2w888pi" src="https://academy.hsoub.com/uploads/monthly_2021_10/FunctionalDependencyExample.thumb.png.0ac587ea3c0a5daec758a22f83b3b1ea.png" style="width: 250px; height: auto;"></a>
</p>

<p>
	قد تسأل نفسك عند النظر إلى هذا الجدول: <strong>ما نوع الاعتماديات التي يمكننا ملاحظتها بين السمات في الجدول R؟</strong>
</p>

<p>
	بما أنّ قيم السمة A فريدة (a1, a2, a3, etc)، فيمكن القول اعتمادًا على تعريف الاعتمادية الوظيفية FD أنّ:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_15" style="">
<span class="pln">A </span><span class="pun">→</span><span class="pln"> B</span><span class="pun">,</span><span class="pln">
A </span><span class="pun">→</span><span class="pln"> C</span><span class="pun">,</span><span class="pln">
A </span><span class="pun">→</span><span class="pln"> D</span><span class="pun">,</span><span class="pln">
A </span><span class="pun">→</span><span class="pln"> E</span></pre>

<ul>
<li>
		ويترتب على ذلك أيضًا أن A → BC، أو أي مجموعة فرعية أخرى من المجموعة ABCDE.
	</li>
	<li>
		يمكن تلخيص ذلك على أساس A → BCDE.
	</li>
	<li>
		تُعَدّ السمة A مفتاحًا رئيسيًا.
	</li>
</ul>
<p>
	بما أن قيم السمة E هي نفسها دائمًا أي كلها لها القيمة e1، فهذا يعني أنّ:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_17" style="">
<span class="pln">A </span><span class="pun">→</span><span class="pln"> E</span><span class="pun">,</span><span class="pln">
B </span><span class="pun">→</span><span class="pln"> E</span><span class="pun">,</span><span class="pln">
C </span><span class="pun">→</span><span class="pln"> E</span><span class="pun">,</span><span class="pln">
D </span><span class="pun">→</span><span class="pln"> E</span></pre>

<p>
	ولكن لا يمكننا تلخيص ما سبق باستخدام ABCD → E، وذلك لأنّ:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_19" style="">
<span class="pln"> A </span><span class="pun">→</span><span class="pln"> E</span><span class="pun">,</span><span class="pln">
B </span><span class="pun">→</span><span class="pln"> E</span><span class="pun">,</span><span class="pln">
AB </span><span class="pun">→</span><span class="pln"> E</span></pre>

<h3>
	ملاحظات أخرى:
</h3>

<ol>
<li>
		تركيبات BC فريدة، لذلك BC → ADE.
	</li>
	<li>
		تركيبات BD فريدة، لذلك BD → ACE.
	</li>
	<li>
		إذا كانت قيم السمة C متطابقة، فإن قيم السمة D متطابقة كذلك.
	</li>
	<li>
		لذلك C → D.
	</li>
	<li>
		ولكن لا تحدِّد قيم السمة D قيم السمة C.
	</li>
	<li>
		لذلك لا تحدّد السمة C السمة D، ولا تحدِّد السمة D السمة C.
	</li>
</ol>
<p>
	يمكن مساعدة النظر إلى البيانات الفعلية في توضيح السمات التي هي سمات اعتمادية dependent، والسمات التي هي سمات محدِّدة determinant.
</p>

<h2>
	قواعد الاستدلال Inference Rules
</h2>

<p>
	تُعَدّ بديهيات أرمسترونغ Armstrong’s axioms مجموعةً من قواعد الاستدلال المستخدَمة لاستنتاج جميع الاعتماديات الوظيفية في قاعدة بيانات علائقية، حيث طوَّر ويليام أرمسترونغ William W. Armstrong هذه البديهيات.
</p>

<p>
	لنفترض أنّ (R(U هو مخطط علاقة لمجموعة سمات U، حيث سنستخدم الأحرف X، وY، وZ لتمثيل أي مجموعة فرعية، أو اتحاد union مجموعتين من السمات اختصارًا، بدلًا من استخدام X U Y.
</p>

<h3>
	بديهية الانعكاس Axiom of reflexivity
</h3>

<p>
	تنص هذه البديهية على أنه إذا كانت Y مجموعة فرعية subset من X، فإنّ X تحدِّد Y، كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="78963" href="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForAxiomOfReflexivity.png.faf5afb28a72a7edca36ef23fe90eae4.png" rel=""><img alt="EquationForAxiomOfReflexivity.png" class="ipsImage ipsImage_thumbnailed" data-fileid="78963" data-unique="916af9hcy" src="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForAxiomOfReflexivity.png.faf5afb28a72a7edca36ef23fe90eae4.png" style="width: 281px; height: 45px;"></a>
</p>

<p>
	افترض الاعتمادية الوظيفية PartNo —&gt; NT123 على سبيل المثال، حيث تتركّب (X (PartNo من معلومات متعددة، وهي: (Y (NT، و(partID (123.
</p>

<h3>
	بديهية الزيادة Axiom of augmentation
</h3>

<p>
	تنص بديهية الزيادة -والمعروفة باسم الاعتمادية الجزئية partial dependency أيضًا- على أنه إذا كانت X تحدِّد Y، فإنّ XZ تحدد YZ مهما كانت Z، أي كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="78962" href="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForAxiomOfAugmentation.png.29e1e8e62f3c7da858d8a54fa8ad0125.png" rel=""><img alt="EquationForAxiomOfAugmentation.png" class="ipsImage ipsImage_thumbnailed" data-fileid="78962" data-unique="f8xa9e356" src="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForAxiomOfAugmentation.png.29e1e8e62f3c7da858d8a54fa8ad0125.png"></a>
</p>

<p>
	تنص بديهية الزيادة على أن يجب على كل سمة ليست مفتاحًا non-key attribute الاعتماد على المفتاح الرئيسي PK بصورة كاملة، فمثلًا، تعتمد السمات التالية: اسم الطالب StudentName، والعنوان Address، والمدينة City، وProv، وPC -أي الرمز البريدي postal code- على سمة رقم الطالب StudentNo فقط، ولا تعتمد على السمتين StudentNo، وGrade معًا.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_38" style="">
<span class="typ">StudentNo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Course</span><span class="pln"> </span><span class="pun">—&gt;</span><span class="pln"> </span><span class="typ">StudentName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Address</span><span class="pun">,</span><span class="pln"> </span><span class="typ">City</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Prov</span><span class="pun">,</span><span class="pln"> PC</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Grade</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DateCompleted</span></pre>

<p>
	هذا الوضع غير مرغوب به لأنه يجب على كل سمة ليست مفتاحًا الاعتماد على المفتاح PK بصورةٍ كاملة، ولكن تعتمد معلومات الطلاب في هذه الحالة جزئيًا فقط على المفتاح الرئيسي PK أي StudentNo.
</p>

<p>
	يجب إصلاح هذه المشكلة من خلال تقسيم الجدول الأصلي إلى جدولين على النحو التالي:
</p>

<ul>
<li>
		الجدول الأول 1: يحوي الحقول التالية:
		<ul>
<li>
				StudentNo.
			</li>
			<li>
				Course.
			</li>
			<li>
				Grade.
			</li>
			<li>
				DateCompleted.
			</li>
		</ul>
</li>
	<li>
		الجدول الثاني 2: ويحوي الحقول التالية:
		<ul>
<li>
				StudentNo.
			</li>
			<li>
				StudentName.
			</li>
			<li>
				Address.
			</li>
			<li>
				City.
			</li>
			<li>
				Prov.
			</li>
			<li>
				PC.
			</li>
		</ul>
</li>
</ul>
<h3>
	البديهية المتعدية Axiom of transitivity
</h3>

<p>
	تنص البديهية المتعدِّية على أنه إذا كانت X تحدِّد Y، وY تحدِّد Z، فإنّ X تحدِّد Z أيضًا، أي كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="78964" href="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForAxiomOfTransitivity.png.058f0c033e189805c6511ad86674ba2d.png" rel=""><img alt="EquationForAxiomOfTransitivity.png" class="ipsImage ipsImage_thumbnailed" data-fileid="78964" data-unique="jnp8zxm4v" src="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForAxiomOfTransitivity.png.058f0c033e189805c6511ad86674ba2d.png"></a>
</p>

<p>
	يحتوي الجدول أدناه على معلومات غير مرتبطة مباشرةً بالطالب، فيجب أن يكون لمعرِّف البرنامج ProgramID، واسم البرنامج ProgramName جدولًا خاصًا بهما، حيث لا يعتمد اسم البرنامج على رقم الطالب، وإنما يعتمد على معرِّف البرنامج.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_21" style="">
<span class="typ">StudentNo</span><span class="pln">  </span><span class="pun">—&gt;</span><span class="pln"> </span><span class="typ">StudentName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Address</span><span class="pun">,</span><span class="pln"> </span><span class="typ">City</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Prov</span><span class="pun">,</span><span class="pln"> PC</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ProgramID</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ProgramName</span></pre>

<p>
	هذه الحالة غير مرغوب بها بسبب اعتماد السمة التي ليست مفتاحًا -أي ProgramName- على سمة أخرى ليست مفتاحًا أيضًا -أي ProgramID-.
</p>

<p>
	نحل هذه المشكلة من خلال تقسيم هذا الجدول إلى جدولين: جدول لمعلومات الطالب، والآخر لمعلومات البرنامج، أي كما يلي:
</p>

<ul>
<li>
		الجدول 1:
	</li>
</ul>
<pre class="ipsCode">
StudentNo —&gt; StudentName, Address, City, Prov, PC, ProgramID
</pre>

<ul>
<li>
		الجدول 2:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_23" style="">
<span class="typ">ProgramID</span><span class="pln"> </span><span class="pun">—&gt;</span><span class="pln"> </span><span class="typ">ProgramName</span></pre>

<p>
	لكن لا نزال بحاجة إلى مفتاح خارجي FK في جدول الطالب لنتمكن من تحديد البرنامج الذي سُجِّل الطالب به.
</p>

<h3>
	الاتحاد Union
</h3>

<p>
	تشير هذه القاعدة إلى أنه إذا كان جدولان منفصلان، والمفتاح الرئيسي PK هو نفسه، فقد ترغب في وضع الجدولين معًا، حيث تنص هذه القاعدة على أنه إذا كانت X تحدِّد Y، وX تحدِّد Z، فيجب على X أن تحدِّد Y وZ أيضًا، أي كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="78966" href="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForTheUnionRule.png.3117ddaf894dea5bcad74244342db905.png" rel=""><img alt="EquationForTheUnionRule.png" class="ipsImage ipsImage_thumbnailed" data-fileid="78966" data-unique="4i019xvhi" src="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForTheUnionRule.png.3117ddaf894dea5bcad74244342db905.png"></a>
</p>

<p>
	افترض على سبيل المثال أنّ:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_25" style="">
<span class="pln">SIN </span><span class="pun">—&gt;</span><span class="pln"> </span><span class="typ">EmpName</span><span class="pln">
SIN </span><span class="pun">—&gt;</span><span class="pln"> </span><span class="typ">SpouseName</span></pre>

<p>
	قد ترغب في ضم هذين الجدولين في جدول واحد على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6801_42" style="">
<span class="pln">SIN </span><span class="pun">–&gt;</span><span class="pln"> </span><span class="typ">EmpName</span><span class="pun">,</span><span class="pln"> </span><span class="typ">SpouseName</span></pre>

<p>
	قد يختار بعض <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">مسؤولي قاعدة البيانات</a> database administrators -أو DBA اختصارًا- الاحتفاظ بهذه الجداول مفصولةً لسببين، هما: السبب الأول هو أنّ كل جدول يصِف كيانًا مختلفًا، لذلك يجب إبقاء الكيانات منفصلةً عن بعضها البعض، والسبب الثاني هو إذا تُرِك اسم الزوج/ـة SpouseName فارغًا NULL في معظم الأوقات، فلا حاجة إلى تضمينه في نفس جدول اسم الموظّف EmpName.
</p>

<h3>
	التفكك Decomposition
</h3>

<p>
	التفكُّك Decomposition هو عكس قاعدة الاتحاد Union، فإذا كان لديك جدولًا يبدو أنه يحتوي على كيانين يحدِّدهما المفتاح الرئيسي PK نفسه، فستفكِّر في تقسيمه إلى جدولين، حيث تنص هذه القاعدة على أنه إذا كانت X تحدِّد Y وZ، فستكون X تحدِّد Y، وX تحدِّد Z بصورةٍ منفصلة، أي كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="78965" href="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForDecompensationRule.png.ed47e3e1a00d7f98bc88bffb33677881.png" rel=""><img alt="EquationForDecompensationRule.png" class="ipsImage ipsImage_thumbnailed" data-fileid="78965" data-unique="yczn6yive" src="https://academy.hsoub.com/uploads/monthly_2021_10/EquationForDecompensationRule.png.ed47e3e1a00d7f98bc88bffb33677881.png"></a>
</p>

<h2>
	مخطط الاعتمادية Dependency Diagram
</h2>

<p>
	يوضِّح مخطط الاعتمادية والمبيَّن في الشكل الآتي العديد من الاعتماديات المختلفة التي قد تكون موجودةً في جدول لم تطبَّقٍ عليه عملية التوحيد non-normalized table، أي الجدول الذي يحتوي على تكرار بيانات.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="93998" href="https://academy.hsoub.com/uploads/monthly_2022_03/DependencyDiagram.thumb.png.15de7a4dbdcf80bee426fa630b6e4058.png" rel=""><img alt="DependencyDiagram.thumb.png" class="ipsImage ipsImage_thumbnailed" data-fileid="93998" data-unique="tgtkednbi" src="https://academy.hsoub.com/uploads/monthly_2022_03/DependencyDiagram.thumb.thumb.png.20d4b65295d31bab648c6848d6c1c83b.png" style="width: 550px; height: auto;"></a>
</p>

<p>
	تُحدَّد الاعتماديات التالية في هذا الجدول كما يلي:
</p>

<ul>
<li>
		يتألف المفتاح الأساسي من مجموع ProjectNo وEmpNo.
	</li>
	<li>
		الاعتماديات الجزئية PDs:
		<ul>
<li>
				ProjName &lt;— ProjectNo.
			</li>
			<li>
				EmpName, DeptNo &lt;— EmpNo.
			</li>
			<li>
				HrsWork &lt;— ProjectNo, EmpNo.
			</li>
		</ul>
</li>
	<li>
		الاعتمادية المتعددية Transitive Dependency:
		<ul>
<li>
				DeptName &lt;—DeptNo.
			</li>
		</ul>
</li>
</ul>
<p>
	ترجمة -وبتصرف- للمقال <a href="https://opentextbc.ca/dbdesign01/chapter/chapter-11-functional-dependencies/" rel="external nofollow">Functional Dependencies</a> لصاحبته Adrienne Watt.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/devops/servers/databases/%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AD%D9%8A%D8%AF-normalization-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r551/" rel="">فهم عملية التوحيد Normalization المستخدمة عند تصميم قاعدة البيانات</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D9%8A-er-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r545/" rel="">نمذجة الكيان العلاقي ER عند تصميم قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D9%88%D9%82%D9%8A%D9%88%D8%AF%D9%87%D8%A7-%D9%84%D8%B6%D9%85%D8%A7%D9%86-%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r544/" rel="">قواعد السلامة وقيودها لضمان سلامة البيانات في قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">المفاهيم الأساسية في قواعد البيانات وتصميمها</a>
	</li>
	<li>
		النسخة العربية الكاملة لكتاب <a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تصميم قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">546</guid><pubDate>Sat, 23 Oct 2021 14:05:00 +0000</pubDate></item><item><title>&#x646;&#x645;&#x630;&#x62C;&#x629; &#x627;&#x644;&#x643;&#x64A;&#x627;&#x646; &#x627;&#x644;&#x639;&#x644;&#x627;&#x642;&#x64A; ER &#x639;&#x646;&#x62F; &#x62A;&#x635;&#x645;&#x64A;&#x645; &#x642;&#x648;&#x627;&#x639;&#x62F; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D9%8A-er-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r545/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/6165212346d9a_------.png.d88e61f440d6bc935c7e50312e250582.png" /></p>

<p>
	تتضمن إحدى النظريات المهمة التي طُوِّرت <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D9%8A-er-%D8%B9%D9%86%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r545/" rel="">لنموذج الكيان العلاقي entity relational</a> -واختصارًا ER- فكرة الاعتمادية الوظيفية functional dependency -أو FD اختصارًا-، والهدف من دراستها هو تحسين فهمك للعلاقات بين البيانات، واكتساب المنهجية الكافية للمساعدة في التصميم العملي لقاعدة البيانات.
</p>

<p>
	تُستخلَص <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r546/" rel="">الاعتماديات الوظيفية FD</a> من دلالات semantics نطاق التطبيق، أي مثل القيود constraints التي شرحناها في المقال السابق، وتصِف كيفية ارتباط السمات المنفصلة individual attributes ببعضها البعض، كما تُعَدّ الاعتماديات الوظيفية FD نوعًا من القيود بين السمات داخل علاقة، وتساهم في تصميم مخطط علاقي جيد، حيث سنلقي في هذا المقال نظرةً على:
</p>

<ul>
<li>
		نظرية الاعتمادية الوظيفية الأساسية وتعريفها.
	</li>
	<li>
		منهجية تحسين تصميمات المخططات، وتسمى أيضًا التوحيد normalization.
	</li>
</ul>
<h2>
	التصميم العلاقي Relational Design والتكرار Redundancy
</h2>

<p>
	يجب احتواء <a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r521/" rel="">التصميم الجيد لقاعدة البيانات العلاقية</a> على جميع السمات والارتباطات الضرورية، حيث يجب أن يقوم التصميم بذلك بأقل قدرٍ ممكن من المعلومات المخزَّنة مع عدم وجود بيانات مكرَّرة redundant.
</p>

<p>
	يُعَدّ التكرار أمرًا غير مرغوب فيه في تصميم قاعدة البيانات، وذلك لأنه يسبب مشاكلًا في الحفاظ على التناسق بعد التحديثات، لكن يمكن أن يؤدي التكرار إلى تحسينات في الأداء في بعض الأحيان مثل إمكانية استخدام التكرار بدلًا من عملية الضم join لربط البيانات، حيث تُستخدَم عملية <a href="https://academy.hsoub.com/programming/sql/%D8%A7%D9%84%D8%AF%D9%85%D8%AC-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D9%88%D9%84-%D9%81%D9%8A-sql-r849/" rel="">الضم join</a> عند الحاجة إلى الحصول على معلومات تستند إلى جدولين مرتبطين.
</p>

<p>
	ضع في بالك الشكل الآتي الذي يوضِّح مثالًا عن التكرار المُستخدَم في الحسابات المصرفية Bank Accounts، وفروع المصرف Branches، حيث يَظهر العميل رقم 1313131 مرتين، أي مرةً للحساب ذو الرقم A-101، ومرةً أخرى للحساب رقم A-102؛ إذ لا يكون رقم العميل زائدًا في هذه الحالة على الرغم من وجود حالات حذفٍ شاذة deletion anomalies في الجدول، وسيحل هذه المشكلة وجود جدول منفصل للعملاء.
</p>

<p>
	إذا تغير عنوان الفرع branch address، فيجب تحديثه في أماكن متعددة، وإذا تُرِك رقم العميل في الجدول كما هو، فلن تحتاج إلى جدول للفرع branch، ولن تكون هناك حاجة إلى عملية ضم، وبالتالي، سيتحسّن الأداء.
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
<thead><tr>
<th>
				accountNo
			</th>
			<th>
				blance
			</th>
			<th>
				customer
			</th>
			<th>
				branch
			</th>
			<th>
				address
			</th>
			<th>
				assets
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				A-101
			</td>
			<td>
				500
			</td>
			<td>
				1313131
			</td>
			<td>
				Downtown
			</td>
			<td>
				Brooklyn
			</td>
			<td>
				9000000
			</td>
		</tr>
<tr>
<td>
				A-102
			</td>
			<td>
				400
			</td>
			<td>
				1313131
			</td>
			<td>
				Perryridge
			</td>
			<td>
				Horseneck
			</td>
			<td>
				1700000
			</td>
		</tr>
<tr>
<td>
				A-113
			</td>
			<td>
				600
			</td>
			<td>
				9876543
			</td>
			<td>
				Round Hill
			</td>
			<td>
				Horseneck
			</td>
			<td>
				8000000
			</td>
		</tr>
<tr>
<td>
				A-201
			</td>
			<td>
				900
			</td>
			<td>
				9676543
			</td>
			<td>
				brighton
			</td>
			<td>
				Brooklyn
			</td>
			<td>
				7100000
			</td>
		</tr>
<tr>
<td>
				A-215
			</td>
			<td>
				700
			</td>
			<td>
				1111111
			</td>
			<td>
				Manus
			</td>
			<td>
				Horseneck
			</td>
			<td>
				400000
			</td>
		</tr>
<tr>
<td>
				A-222
			</td>
			<td>
				700
			</td>
			<td>
				1111111
			</td>
			<td>
				Redwood
			</td>
			<td>
				Palo Alto
			</td>
			<td>
				2100000
			</td>
		</tr>
<tr>
<td>
				A-305
			</td>
			<td>
				350
			</td>
			<td>
				1234567
			</td>
			<td>
				Round Hill
			</td>
			<td>
				Horseneck
			</td>
			<td>
				8000000
			</td>
		</tr>
</tbody>
</table>
<h2>
	التعديلات الشاذة على جداول قاعدة البيانات
</h2>

<p>
	سنعرض أشهر الحالات الشاذة التي تحدث نتيجة إجراء تعديلات من إدخل أو تعديل أو حذف على قاعدة البيانات كما سنضرب مثالًا لذلك.
</p>

<h3>
	حالة الإدخال الشاذة Insertion Anomaly
</h3>

<p>
	تحدث هذه الحالة عند إدخال معلومات متضاربة في جدول، حيث نحتاج إلى التحقق من أن بيانات الفرع branch متوافقة مع الصفوف الموجودة عندما ندخل سجلًا جديدًا مثل رقم الحساب A-306، كما في الشكل التالي:
</p>

<table>
<thead><tr>
<th>
				accountNo
			</th>
			<th>
				blance
			</th>
			<th>
				customer
			</th>
			<th>
				branch
			</th>
			<th>
				address
			</th>
			<th>
				assets
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				A-101
			</td>
			<td>
				500
			</td>
			<td>
				1313131
			</td>
			<td>
				Downtown
			</td>
			<td>
				Brooklyn
			</td>
			<td>
				9000000
			</td>
		</tr>
<tr>
<td>
				A-102
			</td>
			<td>
				400
			</td>
			<td>
				1313131
			</td>
			<td>
				Perryridge
			</td>
			<td>
				Horseneck
			</td>
			<td>
				1700000
			</td>
		</tr>
<tr>
<td>
				A-113
			</td>
			<td>
				600
			</td>
			<td>
				9876543
			</td>
			<td>
				Round Hill
			</td>
			<td>
				Horseneck
			</td>
			<td>
				8000000
			</td>
		</tr>
<tr>
<td>
				A-201
			</td>
			<td>
				900
			</td>
			<td>
				9676543
			</td>
			<td>
				brighton
			</td>
			<td>
				Brooklyn
			</td>
			<td>
				7100000
			</td>
		</tr>
<tr>
<td>
				A-215
			</td>
			<td>
				700
			</td>
			<td>
				1111111
			</td>
			<td>
				Manus
			</td>
			<td>
				Horseneck
			</td>
			<td>
				400000
			</td>
		</tr>
<tr>
<td>
				A-222
			</td>
			<td>
				700
			</td>
			<td>
				1111111
			</td>
			<td>
				Redwood
			</td>
			<td>
				Palo Alto
			</td>
			<td>
				2100000
			</td>
		</tr>
<tr>
<td>
				A-305
			</td>
			<td>
				350
			</td>
			<td>
				1234567
			</td>
			<td>
				Round Hill
			</td>
			<td>
				Horseneck
			</td>
			<td>
				8000000
			</td>
		</tr>
</tbody>
</table>
<h3>
	حالة التحديث الشاذة Update Anomaly
</h3>

<p>
	إذا غيّر أحد فروع المصرف عنوانه مثل الفرع راوند هيل Round Hill في الشكل الآتي، فنحن بحاجة إلى تحديث جميع الصفوف التي تشير إلى هذا الفرع، حيث يسمّى تغيير المعلومات الموجودة بصورة غير صحيحة بحالة تحديث شاذة.
</p>

<table>
<thead><tr>
<th>
				accountNo
			</th>
			<th>
				blance
			</th>
			<th>
				customer
			</th>
			<th>
				branch
			</th>
			<th>
				address
			</th>
			<th>
				assets
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				A-101
			</td>
			<td>
				500
			</td>
			<td>
				1313131
			</td>
			<td>
				Downtown
			</td>
			<td>
				Brooklyn
			</td>
			<td>
				9000000
			</td>
		</tr>
<tr>
<td>
				A-102
			</td>
			<td>
				400
			</td>
			<td>
				1313131
			</td>
			<td>
				Perryridge
			</td>
			<td>
				Horseneck
			</td>
			<td>
				1700000
			</td>
		</tr>
<tr>
<td>
				A-113
			</td>
			<td>
				600
			</td>
			<td>
				9876543
			</td>
			<td>
				Round Hill
			</td>
			<td>
				Horseneck
			</td>
			<td>
				8000000
			</td>
		</tr>
<tr>
<td>
				A-201
			</td>
			<td>
				900
			</td>
			<td>
				9676543
			</td>
			<td>
				brighton
			</td>
			<td>
				Brooklyn
			</td>
			<td>
				7100000
			</td>
		</tr>
<tr>
<td>
				A-215
			</td>
			<td>
				700
			</td>
			<td>
				1111111
			</td>
			<td>
				Manus
			</td>
			<td>
				Horseneck
			</td>
			<td>
				400000
			</td>
		</tr>
<tr>
<td>
				A-222
			</td>
			<td>
				700
			</td>
			<td>
				1111111
			</td>
			<td>
				Redwood
			</td>
			<td>
				Palo Alto
			</td>
			<td>
				2100000
			</td>
		</tr>
<tr>
<td>
				A-305
			</td>
			<td>
				350
			</td>
			<td>
				1234567
			</td>
			<td>
				Round Hill
			</td>
			<td>
				Horseneck
			</td>
			<td>
				8000000
			</td>
		</tr>
<tr>
<td>
				A-306
			</td>
			<td>
				800
			</td>
			<td>
				1111111
			</td>
			<td>
				Round Hill
			</td>
			<td>
				Horseneck
			</td>
			<td>
				8000800
			</td>
		</tr>
</tbody>
</table>
<h3>
	حالة الحذف الشاذة Deletion Anomaly
</h3>

<p>
	تحدث هذه الحالة عند حذف سجل قد يحتوي على سمات لا ينبغي حذفها، إذا أزلنا معلومات حول الحساب الأخير في أحد الفروع، مثل الحساب رقم A-101 في الفرع داون تاون Downtown في الشكل التالي على سبيل المثال، فستختفي جميع معلومات ذلك الفرع.
</p>

<table>
<thead><tr>
<th>
				accountNo
			</th>
			<th>
				blance
			</th>
			<th>
				customer
			</th>
			<th>
				branch
			</th>
			<th>
				address
			</th>
			<th>
				assets
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				A-101
			</td>
			<td>
				500
			</td>
			<td>
				1313131
			</td>
			<td>
				Downtown
			</td>
			<td>
				Brooklyn
			</td>
			<td>
				9000000
			</td>
		</tr>
<tr>
<td>
				A-102
			</td>
			<td>
				400
			</td>
			<td>
				1313131
			</td>
			<td>
				Perryridge
			</td>
			<td>
				Horseneck
			</td>
			<td>
				1700000
			</td>
		</tr>
<tr>
<td>
				A-113
			</td>
			<td>
				600
			</td>
			<td>
				9876543
			</td>
			<td>
				Round Hill
			</td>
			<td>
				Horseneck
			</td>
			<td>
				8000000
			</td>
		</tr>
<tr>
<td>
				A-201
			</td>
			<td>
				900
			</td>
			<td>
				9676543
			</td>
			<td>
				brighton
			</td>
			<td>
				Brooklyn
			</td>
			<td>
				7100000
			</td>
		</tr>
<tr>
<td>
				A-215
			</td>
			<td>
				700
			</td>
			<td>
				1111111
			</td>
			<td>
				Manus
			</td>
			<td>
				Horseneck
			</td>
			<td>
				400000
			</td>
		</tr>
<tr>
<td>
				A-222
			</td>
			<td>
				700
			</td>
			<td>
				1111111
			</td>
			<td>
				Redwood
			</td>
			<td>
				Palo Alto
			</td>
			<td>
				2100000
			</td>
		</tr>
<tr>
<td>
				A-305
			</td>
			<td>
				350
			</td>
			<td>
				1234567
			</td>
			<td>
				Round Hill
			</td>
			<td>
				Horseneck
			</td>
			<td>
				8000000
			</td>
		</tr>
</tbody>
</table>
<p>
	مشكلة حذف الصف A-101 هي عدم معرفتنا مكان الفرع Downtown، وأننا سنفقد جميع المعلومات المتعلقة بالعميل 1313131.
</p>

<p>
	نحتاج إلى تفكيك الجدول الأصلي إلى جداول أصغر متعددة بحيث يكون لكل جدول حدًا أدنى من التداخل مع الجداول الأخرى، وذلك لتجنب هذه الأنواع من مشاكل التحديث أو الحذف.
</p>

<p>
	يجب احتواء كل جدول حساب مصرفي على معلومات حول كيان entity واحد فقط، مثل: الفرع Branch، أو العميل Customer، كما هو موضح في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="78954" href="https://academy.hsoub.com/uploads/monthly_2021_10/ExamplesOfBankAccountTablesThatContainOneEntityEach.png.03d2ded911d37c2baa097b3ff4672331.png" rel=""><img alt="ExamplesOfBankAccountTablesThatContainOneEntityEach.png" class="ipsImage ipsImage_thumbnailed" data-fileid="78954" data-unique="ctfb2p4pb" src="https://academy.hsoub.com/uploads/monthly_2021_10/ExamplesOfBankAccountTablesThatContainOneEntityEach.png.03d2ded911d37c2baa097b3ff4672331.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	سيضمن اتباع هذه العملية أن إضافة معلومات الفرع أو تحديثها سيؤثر على سجل واحد فقط، لذلك لن تعدَّل معلومات الفرع عن طريق الخطأ، ولن تُسجَّل بصورة غير صحيحة، عند إضافة معلومات العميل أو حذفها.
</p>

<h3>
	مثال تطبيقي عن جدول مشروع-موظف والحالات الشاذة
</h3>

<p>
	يوضِّح الشكل الآتي مثالًا لجدول مشروع-موظف employee project table، كما يمكننا الافتراض من هذا الجدول أن:
</p>

<ol>
<li>
		معرِّف الموظف EmpID، ومعرِّف المشروع ProjectID هما مفتاح رئيسي مركَّب composite PK.
	</li>
	<li>
		يحدد معرِّف المشروع الميزانية Budget، أي أنّ للمشروع P1 ميزانيةً لفترة 32 ساعة.
	</li>
</ol>
<table>
<thead><tr>
<th>
				EmpID
			</th>
			<th>
				Budget
			</th>
			<th>
				ProjectID
			</th>
			<th>
				Hours
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				S75
			</td>
			<td>
				32
			</td>
			<td>
				P1
			</td>
			<td>
				7
			</td>
		</tr>
<tr>
<td>
				S75
			</td>
			<td>
				40
			</td>
			<td>
				P2
			</td>
			<td>
				3
			</td>
		</tr>
<tr>
<td>
				S79
			</td>
			<td>
				32
			</td>
			<td>
				P1
			</td>
			<td>
				4
			</td>
		</tr>
<tr>
<td>
				S79
			</td>
			<td>
				27
			</td>
			<td>
				P3
			</td>
			<td>
				1
			</td>
		</tr>
<tr>
<td>
				S80
			</td>
			<td>
				40
			</td>
			<td>
				P2
			</td>
			<td>
				5
			</td>
		</tr>
<tr>
<td>
				 
			</td>
			<td>
				17
			</td>
			<td>
				P4
			</td>
			<td>
				 
			</td>
		</tr>
</tbody>
</table>
<p>
	فيما يلي بعض الحالات الشاذة anomalies المحتملة التي قد تحدث مع هذا الجدول خلال الخطوات التالية:
</p>

<ol>
<li>
		الإجراء: إضافة الصف Add row الذي هو {S85,35,P1,9}.
	</li>
	<li>
		المشكلة: هناك صفان tuples بميزانيات متضاربة.
	</li>
	<li>
		الإجراء: حذف الصف Delete tuple الذي هو {S79, 27, P3, 1}.
	</li>
	<li>
		المشكلة: الخطوة رقم 3 تحذف ميزانية المشروع P3.
	</li>
	<li>
		الإجراء: تحديث الصف Update tuple من {S75, 32, P1, 7} إلى {S75, 35, P1, 7}.
	</li>
	<li>
		المشكلة: تُنشِئ الخطوة رقم 5 صفَّين بقيم مختلفة لميزانية المشروع P1.
	</li>
	<li>
		الحل: إنشاء جدول منفصل separate table لكل من المشاريع Projects والموظفين Employees، أي كما هو موضَّح في الشكل التالي:
	</li>
</ol>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="78956" href="https://academy.hsoub.com/uploads/monthly_2021_10/SeparateTablesForProjectAndEmployee.png.df64c44a6ecf8ef6e339874916142e72.png" rel=""><img alt="SeparateTablesForProjectAndEmployee.png" class="ipsImage ipsImage_thumbnailed" data-fileid="78956" data-unique="oigwq6k3a" src="https://academy.hsoub.com/uploads/monthly_2021_10/SeparateTablesForProjectAndEmployee.png.df64c44a6ecf8ef6e339874916142e72.png" style="width: 400px; height: auto;"></a>
</p>

<h3>
	كيفية تجنب الحالات الشاذة
</h3>

<p>
	أفضل طريقة لإنشاء جداول بدون حالات شاذة هي التأكد من توحيد الجداول، ويتحقق ذلك من خلال فهم الاعتماديات الوظيفية، حيث تضمن الاعتمادية الوظيفية FD في جدول انتماء جميع السمات attributes إلى هذا الجدول، أي ستزيل التكرار والحالات الشاذة.
</p>

<h3>
	مثال تطبيقي: جدولا المشاريع والموظفين المنفصلان
</h3>

<table>
<thead><tr>
<th>
				ProjectID
			</th>
			<th>
				Budeget
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				P1
			</td>
			<td>
				32
			</td>
		</tr>
<tr>
<td>
				P2
			</td>
			<td>
				40
			</td>
		</tr>
<tr>
<td>
				P3
			</td>
			<td>
				27
			</td>
		</tr>
<tr>
<td>
				P4
			</td>
			<td>
				17
			</td>
		</tr>
</tbody>
</table>
<p style="text-align: center;">
	جدول المشروع Project
</p>

<table>
<thead><tr>
<th>
				Emp ID
			</th>
			<th>
				Project ID
			</th>
			<th>
				Hours
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				S75
			</td>
			<td>
				P1
			</td>
			<td>
				7
			</td>
		</tr>
<tr>
<td>
				S75
			</td>
			<td>
				P2
			</td>
			<td>
				3
			</td>
		</tr>
<tr>
<td>
				S79
			</td>
			<td>
				P1
			</td>
			<td>
				4
			</td>
		</tr>
<tr>
<td>
				S79
			</td>
			<td>
				P3
			</td>
			<td>
				1
			</td>
		</tr>
<tr>
<td>
				S80
			</td>
			<td>
				P2
			</td>
			<td>
				5
			</td>
		</tr>
</tbody>
</table>
<p style="text-align: center;">
	جدول الموظف Employee
</p>

<p>
	يكون من خلال الاحتفاظ بالبيانات منفصلة باستخدام جدول مشاريع وجدول موظفين ما يلي:
</p>

<ul>
<li>
		لن تُنشَأ حالات شاذة إذا تغيرت الميزانية.
	</li>
	<li>
		ليست هناك حاجة إلى قيم وهمية للمشاريع التي لم يُعيَّن لها موظفون.
	</li>
	<li>
		إذا حُذِفت مساهمة موظف ما، فلن تُفقَد بيانات مهمة.
	</li>
	<li>
		لن تُنشَأ حالات شاذة إذا أُضيفت مساهمة موظف.
	</li>
</ul>
<h2>
	تمارين
</h2>

<p>
	أولًا، طبِّق التوحيد normalization على الشكل التالي:
</p>

<table>
<thead><tr>
<th>
				Attribute Name
			</th>
			<th>
				Sample Value
			</th>
			<th>
				Sample Value
			</th>
			<th>
				Sample Value
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				StudentID
			</td>
			<td>
				1
			</td>
			<td>
				2
			</td>
			<td>
				3
			</td>
		</tr>
<tr>
<td>
				StudentName
			</td>
			<td>
				John Smith
			</td>
			<td>
				Sandy Law
			</td>
			<td>
				Sue Rogers
			</td>
		</tr>
<tr>
<td>
				CourselD
			</td>
			<td>
				2
			</td>
			<td>
				2
			</td>
			<td>
				3
			</td>
		</tr>
<tr>
<td>
				CourseName
			</td>
			<td>
				Programming Level 1
			</td>
			<td>
				Programming Level 1
			</td>
			<td>
				Business
			</td>
		</tr>
<tr>
<td>
				Grade
			</td>
			<td>
				75%
			</td>
			<td>
				61%
			</td>
			<td>
				81%
			</td>
		</tr>
<tr>
<td>
				CourseDate
			</td>
			<td>
				Jan 5th, 2014
			</td>
			<td>
				Jan 5th, 2014
			</td>
			<td>
				Jan 7th, 2014
			</td>
		</tr>
</tbody>
</table>
<p>
	ثانيًا، أنشِئ مخطط ERD منطقي لخدمة تأجير الأفلام عبر الإنترنت، حيث لا توجد علاقات من النوع متعدد إلى متعدد many to many، واستخدم الوصف التالي للعمليات التي يجب أن تستند عليها قواعد عملك:
</p>

<p>
	تُصنِّف خدمة تأجير الأفلام عبر الإنترنت عناوين الأفلام وفقًا لنوعها إلى: الأفلام الكوميدية comedy، وأفلام الغرب الأمريكي western، والأفلام الكلاسيكية classical، وأفلام الخيال العلمي science fiction، وأفلام الرسوم المتحركة cartoon، وأفلام الحركة action، والأفلام الموسيقية musical، والأفلام المصدرة حديثًا new release.
</p>

<p>
	يحتوي كل نوع على العديد من العناوين المحتملة، وتتوفر نسخ copies متعددة لمعظم العناوين داخل النوع، فمثلًا، لاحظ الملخَّص التالي:
</p>

<ul>
<li>
		TYPE TITLE
	</li>
	<li>
		Musical My Fair Lady (Copy 1)
	</li>
	<li>
		My Fair Lady (Copy 2)
	</li>
	<li>
		Oklahoma (Copy 1)
	</li>
	<li>
		Oklahoma (Copy 2)
	</li>
	<li>
		Oklahoma (Copy 3)
	</li>
</ul>
<p>
	ثالثًا، ما هي الحالات الشاذة الثلاثة للبيانات التي من المحتمل تَشكّلها نتيجةً لتكرار البيانات؟ وكيف يمكن القضاء على مثل هذه الحالات الشاذة؟
</p>

<p>
	وسنتطرق في مقال لاحق لمثال عملي حول تصميم قاعدة بيانات كاملة من الصفر مثل تدريب عملي.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://opentextbc.ca/dbdesign01/chapter/chapter-10-er-modelling/" rel="external nofollow">ER Modelling</a> لصاحبته Adrienne Watt من كتاب <a href="https://opentextbc.ca/dbdesign01/" rel="external nofollow">Database Design</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r546/" rel="">الاعتماديات الوظيفية المستخدمة في تصميم قواعد البيانات</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D9%88%D9%82%D9%8A%D9%88%D8%AF%D9%87%D8%A7-%D9%84%D8%B6%D9%85%D8%A7%D9%86-%D8%B3%D9%84%D8%A7%D9%85%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r544/" rel="">قواعد السلامة وقيودها لضمان سلامة البيانات في قواعد البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D9%86%D9%85%D9%88%D8%B0%D8%AC-%D8%A7%D9%84%D9%83%D9%8A%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D8%A9-er-%D9%84%D8%AA%D9%85%D8%AB%D9%8A%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%AE%D8%B2%D9%8A%D9%86%D9%87%D8%A7-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r543/" rel="">نموذج الكيان والعلاقة ER لتمثيل البيانات وتخزينها في قاعدة البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">المفاهيم الأساسية في قواعد البيانات وتصميمها</a>
	</li>
	<li>
		النسخة العربية الكاملة لكتاب <a href="https://academy.hsoub.com/files/26-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">تصميم قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">545</guid><pubDate>Sun, 17 Oct 2021 14:07:00 +0000</pubDate></item></channel></rss>
