AbdullaScript

Writer
  • عدد منشوراتي

    29
  • تاريخ الإنضمام

  • تاريخ اخر زياره

السمعه بالموقع

13 Good

2 متابعين

عن العضو AbdullaScript

  • الرتبه
    مبدع مثابر
  • تاريخ الميلاد 01/24/91

معلومات عامة

  • الجنس
    ذكر
  • السكن
    مملكة البحرين
  • هواياتي
    Bodybuilding and web development

اخر الزوار

1834 زياره للملف الشخصي
  1. ماهو الcallback hell، جحيم الكولباك؟ لا يوجد شيء مميز في الجافا سكربت يسمى بجحيم الكولباك ما هو الا تسميه لأمر ما قد يقع فيه المطور وهو طريقة كتابة كود حيث يحتوي على عدة دوال Asynchronous مترابطة مع بعضها، واحدة داخل الاخرى، مثال: getData1(function(x){ getData2(x, function(y){ getData3(y, function(z){ ... }); }); }); والسبب في ذلك يعود لأن ناتج "results" كل دالة يعتمد على ما سبقتها. ملاحظة: كلمة asynchronous تعني أمر يحدث لاحقا << لا تركز على هالشي مو موضوعنا. جحيم الكولباك أمر ليس بجيد للكود، خصوصا في الحالات المعقدة التي تكون فيها دوال كثيرة مربوطه مع بعضها البعض وهنا قد يؤخر وقت انتهاء من التنفيذ و كمطور انت لا تريد ان تقع في هذه المشكلة, لحل مشكلة جحيم الكولباك، يستخدم المطورون إحدى مكتبات البرومس promises "الوعد، الوعود"، فالوعد دالة إما أن يتم العمل به fulfilled مع اظهار نتيجة الوعد value او رده rejected مع إظهار السبب error، وقد يكون الكود يحتوي على أكثر من وعد، واحد تلو الآخر. شخصيا لا اعتمد على الوعود في حل مشكلة جحيم الكولباك، عند التعامل مع قواعد البيانات MySQL رغم أنها الطريقة المثلى ولكن تتطلب الكثير مع الكود "وجهة نظر" و قد تواجهك مشاكل في أداء performance التطبيق بعد ذلك, استخدم طريقة أكثر بدائية و فعالة "تفي بالغرض" ، مبدأ الفكرة و طريقة عملها تتشابه كثيرا مع مبدأ عمل promises ولكن بكود أقل، سأرفق الطريقة مع المثال بالأسفل. للتعرف أكثر على جحيم الكولباك، سأعرض لكم مثال على التعامل مع قاعدة البيانات MySQL بالـ NodeJS وعمل اكثر من query وناتج كل query يعتمد على كل سبقتها. var express = require("express"); var app = express(); var mysql = require('mysql'); var conn = mysql.createConnection({ host: 'localhost', user: 'me', password: 'secret', database: 'my_db' }); conn.connect(); // GET method route app.get('/user/posts', function (req, res) { /* http://www.example.com/user/posts?userId=26 */ var userId = req.query.userId; conn.query('SELECT username FROM users WHERE ID = ?', [userId], function (error, results, fields) { if (error) throw error; if (results.length) { var username = results[0].username; conn.query('SELECT * FROM posts WHERE post_by = ?', [username], function (error, posts, fields) { if (error) throw error; if (posts.length) { conn.query('SELECT * FROM users_addresses WHERE username = ?', [username], function (error, address, fields) { if (error) throw error; if (statistics.length) { res.json(200, { posts: posts, address: address }); } else { res.json(200, { error: 'no statistics found' }); } }); } else { res.json(200, { error: 'no posts found' }); } }); } else { res.json(200, { error: 'no user found by ID 26' }); } }); }); للتخلص على مثل هذه المشاكل في حالة التعامل مع MySQL / MariaDB يكون بإسناد results كل عملية query في دالة مثلا var express = require("express"); var app = express(); var mysql = require('mysql'); var conn = mysql.createConnection({ host: 'localhost', user: 'me', password: 'secret', database: 'my_db' }); conn.connect(); // GET method route app.get('/user/posts', function (req, res) { /* http://www.example.com/user/posts?userId=26 */ var userId = req.query.userId; conn.query('SELECT username FROM users WHERE ID = ?', [userId], function (error, results, fields) { if (error) throw error; if (results.length) { setUsername(results[0].username); } else { res.json(200, { error: 'no user found by ID 26' }); } }); function setUsername(user) { var username = user; conn.query('SELECT * FROM posts WHERE post_by = ?', [username], function (error, posts, fields) { if (error) throw error; if (posts.length) { setPosts(posts, username); } else { res.json(200, { error: 'no posts found' }); } }); } function setPosts(po, user) { var posts = po; // po is the result of the prev query and it is an object it could be length of 1 or more doesn't matter var username = user; conn.query('SELECT * FROM users_addresses WHERE username = ?', [username], function (error, address, fields) { if (error) throw error; if (statistics.length) { res.json(200, { username: username, posts: posts, address: address }); } else { res.json(200, { error: 'no statistics found' }); } }); } }); أو بطريقة اخرى وهي عمل execution لكل query بطريقة parallel او series بإستخدام مكتبة async /* Make Sure To Install async npm install async --save */ var async = require(“async”); // Parallel Method async.parallel([ wait5SecondsAndReturn1, wait5SecondsAndReturn2 ], function (err, results){ //after 5 seconds, results will be [1, 2] }); function wait5SecondsAndReturn1(callback) { setTimeout(function(){ callback(null, 1); }, 5000); } function wait5SecondsAndReturn2(callback) { setTimeout(function(){ callback(null, 2); }, 5000); } //Series Method async.series([ wait5SecondsAndReturn1, wait5SecondsAndReturn2 ], function (err, results){ //after 10 seconds, results will be [1, 2] }); function wait5SecondsAndReturn1(callback) { setTimeout(function(){ callback(null, 1); }, 5000); } function wait5SecondsAndReturn2(callback) { setTimeout(function(){ callback(null, 2); }, 5000); } // Another one async.series([ function(callback) { setTimeout(function() { console.log(“Task 1”); callback(null, 1); }, 300); }, function(callback) { setTimeout(function() { console.log(“Task 2”); callback(null, 2); }, 200); }, function(callback) { setTimeout(function() { console.log(“Task 3“); callback(null, 3); }, 100); } ], function(error, results) { console.log(results); }); وبذلك تستطيع التخلص من جحيم الكولباك بدون promises التي يلقى الكثير من المبرمجين المبتدأئين صعوبة في التعامل مع هذا النوع من الدوال. ملاحظات حول المثال السابق: الأخذ بالاعتبار جميع الشروط من ان هذا المستخدم user لدية احصائية مسجله و بوستات, ان لم يكن تستطيع التخلص من الشرط if(posts.length) لا يهم , بالتالي سيتم تمرير اوبجكت بدون قيم. بعض المبرمجين قد لا يتفق مع العملية, احترم ذلك ولكنها تفي بالغرض مع ES2015 و مايليه .. اسناد اوبجكت الى متغير يعطيه نفس قيمه الاوبجكت بشكل مباشر.
  2. لا يخفى على الجميع تفوق لغة الجافاسكربت في الاونه الاخيره " منذ مدة في الحقيقة " بعد ظهور كمية كبيرة وضخمه جدا من المكتبات و أُطُر العمل libraries/frameworks، هذا التضخم و النمو السريع في لغة الجافاسكربت سببت ارباك لكثير من المبرمجين الذين أصبحوا لا يعرفون من اين البداية لدراسة هذه الفريمووركس واين النهايه خصوصا مع وجود تشابه مابينها بسبب المنافسة، على سبيل المثال: AngularJS VueJS ReactJS حيث يعد الإثنين أطر عمل Frontend، ومع التطور ظهر أطر عمل مساعدة لاطار عمل اساسي (ان صح التعبير بالعربي) "بطتنا بطت بطن بطتكم" مثل فريمورك ExpressJS المساعد لل Runtime Environment NodeJS حيث يعمل الإثنين في السيرفر وليس جهة المستخدم، وامثلة كثيرة اخرى لا يسعنا التطرق لهم ( يخرب بيتهم كل يوم شي جديد يطلع ويصدم اكثر من الي قبله ). في هذا الدرس سنقوم بعرض احد المكتبات المبرمجة بلغة الجافاسكربت "PressureJS" لعمل / لتطبيق فكرة الـ3D Touch الموجودة في اجهزة ابل الجديدة، والـ3D Touch هو عبارة عن الضغط بقوة اكثر من المعتاده على بعض الخيارات لإظهار خيارات اكثر او عمل، تفعيل event (حدث) معين. اولا: قم بتحميل المكتبه من خلال الضغط هنا او بإستخدام npm or bower. npm npm install pressure --save bower bower install pressure --save ثانيا: طرق استخدام المكتبة Example 1: <script src="/js/pressure.js"></script> <script src="/js/jquery.pressure.js"></script> Pressure.set('#id-name', { change: function(force){ this.innerHTML = force; } }); Example 2: var Pressure = require('pressure'); Pressure.set('#id-name', { change: function(force){ this.innerHTML = force; } }); كما هو موضح، التجربة ستكون على عنصر في الصفحة بدلالة الـId وهو id-name، تحتوي الدالة اعلاه على حدث event بإسم change تحمل متغير يسمى force، هذا الحدث change يستخدم لمعرفة التغير في قوة الضغط force على العنصر id-name ويكون المتغير force رقم مابين الصفر الى 1 كحد اقصى. ملاحظة: في المثال الذي سأطرحة حاليا، كلمة this ستنعني العنصر نفسه مثلا this.style.width Pressure.set('#element', { start: function(event){ }, end: function(){ // this is called on force end }, startDeepPress: function(event){ // this is called on "force click" / "deep press", aka once the force is greater than 0.5 }, endDeepPress: function(){ // this is called when the "force click" / "deep press" end }, change: function(force, event){ // this is called every time there is a change in pressure // force will always be a value from 0 to 1 on mobile and desktop }, unsupported: function(){ // NOTE: this is only called if the polyfill option is disabled! // this is called once there is a touch on the element and the device or browser does not support Force or 3D touch } }); او عند استخدامك الـjQuery // Select Element By Id $('#element').pressure({ // events goes here }); // Select Element By Class $('.element').pressure({ // events goes here }); لنستعرض الدالة اعلاة كل جزء على حدى: - يوجد 6 انواع من الأحداث events التي تعتمد عليها / تقدمها هذه المكتبه في كلاس Pressure وهم: حدث start: لمعرفة بدأ الضغط حدث end: لمعرفة انتهاء الضغط. حدث startDeepPress: اذا كانت قوة الضغط force اعلى من 0.5 وهي اعلى من نص القيمة العليا 1. حدث endDeepPress: عند الانتهاء من الضغط على العنصر وقيمة الضغط دخلت ضمن قيمة startDeepPress اي اعلى من 0.5. حدث change: وياخذ متغير force كما شرحناه بالاعلى، هذا الحدث سيستدعى دائما عند تغير قيمه الضغط مابين 0 و 1. حدث unsupported: اذا كان المتصفح او الجهاز لايدعم ال3D Touch. - الخيارات options، بالاضافة الى الاحداث والمتغيرات السابقة هناك ايضا متغير خارج دالة الset وهو عبارة عن اوبجكت اختياري يحتوي على عدة عناصر منها polyfill اما ان يكون true او false "يستخدم اذا كان المتصفح او الجهاز لايدعم ال3D Touch ،يكون true بشكل افتراضي. Pressure.set('#example', { change: function(force, event){ this.innerHTML = force; }, unsupported: function(){ alert("Oh no, this device does not support pressure."); } }, {polyfill: false}); - المتغير الثاني في الoptions هو polyfillSpeedUp عدد ms ويستخدم لتحديد سرعة الوصول من 0 الى 1، كل 1000 تساوي ثانية واحدة. Pressure.set('#example', { change: function(force, event){ this.innerHTML = force; } }, {polyfillSpeedUp: 5000}); // takes 5 seconds to go from a force value of 0 to 1 // only on devices that do not support pressure - المتغير polyfillSpeedDown عكس SpeedUp تماما, الوقت بالميلي سكند ms لرجوع قيمة قوة الضغط من 1 إلى 0. Pressure.set('#polyfill-speed-down', { change: function(force, event){ this.innerHTML = force; } }, {polyfillSpeedDown: 2000}); // takes 2 seconds to go from a force value of 1 to 0 // only on devices that do not support pressure - المتغير only اما ان يكون mouse, touch or pointer وهذا يعني عند الضغط على العنصر المراد تطبيق الـ3D Touch عليه اما ان يكون من خلال الفأرة فقط، الضغط بالاصبع فقط او بالبوينتر فقط. // فقط بالفأرة Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {only: 'mouse'}); // فقط عند الضغط بالاصبع, اجهزة ابل Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {only: 'touch'}); // فقط بالبوينتر ديفايسس مثل اجهزة تابلت الواكوم Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {only: 'pointer'}); - متغير preventSelect يعرفه الكثير بـpreventDefault. اما ان يكون true او false , قيمة المتغير تكون true افتراضيا وتستخدم لمنع العمل الافتراضي للعناصر. Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {preventSelect: false}); الجزء الأخير من PressureJS هو دالة لعمل Configuration عام تتشارك فيه جميع العناصر يحتوي على مجموعة من الخيارات التي تم شرحها في قسم Options مثلا. // These are the default configs set by Pressure Pressure.config({ polyfill: true, polyfillSpeedUp: 1000, polyfillSpeedDown: 0, preventSelect: true, only: null }); ولكن, تستطيع عمل override لهذه الاعدادات من خلال عمل دالة Pressure.set({...}); I وإسنادها إلى مجموعة عناصر او عنصر واحد بإستخدام الـId او الـClass. انتهى .. من لديه اسئلة يتفضل هنا او على حسابي في تويتر @AbdullaScript
  3. لا يخفى على الجميع تفوق لغة الجافاسكربت في الاونه الاخيره " منذ مدة في الحقيقة " بعد ظهور كمية كبيرة وضخمه جدا من المكتبات و أُطُر العمل libraries/frameworks، هذا التضخم و النمو السريع في لغة الجافاسكربت سببت ارباك لكثير من المبرمجين الذين أصبحوا لا يعرفون من اين البداية لدراسة هذه الفريمووركس واين النهايه خصوصا مع وجود تشابه مابينها بسبب المنافسة، على سبيل المثال: AngularJS VueJS ReactJS حيث يعد الإثنين أطر عمل Frontend، ومع التطور ظهر أطر عمل مساعدة لاطار عمل اساسي (ان صح التعبير بالعربي) "بطتنا بطت بطن بطتكم" مثل فريمورك ExpressJS المساعد لل Runtime Environment NodeJS حيث يعمل الإثنين في السيرفر وليس جهة المستخدم، وامثلة كثيرة اخرى لا يسعنا التطرق لهم ( يخرب بيتهم كل يوم شي جديد يطلع ويصدم اكثر من الي قبله ). في هذا الدرس سنقوم بعرض احد المكتبات المبرمجة بلغة الجافاسكربت "PressureJS" لعمل / لتطبيق فكرة الـ3D Touch الموجودة في اجهزة ابل الجديدة، والـ3D Touch هو عبارة عن الضغط بقوة اكثر من المعتاده على بعض الخيارات لإظهار خيارات اكثر او عمل، تفعيل event (حدث) معين. اولا: قم بتحميل المكتبه من خلال الضغط هنا او بإستخدام npm or bower. ثانيا: طرق استخدام المكتبة Example 1: <script src="/js/pressure.js"></script> <script src="/js/jquery.pressure.js"></script> Pressure.set('#id-name', { change: function(force){ this.innerHTML = force; } }); Example 2: var Pressure = require('pressure'); Pressure.set('#id-name', { change: function(force){ this.innerHTML = force; } }); كما هو موضح، التجربة ستكون على عنصر في الصفحة بدلالة الـId وهو id-name، تحتوي الدالة اعلاه على حدث event بإسم change تحمل متغير يسمى force، هذا الحدث change يستخدم لمعرفة التغير في قوة الضغط force على العنصر id-name ويكون المتغير force رقم مابين الصفر الى 1 كحد اقصى. ملاحظة: في المثال الذي سأطرحة حاليا، كلمة this ستنعني العنصر نفسه مثلا this.style.width Pressure.set('#element', { start: function(event){ }, end: function(){ // this is called on force end }, startDeepPress: function(event){ // this is called on "force click" / "deep press", aka once the force is greater than 0.5 }, endDeepPress: function(){ // this is called when the "force click" / "deep press" end }, change: function(force, event){ // this is called every time there is a change in pressure // force will always be a value from 0 to 1 on mobile and desktop }, unsupported: function(){ // NOTE: this is only called if the polyfill option is disabled! // this is called once there is a touch on the element and the device or browser does not support Force or 3D touch } }); او عند استخدامك الـjQuery // Select Element By Id $('#element').pressure({ // events goes here }); // Select Element By Class $('.element').pressure({ // events goes here }); لنستعرض الدالة اعلاة كل جزء على حدى: - يوجد 6 انواع من الأحداث events التي تعتمد عليها / تقدمها هذه المكتبه في كلاس Pressure وهم: حدث start: لمعرفة بدأ الضغط حدث end: لمعرفة انتهاء الضغط. حدث startDeepPress: اذا كانت قوة الضغط force اعلى من 0.5 وهي اعلى من نص القيمة العليا 1. حدث endDeepPress: عند الانتهاء من الضغط على العنصر وقيمة الضغط دخلت ضمن قيمة startDeepPress اي اعلى من 0.5. حدث change: وياخذ متغير force كما شرحناه بالاعلى، هذا الحدث سيستدعى دائما عند تغير قيمه الضغط مابين 0 و 1. حدث unsupported: اذا كان المتصفح او الجهاز لايدعم ال3D Touch. - الخيارات options، بالاضافة الى الاحداث والمتغيرات السابقة هناك ايضا متغير خارج دالة الset وهو عبارة عن اوبجكت اختياري يحتوي على عدة عناصر منها polyfill اما ان يكون true او false "يستخدم اذا كان المتصفح او الجهاز لايدعم ال3D Touch ،يكون true بشكل افتراضي. Pressure.set('#example', { change: function(force, event){ this.innerHTML = force; }, unsupported: function(){ alert("Oh no, this device does not support pressure."); } }, {polyfill: false}); - المتغير الثاني في الoptions هو polyfillSpeedUp عدد ms ويستخدم لتحديد سرعة الوصول من 0 الى 1، كل 1000 تساوي ثانية واحدة. Pressure.set('#example', { change: function(force, event){ this.innerHTML = force; } }, {polyfillSpeedUp: 5000}); // takes 5 seconds to go from a force value of 0 to 1 // only on devices that do not support pressure - المتغير polyfillSpeedDown عكس SpeedUp تماما, الوقت بالميلي سكند ms لرجوع قيمة قوة الضغط من 1 إلى 0. Pressure.set('#polyfill-speed-down', { change: function(force, event){ this.innerHTML = force; } }, {polyfillSpeedDown: 2000}); // takes 2 seconds to go from a force value of 1 to 0 // only on devices that do not support pressure - المتغير only اما ان يكون mouse, touch or pointer وهذا يعني عند الضغط على العنصر المراد تطبيق الـ3D Touch عليه اما ان يكون من خلال الفأرة فقط، الضغط بالاصبع فقط او بالبوينتر فقط. // فقط بالفأرة Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {only: 'mouse'}); // فقط عند الضغط بالاصبع, اجهزة ابل Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {only: 'touch'}); // فقط بالبوينتر ديفايسس مثل اجهزة تابلت الواكوم Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {only: 'pointer'}); - متغير preventSelect يعرفه الكثير بـpreventDefault. اما ان يكون true او false , قيمة المتغير تكون true افتراضيا وتستخدم لمنع العمل الافتراضي للعناصر. Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {preventSelect: false}); الجزء الأخير من PressureJS هو دالة لعمل Configuration عام تتشارك فيه جميع العناصر يحتوي على مجموعة من الخيارات التي تم شرحها في قسم Options مثلا. // These are the default configs set by Pressure Pressure.config({ polyfill: true, polyfillSpeedUp: 1000, polyfillSpeedDown: 0, preventSelect: true, only: null }); ولكن, تستطيع عمل override لهذه الاعدادات من خلال عمل دالة Pressure.set({...}); I وإسنادها إلى مجموعة عناصر او عنصر واحد بإستخدام الـId او الـClass. انتهى .. من لديه اسئلة يتفضل هنا او على حسابي في تويتر @AbdullaScript
  4. ولا يهمك نرتب الموضوع اكثر ونضيفها كمثال رابع بالتفصيل 🌹
  5. ماهو الcallback hell، جحيم الكولباك؟ لا يوجد شيء مميز في الجافا سكربت يسمى بجحيم الكولباك ما هو الا تسميه لأمر ما قد يقع فيه المطور وهو طريقة كتابة كود حيث يحتوي على عدة دوال Asynchronous مترابطة مع بعضها، واحدة داخل الاخرى، مثال: getData1(function(x){ getData2(x, function(y){ getData3(y, function(z){ ... }); }); }); والسبب في ذلك يعود لأن ناتج "results" كل دالة يعتمد على ما سبقتها. ملاحظة: كلمة asynchronous تعني أمر يحدث لاحقا << لا تركز على هالشي مو موضوعنا. جحيم الكولباك أمر ليس بجيد للكود، خصوصا في الحالات المعقدة التي تكون فيها دوال كثيرة مربوطه مع بعضها البعض وهنا قد يؤخر وقت انتهاء من التنفيذ و كمطور انت لا تريد ان تقع في هذه المشكلة, لحل مشكلة جحيم الكولباك، يستخدم المطورون إحدى مكتبات البرومس promises "الوعد، الوعود"، فالوعد دالة إما أن يتم العمل به fulfilled مع اظهار نتيجة الوعد value او رده rejected مع إظهار السبب error، وقد يكون الكود يحتوي على أكثر من وعد، واحد تلو الآخر. شخصيا لا اعتمد على الوعود في حل مشكلة جحيم الكولباك، عند التعامل مع قواعد البيانات MySQL رغم أنها الطريقة المثلى ولكن تتطلب الكثير مع الكود "وجهة نظر" و قد تواجهك مشاكل في أداء performance التطبيق بعد ذلك, استخدم طريقة أكثر بدائية و فعالة "تفي بالغرض" ، مبدأ الفكرة و طريقة عملها تتشابه كثيرا مع مبدأ عمل promises ولكن بكود أقل، سأرفق الطريقة مع المثال بالأسفل. للتعرف أكثر على جحيم الكولباك، سأعرض لكم مثال على التعامل مع قاعدة البيانات MySQL بالـ NodeJS وعمل اكثر من query وناتج كل query يعتمد على كل سبقتها. var express = require("express"); var app = express(); var mysql = require('mysql'); var conn = mysql.createConnection({ host: 'localhost', user: 'me', password: 'secret', database: 'my_db' }); conn.connect(); // GET method route app.get('/user/posts', function (req, res) { /* http://www.example.com/user/posts?userId=26 */ var userId = req.query.userId; conn.query('SELECT username FROM users WHERE ID = ?', [userId], function (error, results, fields) { if (error) throw error; if (results.length) { var username = results[0].username; conn.query('SELECT * FROM posts WHERE post_by = ?', [username], function (error, posts, fields) { if (error) throw error; if (posts.length) { conn.query('SELECT * FROM users_addresses WHERE username = ?', [username], function (error, address, fields) { if (error) throw error; if (statistics.length) { res.json(200, { posts: posts, address: address }); } else { res.json(200, { error: 'no statistics found' }); } }); } else { res.json(200, { error: 'no posts found' }); } }); } else { res.json(200, { error: 'no user found by ID 26' }); } }); }); للتخلص على مثل هذه المشاكل في حالة التعامل مع MySQL / MariaDB يكون بإسناد results كل عملية query في دالة مثلا var express = require("express"); var app = express(); var mysql = require('mysql'); var conn = mysql.createConnection({ host: 'localhost', user: 'me', password: 'secret', database: 'my_db' }); conn.connect(); // GET method route app.get('/user/posts', function (req, res) { /* http://www.example.com/user/posts?userId=26 */ var userId = req.query.userId; conn.query('SELECT username FROM users WHERE ID = ?', [userId], function (error, results, fields) { if (error) throw error; if (results.length) { setUsername(results[0].username); } else { res.json(200, { error: 'no user found by ID 26' }); } }); function setUsername(user) { var username = user; conn.query('SELECT * FROM posts WHERE post_by = ?', [username], function (error, posts, fields) { if (error) throw error; if (posts.length) { setPosts(posts, username); } else { res.json(200, { error: 'no posts found' }); } }); } function setPosts(po, user) { var posts = po; // po is the result of the prev query and it is an object it could be length of 1 or more doesn't matter var username = user; conn.query('SELECT * FROM users_addresses WHERE username = ?', [username], function (error, address, fields) { if (error) throw error; if (statistics.length) { res.json(200, { username: username, posts: posts, address: address }); } else { res.json(200, { error: 'no statistics found' }); } }); } }); أو بطريقة اخرى وهي عمل execution لكل query بطريقة parallel او series بإستخدام مكتبة async /* Make Sure To Install async npm install async --save */ var async = require(“async”); // Parallel Method async.parallel([ wait5SecondsAndReturn1, wait5SecondsAndReturn2 ], function (err, results){ //after 5 seconds, results will be [1, 2] }); function wait5SecondsAndReturn1(callback) { setTimeout(function(){ callback(null, 1); }, 5000); } function wait5SecondsAndReturn2(callback) { setTimeout(function(){ callback(null, 2); }, 5000); } //Series Method async.series([ wait5SecondsAndReturn1, wait5SecondsAndReturn2 ], function (err, results){ //after 10 seconds, results will be [1, 2] }); function wait5SecondsAndReturn1(callback) { setTimeout(function(){ callback(null, 1); }, 5000); } function wait5SecondsAndReturn2(callback) { setTimeout(function(){ callback(null, 2); }, 5000); } // Another one async.series([ function(callback) { setTimeout(function() { console.log(“Task 1”); callback(null, 1); }, 300); }, function(callback) { setTimeout(function() { console.log(“Task 2”); callback(null, 2); }, 200); }, function(callback) { setTimeout(function() { console.log(“Task 3“); callback(null, 3); }, 100); } ], function(error, results) { console.log(results); }); وبذلك تستطيع التخلص من جحيم الكولباك بدون promises التي يلقى الكثير من المبرمجين المبتدأئين صعوبة في التعامل مع هذا النوع من الدوال. ملاحظات حول المثال السابق: الأخذ بالاعتبار جميع الشروط من ان هذا المستخدم user لدية احصائية مسجله و بوستات, ان لم يكن تستطيع التخلص من الشرط if(posts.length) لا يهم , بالتالي سيتم تمرير اوبجكت بدون قيم. بعض المبرمجين قد لا يتفق مع العملية, احترم ذلك ولكنها تفي بالغرض مع ES2015 و مايليه .. اسناد اوبجكت الى متغير يعطيه نفس قيمه الاوبجكت بشكل مباشر.
  6. اذا، ماهو الـ connection pool؟ لربما سمعت بعبارة " الاتصال بقاعدة البيانات أمر مكلف " حيث كل اتصال على حدى يمر عبر سلسلة من الأمور منها الـ auth ( الى اخره) و عملية فتح و غلق الاتصال بقاعدة البيانات يعتبر مكلف للوقت و ريسورسس السيرفر, وبالعودة لـdocumentation الـMySQL في قسم B.5.2.7 Too many connections سنلاحظ حديث مطوري هذا النوع من قواعد البيانات عن الرقم المثالي والإفتراضي لعدد الاتصالات المسموح به لتقدم خدمة سريعة وهو 151 اتصال ( سابقا كان 100 اتصال فعال ) في حالة عمل الخدمة مع ويب سيرفر الـapache لتقديم خدمة افضل بالتالي وجب التنبيه بأن هناك عدد ما لكمية الاتصال بقاعدة البيانات. ولحل هذه المشكلة وجد ما يسمى بالـconnection pool الذي يعمل كناقل/ وسيط سريع بين الطلب و قاعدة البيانات ليقلل التكلفة (من الوقت و الريسورسس ) ويرفع و يزيد من الأداء اذا، ماهو / هي الـ connection pool فعليا؟ إن صح الوصف فهي عبارة عن بركة ( كما في الصوره اعلاه) تحتوي على مجموعة من الاتصالات بقاعدة البيانات مفتوحة وجاهزة للاستخدام المتكرر ( ولنفترض 10) والفائدة من ذلك توفير الوقت الذي يكون مابين اغلاق الاتصال و فتحه مرة أخرى لعملية أخرى another query بذلك وعند نفاذ كمية الاتصالات من البركة (اي ان هناك عدد معين من المستخدمين في نفس الوقت يستخدمون جميع قنوات الاتصال في هذه البركة ) يتم اضافة اتصال آخر بشكل اوتوماتيكي ( ليصبح مثلا 14 اتصال داخل البركة ) وعند الانتهاء يرجع للعدد الطبيعي (10) ويتم غلق هذه الاتصالات حمل ملف كيفية عمل كونفيقريشن لقاعدة البيانات و الـconnection pool في ملف مستقل واستخدامه في تطبيقك الـNodeJS. ملاحظة: استخدام الـ connection pool آمن جدا و مع وجود كمية اتصالات مفتوحة وفي المرحلة الاخير اي بعيدا عن connection parsing and authentication لا يعني ذلك عدم الأمان.
  7. السلام عليكم ورحمة الله وبركاته.. في هذا الدرس الثالث من دروس النود جي اس سنقوم بتعلم كيفية ضبط ويب سيرفر NGINX للعمل مع تطبيقات / مايكرو سيرفس الNodeJS و تحويل requests الى بورتات تطبيقاتك بشكل ضمني ماهو الnginx؟ ببساطة هو بروكسي سيرفر عالي الاداء او ويب سيرفر، بديل الapache. في ماذا يستخدم؟ يستخدم في ريفيرس بروكسي للبروتوكولات HTTP, HTTPS, SMTP, IMAP, POP3 و كذلك لعمل توازن الضغط على السيرفر مثلا عندما يكون هناك عدد كبير جدا من الrequests تستطيع توزيع هذه الطلبات بالupstream بين عدة بورتات في نفس السيرفر او سيرفر خارجي مثلا اذا كان التطبيق او الموقع مبرمج بالNodeJS. بالعربي: لا تحاتي بتعرف كلشي بعد شوي. اولا: تثبيت الويب سيرفر. لتثبيت الويب سيرفر nginx اتبع التعليمات / الخطوات التالية: افتح التيرمنال وقم بإيقاف الapache اذا كان مثبت sudo /etc/init.d/apache stop حدث sudo apt-get update ثبت sudo apt-get install nginx تأكد ان الويب سيرفر يعمل sudo /etc/init.d/nginx status ملاحظة: مهم جدا ايقاف Apache قبل تثبيت Nginx ثانيا: تشغيل تطبيقك الNode على الدومين الرئيسي. لتشغيل التطبيق عليك تحويل جميع الطلبات requests التي تأتي من العميل الى الPort الذي يعمل عليه التطبيق (3000 مثلا) عبر الويب سيرفر NGINX. ولعمل ذلك، افتح التيرمنال و قم بمتابعة هذه الاوامر اذهب لمجلد الويب سيرفر cd /etc/ngin/sites-available اكتب ls وسترى ملف بإسم default. افتح الملف للتعديل بإستخدام vim او nano وفي هذا الدرس سنستخدم الاول sudo vim default امسح كلشي واكتب هذا الكود server { listen 80 default_server; listen [::]:80 default_server; server_name www.example.com example.com; access_log /path/to/log/static_domain_access.log; location / { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_set_header X-NginX-Proxy true; proxy_pass http://127.0.0.1:3000; proxy_redirect off; } } اخيرا قم بإعادة تشغيل الويب سيرفر افتح المتصفح و اكتب موقعك http://www example.com Bonus إذا كان لديك تطبيق \ موقع كبير جدا او API و تريد عمل load balancing لتوزيع عمليه الطلبات في الصورتين ادناه الطريقة لذلك, لاحظ ان التطبيق يعمل على اكثر من بورت وكذلك الـproxy pass هو عباره عن اسم الـupstream .cluster تطبيق الNode كونفيقريشن الـNginx
  8. السلام عليكم ورحمة الله وبركاته.. في هذا الدرس الثالث من دروس النود جي اس سنقوم بتعلم كيفية ضبط ويب سيرفر NGINX للعمل مع تطبيقات / مايكرو سيرفس الNodeJS و تحويل requests الى بورتات تطبيقاتك بشكل ضمني ماهو الnginx؟ ببساطة هو بروكسي سيرفر عالي الاداء او ويب سيرفر، بديل الapache. في ماذا يستخدم؟ يستخدم في ريفيرس بروكسي للبروتوكولات HTTP, HTTPS, SMTP, IMAP, POP3 و كذلك لعمل توازن الضغط على السيرفر مثلا عندما يكون هناك عدد كبير جدا من الrequests تستطيع توزيع هذه الطلبات بالupstream بين عدة بورتات في نفس السيرفر او سيرفر خارجي مثلا اذا كان التطبيق او الموقع مبرمج بالNodeJS. بالعربي: لا تحاتي بتعرف كلشي بعد شوي. اولا: تثبيت الويب سيرفر. لتثبيت الويب سيرفر nginx اتبع التعليمات / الخطوات التالية: افتح التيرمنال وقم بإيقاف الapache اذا كان مثبت sudo /etc/init.d/apache stop حدث sudo apt-get update ثبت sudo apt-get install nginx تأكد ان الويب سيرفر يعمل sudo /etc/init.d/nginx status ملاحظة: مهم جدا ايقاف Apache قبل تثبيت Nginx ثانيا: تشغيل تطبيقك الNode على الدومين الرئيسي. لتشغيل التطبيق عليك تحويل جميع الطلبات requests التي تأتي من العميل الى الPort الذي يعمل عليه التطبيق (3000 مثلا) عبر الويب سيرفر NGINX. ولعمل ذلك، افتح التيرمنال و قم بمتابعة هذه الاوامر اذهب لمجلد الويب سيرفر cd /etc/ngin/sites-available اكتب ls وسترى ملف بإسم default. افتح الملف للتعديل بإستخدام vim او nano وفي هذا الدرس سنستخدم الاول sudo vim default امسح كلشي واكتب هذا الكود server { listen 80 default_server; listen [::]:80 default_server; server_name www.example.com example.com; access_log /path/to/log/static_domain_access.log; location / { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_set_header X-NginX-Proxy true; proxy_pass http://127.0.0.1:3000; proxy_redirect off; } } اخيرا قم بإعادة تشغيل الويب سيرفر افتح المتصفح و اكتب موقعك http://www example.com Bonus إذا كان لديك تطبيق \ موقع كبير جدا او API و تريد عمل load balancing لتوزيع عمليه الطلبات في الصورتين ادناه الطريقة لذلك, لاحظ ان التطبيق يعمل على اكثر من بورت وكذلك الـproxy pass هو عباره عن اسم الـupstream .cluster تطبيق الNode كونفيقريشن الـNginx
  9. السلام عليكم و رحمة الله و بركاته .. عودة الى الجزء الاول، وضحت كيفية ارسال بيانات من تطبيق الNode الى Pug وكيفية استقبال البيانات في الطرف الاخر و عرضها. في هذا الدرس سنتعامل مع قاعدة البيانات ونرسل البيانات بطريقتين مختلفتين: سيتم ارسال جميع البيانات من احد الجداول الى الواجهة و سأعرض لكم طريقة التعامل مع هذا النوع من البيانات المرسله سننشأه items عباره عن json objects وبعدها نرسلهم. الطريقة الأولى: و بالحديث عن قواعد البيانات، سنستخدم قاعدة بيانات MySQL هذه المره ( الرجاء الرجوع للدرس الاول للحصول على كافة التجهيزات لهذا الدرس). / هنا , انشأ قاعدة بيانات بإسم company وجدول employees مثلا ومن ثم اضف هذه المدخلات. -- phpMyAdmin SQL Dump -- version 4.5.4.1deb2ubuntu2 -- http://www.phpmyadmin.net -- -- Host: localhost -- Generation Time: Jun 09, 2017 at 10:41 AM -- Server version: 5.7.18-0ubuntu0.16.04.1 -- PHP Version: 7.1.5-1+deb.sury.org~xenial+2 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; /*!40101 SET @[email protected]@CHARACTER_SET_CLIENT */; /*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */; /*!40101 SET @[email protected]@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- -- Database: `company` -- -- -------------------------------------------------------- -- -- Table structure for table `employees` -- CREATE TABLE `employees` ( `ID` int(11) NOT NULL, `name` text COLLATE utf8_unicode_ci NOT NULL, `position` text COLLATE utf8_unicode_ci NOT NULL, `office` text COLLATE utf8_unicode_ci NOT NULL, `age` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -- -- Dumping data for table `employees` -- INSERT INTO `employees` (`ID`, `name`, `position`, `office`, `age`) VALUES (1, 'Airi Satou', 'Accountant', 'Tokyo', 23), (2, 'Airi Satou', 'Accountant', 'Tokyo', 23), (3, 'Donna Snider', 'Customer Support', 'New York', 27), (4, 'Brenden Wagner', 'Software Engineer', 'San Francisco', 28), (5, 'Caesar Vance', 'Pre-Sales Support', 'New York', 23), (6, 'Cedric Kelly', 'Senior Javascript Developer', 'Edinburgh', 22), (7, 'Dai Rios', 'Personnel Lead', 'Edinburgh', 35); -- -- Indexes for dumped tables -- -- -- Indexes for table `employees` -- ALTER TABLE `employees` ADD PRIMARY KEY (`ID`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `employees` -- ALTER TABLE `employees` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8; /*!40101 SET [email protected]_CHARACTER_SET_CLIENT */; /*!40101 SET [email protected]_CHARACTER_SET_RESULTS */; /*!40101 SET [email protected]_COLLATION_CONNECTION */; افتح ملف app.js و انشأ هذا الاوبجكت لعمل connection بين التطبيق وقاعدة البيانات // connection var connection = mysql.createConnection({ host : 'localhost', user : '...', password : '...', database : 'db_name' }); بعد ذلك، سنقوم بتعديل صفحة الـdetails في ملف app.js - المسار الذي يعرض صفحة الـdetails - لعمل Selection query app.get('/details', function(req, res) { connection.query('SELECT * From `employees`', function (error, results, fields) { if (error) throw error; console.log('The solution is: ', results); res.render('details', { title: 'Details - Pug ExpressJS NodeJS Tutorial', employees: results }); }); }); الـsyntax بسيط جدا، اولا connection وهو متغير التوصيل مم ثم query ثابته بعد ذلك الكويري &nbsp;ومن ثم الارقيومنتس (لمعلومات اكثر تجدونها هنا https://github.com/mysqljs/mysql/blob/master/Readme.md ) مخرجات اي query دائما ما يكون json object بالتالي متغير results هو عباره عن list of objects [ { "prop1":"value1", "prop2":"value2" }, { "prop1":"value3", "prop2":"value4" } ] نرجع إلى ملف details.pug ونقوم بتعديل block الجدول إلى التالي table#example.display.nowrap.dataTable.dtr-inline.collapsed(cellspacing='0') thead tr(role='row') th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Name: activate to sort column ascending', style='width: 142px;') Name th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Position: activate to sort column ascending', style='width: 192px;') Position th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Office: activate to sort column ascending', style='width: 89px;') Office th.dt-body-right.sorting_asc(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Age: activate to sort column descending', style='width: 37px;', aria-sort='ascending') Age tfoot tr th(rowspan='1', colspan='1') Name th(rowspan='1', colspan='1') Position th(rowspan='1', colspan='1') Office th.dt-body-right(rowspan='1', colspan='1') Age tbody for employee in employees tr.odd(role='row') td #{employee.name} td #{employee.position} td #{employee.office} td.dt-body-right.sorting_1 #{employee.age} نلاحظ وجود الـfor loop و طريقة استقبال وعرض المعلومات بسطر واحد فقط و ترجمته حرفيا ان لكل موظف في اوبجكت الموظفين ( الذي ارسلناه من الـNode ) قم بعمل صف في الجدول واضف مابعده for employee in employees tr.odd(role='row') td #{employee.name} td #{employee.position} td #{employee.office} td.dt-body-right.sorting_1 #{employee.age} بهذا انتهينا من الجزء الأول للدرس وننتقل للجزء الثاني: هذا الجزء من الدرس يتعلق بكيفية عمل items بشكل تخصيصي .. ان ماذا لو انك لا تريد ان تضم عمر الموظف في جدول العرض؟ سنقوم بالتالي في ملف app.js و details.pug - وكلشئ آخر يبقى كما هو: //app.js app.get('/details', function (req, res) { connection.query('SELECT * From `employees`', function (error, results, fields) { if (error) { throw error; } else { console.log('The solution is: ', results); var employees_json = []; for (var index = 0; index < results.length; index++) { var item = { name: results[index].name, position: results[index].position, office: results[index].office } employees_json.push(item); } res.render('details', { title: 'Details - Pug ExpressJS NodeJS Tutorial', employees: employees_json }); } }); }); //details.pug table#example.display.nowrap.dataTable.dtr-inline.collapsed(cellspacing='0') thead tr(role='row') th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Name: activate to sort column ascending', style='width: 142px;') Name th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Position: activate to sort column ascending', style='width: 192px;') Position th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Office: activate to sort column ascending', style='width: 89px;') Office //th.dt-body-right.sorting_asc(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Age: activate to sort column descending', style='width: 37px;', aria-sort='ascending') Age tfoot tr th(rowspan='1', colspan='1') Name th(rowspan='1', colspan='1') Position th(rowspan='1', colspan='1') Office th.dt-body-right(rowspan='1', colspan='1') Age tbody for employee in employees tr.odd(role='row') td #{employee.name} td #{employee.position} td #{employee.office} //td.dt-body-right.sorting_1 #{employee.age} إضغط هنا لتحميل ملفات الدرس الثاني anwbh-app-lesson2.zip
  10. السلام عليكم و رحمة الله و بركاته .. عودة الى الجزء الاول، وضحت كيفية ارسال بيانات من تطبيق الNode الى Pug وكيفية استقبال البيانات في الطرف الاخر و عرضها. في هذا الدرس سنتعامل مع قاعدة البيانات ونرسل البيانات بطريقتين مختلفتين: سيتم ارسال جميع البيانات من احد الجداول الى الواجهة و سأعرض لكم طريقة التعامل مع هذا النوع من البيانات المرسله سننشأه items عباره عن json objects وبعدها نرسلهم. الطريقة الأولى: و بالحديث عن قواعد البيانات، سنستخدم قاعدة بيانات MySQL هذه المره ( الرجاء الرجوع للدرس الاول للحصول على كافة التجهيزات لهذا الدرس). / هنا , انشأ قاعدة بيانات بإسم company وجدول employees مثلا ومن ثم اضف هذه المدخلات. -- phpMyAdmin SQL Dump -- version 4.5.4.1deb2ubuntu2 -- http://www.phpmyadmin.net -- -- Host: localhost -- Generation Time: Jun 09, 2017 at 10:41 AM -- Server version: 5.7.18-0ubuntu0.16.04.1 -- PHP Version: 7.1.5-1+deb.sury.org~xenial+2 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; /*!40101 SET @[email protected]@CHARACTER_SET_CLIENT */; /*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */; /*!40101 SET @[email protected]@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- -- Database: `company` -- -- -------------------------------------------------------- -- -- Table structure for table `employees` -- CREATE TABLE `employees` ( `ID` int(11) NOT NULL, `name` text COLLATE utf8_unicode_ci NOT NULL, `position` text COLLATE utf8_unicode_ci NOT NULL, `office` text COLLATE utf8_unicode_ci NOT NULL, `age` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -- -- Dumping data for table `employees` -- INSERT INTO `employees` (`ID`, `name`, `position`, `office`, `age`) VALUES (1, 'Airi Satou', 'Accountant', 'Tokyo', 23), (2, 'Airi Satou', 'Accountant', 'Tokyo', 23), (3, 'Donna Snider', 'Customer Support', 'New York', 27), (4, 'Brenden Wagner', 'Software Engineer', 'San Francisco', 28), (5, 'Caesar Vance', 'Pre-Sales Support', 'New York', 23), (6, 'Cedric Kelly', 'Senior Javascript Developer', 'Edinburgh', 22), (7, 'Dai Rios', 'Personnel Lead', 'Edinburgh', 35); -- -- Indexes for dumped tables -- -- -- Indexes for table `employees` -- ALTER TABLE `employees` ADD PRIMARY KEY (`ID`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `employees` -- ALTER TABLE `employees` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8; /*!40101 SET [email protected]_CHARACTER_SET_CLIENT */; /*!40101 SET [email protected]_CHARACTER_SET_RESULTS */; /*!40101 SET [email protected]_COLLATION_CONNECTION */; افتح ملف app.js و انشأ هذا الاوبجكت لعمل connection بين التطبيق وقاعدة البيانات // connection var connection = mysql.createConnection({ host : 'localhost', user : '...', password : '...', database : 'db_name' }); بعد ذلك، سنقوم بتعديل صفحة الـdetails في ملف app.js - المسار الذي يعرض صفحة الـdetails - لعمل Selection query app.get('/details', function(req, res) { connection.query('SELECT * From `employees`', function (error, results, fields) { if (error) throw error; console.log('The solution is: ', results); res.render('details', { title: 'Details - Pug ExpressJS NodeJS Tutorial', employees: results }); }); }); الـsyntax بسيط جدا، اولا connection وهو متغير التوصيل مم ثم query ثابته بعد ذلك الكويري &nbsp;ومن ثم الارقيومنتس (لمعلومات اكثر تجدونها هنا https://github.com/mysqljs/mysql/blob/master/Readme.md ) مخرجات اي query دائما ما يكون json object بالتالي متغير results هو عباره عن list of objects [ { "prop1":"value1", "prop2":"value2" }, { "prop1":"value3", "prop2":"value4" } ] نرجع إلى ملف details.pug ونقوم بتعديل block الجدول إلى التالي table#example.display.nowrap.dataTable.dtr-inline.collapsed(cellspacing='0') thead tr(role='row') th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Name: activate to sort column ascending', style='width: 142px;') Name th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Position: activate to sort column ascending', style='width: 192px;') Position th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Office: activate to sort column ascending', style='width: 89px;') Office th.dt-body-right.sorting_asc(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Age: activate to sort column descending', style='width: 37px;', aria-sort='ascending') Age tfoot tr th(rowspan='1', colspan='1') Name th(rowspan='1', colspan='1') Position th(rowspan='1', colspan='1') Office th.dt-body-right(rowspan='1', colspan='1') Age tbody for employee in employees tr.odd(role='row') td #{employee.name} td #{employee.position} td #{employee.office} td.dt-body-right.sorting_1 #{employee.age} نلاحظ وجود الـfor loop و طريقة استقبال وعرض المعلومات بسطر واحد فقط و ترجمته حرفيا ان لكل موظف في اوبجكت الموظفين ( الذي ارسلناه من الـNode ) قم بعمل صف في الجدول واضف مابعده for employee in employees tr.odd(role='row') td #{employee.name} td #{employee.position} td #{employee.office} td.dt-body-right.sorting_1 #{employee.age} بهذا انتهينا من الجزء الأول للدرس وننتقل للجزء الثاني: هذا الجزء من الدرس يتعلق بكيفية عمل items بشكل تخصيصي .. ان ماذا لو انك لا تريد ان تضم عمر الموظف في جدول العرض؟ سنقوم بالتالي في ملف app.js و details.pug - وكلشئ آخر يبقى كما هو: //app.js app.get('/details', function (req, res) { connection.query('SELECT * From `employees`', function (error, results, fields) { if (error) { throw error; } else { console.log('The solution is: ', results); var employees_json = []; for (var index = 0; index < results.length; index++) { var item = { name: results[index].name, position: results[index].position, office: results[index].office } employees_json.push(item); } res.render('details', { title: 'Details - Pug ExpressJS NodeJS Tutorial', employees: employees_json }); } }); }); //details.pug table#example.display.nowrap.dataTable.dtr-inline.collapsed(cellspacing='0') thead tr(role='row') th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Name: activate to sort column ascending', style='width: 142px;') Name th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Position: activate to sort column ascending', style='width: 192px;') Position th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Office: activate to sort column ascending', style='width: 89px;') Office //th.dt-body-right.sorting_asc(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Age: activate to sort column descending', style='width: 37px;', aria-sort='ascending') Age tfoot tr th(rowspan='1', colspan='1') Name th(rowspan='1', colspan='1') Position th(rowspan='1', colspan='1') Office th.dt-body-right(rowspan='1', colspan='1') Age tbody for employee in employees tr.odd(role='row') td #{employee.name} td #{employee.position} td #{employee.office} //td.dt-body-right.sorting_1 #{employee.age} إضغط هنا لتحميل ملفات الدرس الثاني anwbh-app-lesson2.zip
  11. السلام عليكم و رحمة الله و بركاته.. في هذا الموضوع سنتحدث عن عن علاقة إطار العمل ExpressJS مع الباترن NodeJS و كيفية عمل Pug as template engine اولا: حتى لا تكون هناك امور مبهمه و ابعاد الغيوم التي تدور حول اذهان الكثير من يريد العمل او التوجه لهذا الباترن يجب عرض بعض من الحقائق: الـNodeJS ليست لغة جديدة .. انما بيئة مبرمجة بالـJS. هذه البيئه تعمل في جهة السيرفر. ان كنت مبرمج AngularJS or ReactJS ليس هناك سطر محدد تربط فيه بين تطبيقك الNode مع الفريموورك الذي تعمل به. طريقة الربط تكون من خلال HTTP requests. تستطيع التعامل مع قواعد البيانات المختلفه مباشره بالـNode مثل MySQL, MariaDB و اشهرهم في هذا المجال هي MongoDB. نعود مرة اخرى للـExpressJS الذي هو يعتبر فريم وورك ابعد مما ان يقال عنه "مساعد" في تطبيقات الـNode. بإستخدام هذا الفريم وورك الذي يعمل كذلك في السيرفر، يتم تسهيل العمل و كمية الكود في تطبيق الـNode بشكل كبير جدا. مثال على تطبيق Node بإستخدام فريم وورك ExpressJS وسيتم شرح اجزائه جميعها var express = require('express'); var app = express(); app.get('/', function (req, res) { res.send('Hello World!') }); app.listen(3000, function () { console.log('Example app listening on port 3000!') }); اول سطرين استدعاء موديول الاكسبرس و من ثم دالة الاكسبرس في المتغير app الذي استخدمناه في صنع التطبيق. الشطر الثاني get هو عبارة عن نوع الـhttp request قد يكون GET, POST, DELETE, UPDATE etc …. بعد ذلك يأتي المسار - لتفاصيل اكثر حول هذا الجزء الرجاء زيارة الدرس السابق. نننقل الآن الى امر اخر في الـExpressJS وهو الـtemplating ( عمل الواجهات UI و استقبال البيانات المرسلة من الـNode ) لعمل الواجهات الديناميكيه يفضل استخدام محركات التمبليت التي تتوافق مع الاكسبرس وهي PUG - know as Jade Mustache EJS و في هذا الدرس سنستخدم المحرك الاول لعمل صفحة ويب اعتيادية و اخرى ديناميكية, لصنع واجهة بمحرك التمبليت pug يجب عليك ان تتقن او ان تاخذ فكره عن هذا المحرك لتعرف كيفية كتابه الكود ومثال على ذلك doctype html html(lang='en') head title Jade script(type='text/javascript'). foo = true; bar = function () {}; if (foo) { bar(1 + 5) } body h1 Jade - node template engine #container.col p You are amazing p | Jade is a terse and simple | templating language with a | strong focus on performance | and powerful features. يعادل في الHTML <!DOCTYPE html> <html lang="en"> <head> <title>Jade</title> <script type="text/javascript"> foo = true; bar = function () {}; if (foo) { bar(1 + 5) } </script> </head> <body> <h1>Jade - node template engine</h1> <div id="container" class="col"> <p>You are amazing</p> <p> Jade is a terse and simple templating language with a strong focus on performance and powerful features. </p> </div> </body> </html> لمعلومات اكثر حول اللغة اطلع على موقعهم الرسمي وبذلك سنقوم بإنشاء مجلدات ومستندات بهذه الطريقة حمل الـbootstrap وانقل كل من bootstrap.min.css إلى مجلد css , انقل bootstrap.min.js إلى مجلد js بعد ذلك إبدأ بتثبيت الـpackages التي سنعمل بها من خلال فتح الـterminal في مجلد myapp من خلال الاوامر التالية $ npm install express --save $ npm install cookie-parser --save $ npm install body-parser --save $ npm install mysql --save افتح ملف التطبيق app.js وقم بإستدعاء هذه البكجات var express = require('express'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var mysql = require('mysql'); الآن نبدأ بإعداد config فريم وورك الـExpressJS مع cookie-parser body-parser ( سنستخدمهم لاحقا ) var router = express.Router(); var app = express(); app.use(bodyParser.json({limit: "50mb"})); app.use(cookieParser()); var urlencodedParser = bodyParser.urlencoded({ extended: true, parameterLimit:50000 }); app.use("/", router); نضيف امكانية استخدام ملفات الـcss, js , images etc من خلال استخدام الـmiddleware ـexpress static بإعطاء مسار وهمي لهذه الملفات app.use('/css', express.static(__dirname + '/public/css')); app.use('/js', express.static(__dirname + '/public/js')); نرى وجود ملفات الـcss and js في مجلد public/css ولكن المسار الذي سنكتبه في الكود هو فقط css/ وليس بالضرورة ان يكون اسم المسار الوهمي ذو علاقه بالمسار الاساسي .. تستطيع ان تسميه مثلا sambosa/ و في الحقيقة هو public/css/ تحديد نوع الـtemplate engine الذي سنستخدمه في هذا التطبيق مع تحديد مسار مجلد الـviews الذي يحتوي على صفحات الموقع او التطبيق app.set('views', __dirname + '/views'); app.set('view engine', 'pug'); بعد إنشاء ملفات الـpug في إحدى الخطوات السابقه , انسخ والصق كود الصفحتين index.pug and layout.pug details.pug كلن على حدى //layout.pug doctype html html head title= title script(src='https://code.jquery.com/jquery-3.2.1.min.js') link(rel='stylesheet', href='/css/bootstrap.min.css') script(src='/js/bootstrap.min.js') body nav.navbar.navbar-default .container .navbar-header button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#navbar', aria-expanded='false', aria-controls='navbar') span.sr-only Toggle navigation span.icon-bar span.icon-bar span.icon-bar a.navbar-brand(href='/') NodeJS #navbar.navbar-collapse.collapse ul.nav.navbar-nav li.active a(href='/') Home li a(href='/details') details li.dropdown a.dropdown-toggle(href='#', data-toggle='dropdown', role='button', aria-haspopup='true', aria-expanded='false') | Dropdown span.caret ul.dropdown-menu li a(href='#') Action li a(href='#') Another action li a(href='#') Something else here li.divider(role='separator') li.dropdown-header Nav header li a(href='#') Separated link li a(href='#') One more separated link block content //index.pug extends layout block content .container h1 #{msg} p #{username} , welcome to the first templating tutorial //details.pug extends layout block content .container .table-responsive h2 user table p This is all users we have so far table.table.table-bordered#example thead tr th Firstname th Lastname th Email tbody tr td John td Doe td [email protected] tr td Mary td Moe td [email protected] tr td July td Dooley td [email protected] link(rel='stylesheet', type='text/css', href='https://cdn.datatables.net/v/dt/dt-1.10.15/datatables.min.css') script(type='text/javascript', src='https://cdn.datatables.net/v/dt/dt-1.10.15/datatables.min.js') script(). $(document).ready(function() { $('#example').DataTable(); }); ملاحظة: نستخدم extends layout لكي لا نكرر الـhead في الصفحات الاخرى , مثل include في الـPHP ( في هذا الدرس ) - الاستخدام الحقيقي للـlayout هو تصميم شكل معين لصفحات معينه .. كـtemplate خاص مثلا - معلومات اكثر من خلال الرابط هنا الأن تم تجهيز المستوى الأول من التطبيق وهو الـconfigurations , ننتقل إلى النص الآخر وهو الـroutes . اولا route الصفحة الرئيسية سيكون كالتالي app.get('/', function(req, res) { res.render('index', { title: 'Pug ExpressJS NodeJS Tutorial', username: 'abdulla', msg: 'Hey There!' }) }); نلاحظ ان مسار الـroute هو مجرد slash للامام .. بذلك يتم تحديد المسار الرئيسي للتطبيق, بعد ذلك res.render اي تعني response render حيث يقوم تطبيق الـNode بالأجابة من بعد عمل طلب request من طرف المستخدم , للتوضيح اكثر الـHTTP هو عباره عن بروتوكول طلب و اجابة وبذلك request and response - req, res فعند طلب العميل امر ما يجب عليه ان يحصل على شي ما في المقابل. و كما موضع في الدالة اعلاه ان الـresponse هو عباره عن عمل render لملف index.pug الموجود في مجلد views مع ارسال ثلاث متغيرات title, username and msg , و طريقة استقبال البيانات في الـpug هي كالتالي ( يوجد اكثر من طريقة ) h1 #{username} p Welcome to #{title} خطوة اخيره لتشغيل التطبيق يجب تحديد بورت معين ولنفترض 3000 app.listen(3000, function() { console.log('The app is running http://localhost:3000'); }); افتح الـterminal داخل مجلد التطبيق myapp واكتب الامر التالي لتشغيل التطبيق node app.js افتح المتطفح على المسار انتهى الدرس الاول .. تم من خلاله عمل configuration لتطبيق الـnode الذي سنستخدمه في الدروس القادمة تثبيت template engine و توصيله مع تطبيق الـNode ارسال بيانات من الـNode إلى pug الدرس القادم سيكون هناك سنعرض لكم كيفية التعامل مع قواعد البيانات وإرسال المعلومات الى pug للحصول على ملفات العمل تجدونهم في المرفقات, بعد تحميل الملف قم بفك الضغط انتقل إلى داخل المجلد واكتب الأمر التالي لتثبيت جميع الـpackages دفعة واحده $ npm install --save أضغط هنا لتحميل ملفات العمل anwbh-app.zip موقع مساعد لتحويل كودات الـHTML إلى Pug http://html2jade.org
  12. السلام عليكم و رحمة الله و بركاته.. في هذا الموضوع سنتحدث عن عن علاقة إطار العمل ExpressJS مع الباترن NodeJS و كيفية عمل Pug as template engine اولا: حتى لا تكون هناك امور مبهمه و ابعاد الغيوم التي تدور حول اذهان الكثير من يريد العمل او التوجه لهذا الباترن يجب عرض بعض من الحقائق: الـNodeJS ليست لغة جديدة .. انما بيئة مبرمجة بالـJS. هذه البيئه تعمل في جهة السيرفر. ان كنت مبرمج AngularJS or ReactJS ليس هناك سطر محدد تربط فيه بين تطبيقك الNode مع الفريموورك الذي تعمل به. طريقة الربط تكون من خلال HTTP requests. تستطيع التعامل مع قواعد البيانات المختلفه مباشره بالـNode مثل MySQL, MariaDB و اشهرهم في هذا المجال هي MongoDB. نعود مرة اخرى للـExpressJS الذي هو يعتبر فريم وورك ابعد مما ان يقال عنه "مساعد" في تطبيقات الـNode. بإستخدام هذا الفريم وورك الذي يعمل كذلك في السيرفر، يتم تسهيل العمل و كمية الكود في تطبيق الـNode بشكل كبير جدا. مثال على تطبيق Node بإستخدام فريم وورك ExpressJS وسيتم شرح اجزائه جميعها var express = require('express'); var app = express(); app.get('/', function (req, res) { res.send('Hello World!') }); app.listen(3000, function () { console.log('Example app listening on port 3000!') }); اول سطرين استدعاء موديول الاكسبرس و من ثم دالة الاكسبرس في المتغير app الذي استخدمناه في صنع التطبيق. الشطر الثاني get هو عبارة عن نوع الـhttp request قد يكون GET, POST, DELETE, UPDATE etc …. بعد ذلك يأتي المسار - لتفاصيل اكثر حول هذا الجزء الرجاء زيارة الدرس السابق. نننقل الآن الى امر اخر في الـExpressJS وهو الـtemplating ( عمل الواجهات UI و استقبال البيانات المرسلة من الـNode ) لعمل الواجهات الديناميكيه يفضل استخدام محركات التمبليت التي تتوافق مع الاكسبرس وهي PUG - know as Jade Mustache EJS و في هذا الدرس سنستخدم المحرك الاول لعمل صفحة ويب اعتيادية و اخرى ديناميكية, لصنع واجهة بمحرك التمبليت pug يجب عليك ان تتقن او ان تاخذ فكره عن هذا المحرك لتعرف كيفية كتابه الكود ومثال على ذلك doctype html html(lang='en') head title Jade script(type='text/javascript'). foo = true; bar = function () {}; if (foo) { bar(1 + 5) } body h1 Jade - node template engine #container.col p You are amazing p | Jade is a terse and simple | templating language with a | strong focus on performance | and powerful features. يعادل في الHTML <!DOCTYPE html> <html lang="en"> <head> <title>Jade</title> <script type="text/javascript"> foo = true; bar = function () {}; if (foo) { bar(1 + 5) } </script> </head> <body> <h1>Jade - node template engine</h1> <div id="container" class="col"> <p>You are amazing</p> <p> Jade is a terse and simple templating language with a strong focus on performance and powerful features. </p> </div> </body> </html> لمعلومات اكثر حول اللغة اطلع على موقعهم الرسمي وبذلك سنقوم بإنشاء مجلدات ومستندات بهذه الطريقة حمل الـbootstrap وانقل كل من bootstrap.min.css إلى مجلد css , انقل bootstrap.min.js إلى مجلد js بعد ذلك إبدأ بتثبيت الـpackages التي سنعمل بها من خلال فتح الـterminal في مجلد myapp من خلال الاوامر التالية $ npm install express --save $ npm install cookie-parser --save $ npm install body-parser --save $ npm install mysql --save افتح ملف التطبيق app.js وقم بإستدعاء هذه البكجات var express = require('express'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var mysql = require('mysql'); الآن نبدأ بإعداد config فريم وورك الـExpressJS مع cookie-parser body-parser ( سنستخدمهم لاحقا ) var router = express.Router(); var app = express(); app.use(bodyParser.json({limit: "50mb"})); app.use(cookieParser()); var urlencodedParser = bodyParser.urlencoded({ extended: true, parameterLimit:50000 }); app.use("/", router); نضيف امكانية استخدام ملفات الـcss, js , images etc من خلال استخدام الـmiddleware ـexpress static بإعطاء مسار وهمي لهذه الملفات app.use('/css', express.static(__dirname + '/public/css')); app.use('/js', express.static(__dirname + '/public/js')); نرى وجود ملفات الـcss and js في مجلد public/css ولكن المسار الذي سنكتبه في الكود هو فقط css/ وليس بالضرورة ان يكون اسم المسار الوهمي ذو علاقه بالمسار الاساسي .. تستطيع ان تسميه مثلا sambosa/ و في الحقيقة هو public/css/ تحديد نوع الـtemplate engine الذي سنستخدمه في هذا التطبيق مع تحديد مسار مجلد الـviews الذي يحتوي على صفحات الموقع او التطبيق app.set('views', __dirname + '/views'); app.set('view engine', 'pug'); بعد إنشاء ملفات الـpug في إحدى الخطوات السابقه , انسخ والصق كود الصفحتين index.pug and layout.pug details.pug كلن على حدى //layout.pug doctype html html head title= title script(src='https://code.jquery.com/jquery-3.2.1.min.js') link(rel='stylesheet', href='/css/bootstrap.min.css') script(src='/js/bootstrap.min.js') body nav.navbar.navbar-default .container .navbar-header button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#navbar', aria-expanded='false', aria-controls='navbar') span.sr-only Toggle navigation span.icon-bar span.icon-bar span.icon-bar a.navbar-brand(href='/') NodeJS #navbar.navbar-collapse.collapse ul.nav.navbar-nav li.active a(href='/') Home li a(href='/details') details li.dropdown a.dropdown-toggle(href='#', data-toggle='dropdown', role='button', aria-haspopup='true', aria-expanded='false') | Dropdown span.caret ul.dropdown-menu li a(href='#') Action li a(href='#') Another action li a(href='#') Something else here li.divider(role='separator') li.dropdown-header Nav header li a(href='#') Separated link li a(href='#') One more separated link block content //index.pug extends layout block content .container h1 #{msg} p #{username} , welcome to the first templating tutorial //details.pug extends layout block content .container .table-responsive h2 user table p This is all users we have so far table.table.table-bordered#example thead tr th Firstname th Lastname th Email tbody tr td John td Doe td [email protected] tr td Mary td Moe td [email protected] tr td July td Dooley td [email protected] link(rel='stylesheet', type='text/css', href='https://cdn.datatables.net/v/dt/dt-1.10.15/datatables.min.css') script(type='text/javascript', src='https://cdn.datatables.net/v/dt/dt-1.10.15/datatables.min.js') script(). $(document).ready(function() { $('#example').DataTable(); }); ملاحظة: نستخدم extends layout لكي لا نكرر الـhead في الصفحات الاخرى , مثل include في الـPHP ( في هذا الدرس ) - الاستخدام الحقيقي للـlayout هو تصميم شكل معين لصفحات معينه .. كـtemplate خاص مثلا - معلومات اكثر من خلال الرابط هنا الأن تم تجهيز المستوى الأول من التطبيق وهو الـconfigurations , ننتقل إلى النص الآخر وهو الـroutes . اولا route الصفحة الرئيسية سيكون كالتالي app.get('/', function(req, res) { res.render('index', { title: 'Pug ExpressJS NodeJS Tutorial', username: 'abdulla', msg: 'Hey There!' }) }); نلاحظ ان مسار الـroute هو مجرد slash للامام .. بذلك يتم تحديد المسار الرئيسي للتطبيق, بعد ذلك res.render اي تعني response render حيث يقوم تطبيق الـNode بالأجابة من بعد عمل طلب request من طرف المستخدم , للتوضيح اكثر الـHTTP هو عباره عن بروتوكول طلب و اجابة وبذلك request and response - req, res فعند طلب العميل امر ما يجب عليه ان يحصل على شي ما في المقابل. و كما موضع في الدالة اعلاه ان الـresponse هو عباره عن عمل render لملف index.pug الموجود في مجلد views مع ارسال ثلاث متغيرات title, username and msg , و طريقة استقبال البيانات في الـpug هي كالتالي ( يوجد اكثر من طريقة ) h1 #{username} p Welcome to #{title} خطوة اخيره لتشغيل التطبيق يجب تحديد بورت معين ولنفترض 3000 app.listen(3000, function() { console.log('The app is running http://localhost:3000'); }); افتح الـterminal داخل مجلد التطبيق myapp واكتب الامر التالي لتشغيل التطبيق node app.js افتح المتطفح على المسار انتهى الدرس الاول .. تم من خلاله عمل configuration لتطبيق الـnode الذي سنستخدمه في الدروس القادمة تثبيت template engine و توصيله مع تطبيق الـNode ارسال بيانات من الـNode إلى pug الدرس القادم سيكون هناك سنعرض لكم كيفية التعامل مع قواعد البيانات وإرسال المعلومات الى pug للحصول على ملفات العمل تجدونهم في المرفقات, بعد تحميل الملف قم بفك الضغط انتقل إلى داخل المجلد واكتب الأمر التالي لتثبيت جميع الـpackages دفعة واحده $ npm install --save أضغط هنا لتحميل ملفات العمل anwbh-app.zip موقع مساعد لتحويل كودات الـHTML إلى Pug http://html2jade.org
  13. السلام عليكم ورحمة الله وبركاته .. من بعد المقدمة حول قاعدة بيانات الـMongoDB حيث تم التعرف على: ما نوع قاعدة البيانات. كيفية تخزين البيانات فيها. العمليات البسيطة منها الـfind. الفروقات السطيحة مابين الـMongoDB و قواعد البيانات الأخرى من نوع RDBMS. لماذا انصح بالتحول إلى هذا النوع من قواعد البيانات. إذا , اصبح هناك نظرة شاملة حول هذا النوع من قواعد البيانات و في هذا الدرس سنبدأ بأول العمليات المهمة والاساسية التي تسمى بـCRUD اختصارا إلى: Create Read Update Delete نبدأ بسمه تعالى, افتح الـCMD او الـTerminal و اكتب الكوماند التالي لتفعيل خدمة الـMongoDB في جهازك بعد ذلك افتح CMD آخر واكتب الكوماند التالي للدخول على MongoDB Shell بعد الدخول على الـMongoDB Shell لمعلومات اكثر اكتب help لندا بتصفح قواعد البيانات الموجوده مسبقا في بكتابه show dbs ستظهر قاعدة بيانات واحده اسمها local تحتوي على collection بإسم startup_log وهنا ننوه مره اخرى بأن: اسم الـTable في الـMongoDB هو Collection اسم الـRow في الـMongoDB هو Document قم بإنشاء قاعدة بيانات جديدة و اختارها من خلال كوماند واحد و DATABASE_NAME تعني اسم قاعدة البيانات التي تريد عملها ولنفترض abdullashop بعد انشاء قاعدة البيانات واختيارها نبدأ الآن بعمل collection بإسم مثلا customers db.createCollection("customers") //results /* { "ok" : 1 } */ أولا: Create الأن نأتي لموضوع الإضافه بداخل الكولكشن .. للإضافه هناك ثلاث خيارات ممكن استخدامها: db.collection.insert() - old db.collection.insertOne() New in version 3.2 db.collection.insertMany() New in version 3.2 و في هذا الدرس سنستخدم insertMany لإضافة اكثر من document في collection بإستخدام كوماند واحد Syntax db.collection.insertMany( { [ <document 1> , <document 2>, ... ] }, { writeConcern: <document>, ordered: <boolean> } ) ماسنضيفه بداخل الكولكشن هو ( اعمل نسخ ومن ثم لصق في الـCMD) db.customers.insertMany([ { cus_name: "Abdulla Jassim", payment: 10, branch: "Hamad Town" }, { cus_name: "Mohammed Yousif", payment: 12, branch: "Saar" }, { cus_name: "Yassir Khalaf", payment: 4.5, branch: "Isa Town" }, { cus_name: "omar khalid", payment: 7.2, branch: "Manama" }, { cus_name: "Reem Ali", payment: 34, branch: "Riffa" }, { cus_name: "Fatima Talal", payment: 9.6, branch: "Manama" } ]) // results // /* { "acknowledged" : true, "insertedIds" : [ ObjectId("5803b8ccf9f236bb5591f181"), ObjectId("5803b8ccf9f236bb5591f182"), ObjectId("5803b8ccf9f236bb5591f183"), ObjectId("5803b8ccf9f236bb5591f184"), ObjectId("5803b8ccf9f236bb5591f185"), ObjectId("5803b8ccf9f236bb5591f186") ] } */ ثانيا: Read بعد عمل قاعدة البيانات , كولكشن و إضافه دوكيومنتس تأتي العمليه الثانية في الـCRUD وهي Read او Find في مصطلحات الـMongoDB وللبحث \ لقراءة جميع المدخلات التي في جدول customers تكون بالكماند التالي ( ملاحظة pretty() function فقط لعرض الناتج بشكل اوضح ) Syntax db.collection.find() db.cunstomers.find({}).pretty() // results // /* { "_id" : ObjectId("5803b8ccf9f236bb5591f181"), "cus_name" : "Abdulla Jassim", "payment" : 10, "branch" : "Hamad Town" } { "_id" : ObjectId("5803b8ccf9f236bb5591f182"), "cus_name" : "Mohammed Yousif", "payment" : 12, "branch" : "Saar" } { "_id" : ObjectId("5803b8ccf9f236bb5591f183"), "cus_name" : "Yassir Khalaf", "payment" : 4.5, "branch" : "Isa Town" } { "_id" : ObjectId("5803b8ccf9f236bb5591f184"), "cus_name" : "omar khalid", "payment" : 7.2, "branch" : "Manama" } { "_id" : ObjectId("5803b8ccf9f236bb5591f185"), "cus_name" : "Reem Ali", "payment" : 34, "branch" : "Riffa" } { "_id" : ObjectId("5803b8ccf9f236bb5591f186"), "cus_name" : "Fatima Talal", "payment" : 9.6, "branch" : "Manama" } */ تطبيقات حول db.collection.find استخرج اسماء جميع الأشخاص الذين دفعوا اكثر من 10 دنانير .. سيكون الكوماند db.customers.find( { payment:{$gt: 10} }, { payment: 0, branch: 0 , _id: 0 } ) /* { payment:{$gt: 10} } = the condition where payment $gt greater than 10 { payment: 0, branch: 0 , _id: 0 } = exclude these fields/cols from results Resutls: { "cus_name" : "Mohammed Yousif" } { "cus_name" : "Reem Ali" } */ استخرج جميع من يحتوي اسمه على المقطع al db.customers.find({cus_name: /al/}).pretty() // Results // /* { "_id" : ObjectId("5803b8ccf9f236bb5591f183"), "cus_name" : "Yassir Khalaf", "payment" : 4.5, "branch" : "Isa Town" } { "_id" : ObjectId("5803b8ccf9f236bb5591f184"), "cus_name" : "omar khalid", "payment" : 7.2, "branch" : "Manama" } { "_id" : ObjectId("5803b8ccf9f236bb5591f186"), "cus_name" : "Fatima Talal", "payment" : 9.6, "branch" : "Manama" } */ ثالثا: Update لتحديث دوكيومنت معين او عدد من الدوكيومنتس يعتمد على الحاله التي تواجهها: db.collection.update() - old db.collection.updateOne() New in version 3.2 db.collection.updateMany() New in version 3.2 db.collection.replaceOne() New in version 3.2 ولكن لنبدأ بابسط الاوامر Syntax db.collection.updateOne(filter, update, options) وأمثلة على ذلك , تحديث مدفوعات من اسمه Abdulla إلى 14 db.customers.updateOne({"cus_name": "Abdulla Jassim"}, {$set: {"payment": 14} }) /* set payment = 14 where cus_name= 'Abdulla Jassim' Resutls If Match { "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 } Results If No Match { "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0 } */ وبنفس الطريقة تستطيع تعديل اكثر من document دفعة واحده بإستخدام db.collection.updateMany رابعا: Delete في الحقيقة لا يوجد الكثير للحديث عنه في عملية الحذف لان الاتجاه والنتيجه واحده في كل الحالات حيث انه سيتم حذف الدوكيومنت التي تحدده db.collection.remove() - old db.collection.deleteOne() New in version 3.2 db.collection.deleteMany() New in version 3.2 و ساينتكس الحذف سيكون Syntax db.collection.deleteOne() مثال على حذف احد الدوكيومنتس في Collection الـcustomers db.customers.deleteOne({_id: ObjectId("5803b8ccf9f236bb5591f186") }) /* Resutls If match { "acknowledged" : true, "deletedCount" : 1 } Resutls If !match { "acknowledged" : true, "deletedCount" : 0 */ مثال آخر على حذف اكثر من document دفعة واحده db.customers.deleteMany({"payment": {$not: {$eq: 0 } } }) /* Delete all document from customers where paymanet != 0 {$not: {$eq: 0 } } means != 0 Results If match { "acknowledged" : true, "deletedCount" : 5 } Results If !match (the statment is right but no such documents found) { "acknowledged" : true, "deletedCount" : 0 } */
  14. البدأ بعمليات الـCRUD في قاعدة بيانات الـMongoDB السلام عليكم ورحمة الله وبركاته .. من بعد المقدمة حول قاعدة بيانات الـMongoDB حيث تم التعرف على: ما نوع قاعدة البيانات. كيفية تخزين البيانات فيها. العمليات البسيطة منها الـfind. الفروقات السطيحة مابين الـMongoDB و قواعد البيانات الأخرى من نوع RDBMS. لماذا انصح بالتحول إلى هذا النوع من قواعد البيانات. إذا , اصبح هناك نظرة شاملة حول هذا النوع من قواعد البيانات و في هذا الدرس سنبدأ بأول العمليات المهمة والاساسية التي تسمى بـCRUD اختصارا إلى: Create Read Update Delete نبدأ بسمه تعالى, افتح الـCMD او الـTerminal و اكتب الكوماند التالي لتفعيل خدمة الـMongoDB في جهازك بعد ذلك افتح CMD آخر واكتب الكوماند التالي للدخول على MongoDB Shell بعد الدخول على الـMongoDB Shell لمعلومات اكثر اكتب help لندا بتصفح قواعد البيانات الموجوده مسبقا في بكتابه show dbs ستظهر قاعدة بيانات واحده اسمها local تحتوي على collection بإسم startup_log وهنا ننوه مره اخرى بأن: اسم الـTable في الـMongoDB هو Collection اسم الـRow في الـMongoDB هو Document قم بإنشاء قاعدة بيانات جديدة و اختارها من خلال كوماند واحد و DATABASE_NAME تعني اسم قاعدة البيانات التي تريد عملها ولنفترض abdullashop بعد انشاء قاعدة البيانات واختيارها نبدأ الآن بعمل collection بإسم مثلا customers db.createCollection("customers") //results /* { "ok" : 1 } */ أولا: Create الأن نأتي لموضوع الإضافه بداخل الكولكشن .. للإضافه هناك ثلاث خيارات ممكن استخدامها: db.collection.insert() - old db.collection.insertOne() New in version 3.2 db.collection.insertMany() New in version 3.2 و في هذا الدرس سنستخدم insertMany لإضافة اكثر من document في collection بإستخدام كوماند واحد Syntax db.collection.insertMany( { [ <document 1> , <document 2>, ... ] }, { writeConcern: <document>, ordered: <boolean> } ) ماسنضيفه بداخل الكولكشن هو ( اعمل نسخ ومن ثم لصق في الـCMD) db.customers.insertMany([ { cus_name: "Abdulla Jassim", payment: 10, branch: "Hamad Town" }, { cus_name: "Mohammed Yousif", payment: 12, branch: "Saar" }, { cus_name: "Yassir Khalaf", payment: 4.5, branch: "Isa Town" }, { cus_name: "omar khalid", payment: 7.2, branch: "Manama" }, { cus_name: "Reem Ali", payment: 34, branch: "Riffa" }, { cus_name: "Fatima Talal", payment: 9.6, branch: "Manama" } ]) // results // /* { "acknowledged" : true, "insertedIds" : [ ObjectId("5803b8ccf9f236bb5591f181"), ObjectId("5803b8ccf9f236bb5591f182"), ObjectId("5803b8ccf9f236bb5591f183"), ObjectId("5803b8ccf9f236bb5591f184"), ObjectId("5803b8ccf9f236bb5591f185"), ObjectId("5803b8ccf9f236bb5591f186") ] } */ ثانيا: Read بعد عمل قاعدة البيانات , كولكشن و إضافه دوكيومنتس تأتي العمليه الثانية في الـCRUD وهي Read او Find في مصطلحات الـMongoDB وللبحث \ لقراءة جميع المدخلات التي في جدول customers تكون بالكماند التالي ( ملاحظة pretty() function فقط لعرض الناتج بشكل اوضح ) Syntax db.collection.find() db.cunstomers.find({}).pretty() // results // /* { "_id" : ObjectId("5803b8ccf9f236bb5591f181"), "cus_name" : "Abdulla Jassim", "payment" : 10, "branch" : "Hamad Town" } { "_id" : ObjectId("5803b8ccf9f236bb5591f182"), "cus_name" : "Mohammed Yousif", "payment" : 12, "branch" : "Saar" } { "_id" : ObjectId("5803b8ccf9f236bb5591f183"), "cus_name" : "Yassir Khalaf", "payment" : 4.5, "branch" : "Isa Town" } { "_id" : ObjectId("5803b8ccf9f236bb5591f184"), "cus_name" : "omar khalid", "payment" : 7.2, "branch" : "Manama" } { "_id" : ObjectId("5803b8ccf9f236bb5591f185"), "cus_name" : "Reem Ali", "payment" : 34, "branch" : "Riffa" } { "_id" : ObjectId("5803b8ccf9f236bb5591f186"), "cus_name" : "Fatima Talal", "payment" : 9.6, "branch" : "Manama" } */ تطبيقات حول db.collection.find استخرج اسماء جميع الأشخاص الذين دفعوا اكثر من 10 دنانير .. سيكون الكوماند db.customers.find( { payment:{$gt: 10} }, { payment: 0, branch: 0 , _id: 0 } ) /* { payment:{$gt: 10} } = the condition where payment $gt greater than 10 { payment: 0, branch: 0 , _id: 0 } = exclude these fields/cols from results Resutls: { "cus_name" : "Mohammed Yousif" } { "cus_name" : "Reem Ali" } */ استخرج جميع من يحتوي اسمه على المقطع al db.customers.find({cus_name: /al/}).pretty() // Results // /* { "_id" : ObjectId("5803b8ccf9f236bb5591f183"), "cus_name" : "Yassir Khalaf", "payment" : 4.5, "branch" : "Isa Town" } { "_id" : ObjectId("5803b8ccf9f236bb5591f184"), "cus_name" : "omar khalid", "payment" : 7.2, "branch" : "Manama" } { "_id" : ObjectId("5803b8ccf9f236bb5591f186"), "cus_name" : "Fatima Talal", "payment" : 9.6, "branch" : "Manama" } */ ثالثا: Update لتحديث دوكيومنت معين او عدد من الدوكيومنتس يعتمد على الحاله التي تواجهها: db.collection.update() - old db.collection.updateOne() New in version 3.2 db.collection.updateMany() New in version 3.2 db.collection.replaceOne() New in version 3.2 ولكن لنبدأ بابسط الاوامر Syntax db.collection.updateOne(filter, update, options) وأمثلة على ذلك , تحديث مدفوعات من اسمه Abdulla إلى 14 db.customers.updateOne({"cus_name": "Abdulla Jassim"}, {$set: {"payment": 14} }) /* set payment = 14 where cus_name= 'Abdulla Jassim' Resutls If Match { "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 } Results If No Match { "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0 } */ وبنفس الطريقة تستطيع تعديل اكثر من document دفعة واحده بإستخدام db.collection.updateMany رابعا: Delete في الحقيقة لا يوجد الكثير للحديث عنه في عملية الحذف لان الاتجاه والنتيجه واحده في كل الحالات حيث انه سيتم حذف الدوكيومنت التي تحدده db.collection.remove() - old db.collection.deleteOne() New in version 3.2 db.collection.deleteMany() New in version 3.2 و ساينتكس الحذف سيكون Syntax db.collection.deleteOne() مثال على حذف احد الدوكيومنتس في Collection الـcustomers db.customers.deleteOne({_id: ObjectId("5803b8ccf9f236bb5591f186") }) /* Resutls If match { "acknowledged" : true, "deletedCount" : 1 } Resutls If !match { "acknowledged" : true, "deletedCount" : 0 */ مثال آخر على حذف اكثر من document دفعة واحده db.customers.deleteMany({"payment": {$not: {$eq: 0 } } }) /* Delete all document from customers where paymanet != 0 {$not: {$eq: 0 } } means != 0 Results If match { "acknowledged" : true, "deletedCount" : 5 } Results If !match (the statment is right but no such documents found) { "acknowledged" : true, "deletedCount" : 0 } */ تم ترقية هذا الطرح المميز الى صفحة المقالات
  15. ماهي قاعدة بيانات الـMongoDB؟ في السابق كان الحديث حول قواعدة البيانات المعروفه و المتوارد بين اقطاب المبرمجين من مختلف الأصعدة ابتدا من web developers إلى الـsoftware developers على مختلف المنصات windows, OSX, Linux و جل الحديث كان يدور حول نوع واحد فقط وهو RDBMS Relational database management system مثل MS SQL Server, IBM DB2, Oracle, MySQL, and Microsoft Access التي تعتمد في حفظ البيانات داخل جداول ولكن في الآونة الأخيرة و بعد صدور عدد من JS Frameworks و ارتفاع عدد مستخدمي لغة الجافاسكربت بدأت شركة 10GEN في العمل على قاعدة بيانات من نوع مختلف تماما عما سبق ذكرة وهي NoSQL تحت اسم MongoDB اي قاعدة بيانات لا توجد بها علاقة بين الجداول وتعتمد في حفظ البيانات كمستندات BOSN ويعد هذا النوع الأشهر بين عائلة الـNoSQL وهنا ننوه بأن جميع ما تعرفه عن الـSQL Databases قد يتغير فبالتاكيد لن يكون هناك كوريز بالطريقة التي اعتدت العمل عليها. 1- أمثله وبما ان الكثير من المبرمجين لديه خلفية في الـMySQL سأقوم بمقارنة سريعة حول الأختلافات السطحية بين المونجو والـMySQL: اسم الـTable في الـMongoDB هو Collection اسم الـRow في الـMongoDB هو Document تعتمد قواعد بيانات الـRDBMS على الجداول كالنحو التالي: بينما قاعدة بيانات الـMongoDB تعتمد على BSON وهذا يعني Binary Encoding Of JSON Objects وتكون كالنحو التالي: { "_id" : ObjectId("57fe832b13e6a51130a23d2a"), "ID" : 1, "username" : "abdulla", "email" : "[email protected]" } { "_id" : ObjectId("57fe832b13e6a51130a23d2b"), "ID" : 2, "username" : "omar", "email" : "[email protected]" } { "_id" : ObjectId("57fe832b13e6a51130a23d2c"), "ID" : 3, "username" : "mohammed", "email" : "[email protected]" } امثلة حول الفروقات في عمليات الـQueries مابين الـMongoDB و الـMySQL OR RDBMS ولنفترض بأن لدينا جدول و كولكشن يحتويان على عدد من الصفوف والدوكيومنتس فيهم معلومات حول مستخدمين عرض جميع المستخدمين من هم دون السن الـ24 SELECT * FROM users WHERE age < 24 db.users.find({"age": { $lt: 24 }}) // $lt = less than عرض جميع المستخدمين الذين اعمارهم مابين الـ20 والـ30 SELECT * FROM `users` WHERE `age` BETWEEN 20 AND 30 db.users.find({ age: { $gt: 20, $lt: 30 }}) // $gt = greater than عرض المستخدمين الذين اسمائهم تحتوي على حرف A في الاول او الاخير او المنتصف لايهم SELECT * FROM `users` WHERE username LIKE %A% db.users.find({username: /A/}) و في حالة الإضافة INSERT INTO `users` (username,age,status) VALUES ('abdulla',25,'active') db.users.insertOne({username: "abdulla", age: 25, status: "active"}) ولكن هناك فارق كبير في هذه الكويري و بما ان قاعدة بيانات الـMongoDB ليست Relational بالتالي ليس هناك Schema محدده عند الإضافه فتستطيع مثلا إضافة document بمتغير col,field ليس موجود في الـdocument السابق او التالي في نفس الـCollection وبهذا يقال للـMongoDB بأن اهم مميزات هذا النوع من قواعد البيانات بأنه Flexible او Dynamic Schema ومثال على ذلك: db.users.insert([ { username: { fname: "abdulla", lname: "bahraini" }, age: 25, status: "active" }, { username: "mohammed", age: 19, status: "not active" } ]) 2- لماذا التحول الى MongoDB ( وجهة نظر ) كما اسلفنا سابقا ومع صدور عدد من js frameworks وبالاخص Meanjs المعني ب expressjs , angularjs & nodejs بالاضافه الmongodb و توسع هذه الفريموركس بشكل ضخم و رهيب جدا ومنها النود التي اصبحت خطر داهم على لغة الphp مقارنة بالسرعة, الاداء الرهيب وتناغم المونجو مع هذه الفريموركس بشكل افضل سبب في توجه الكثير من المطورين الى المونجو. ليس عند هذا الحد وحسب بل نظرا الى سرعة المونجو حسب الاحصائيات تبين اهمه الانتقال من قواعد البيانات الاعتيادية الى المونجو. تجربة اضافه 10000 صف و دوكيومنت في MySQL و MongoDB .. نلاحظ الفرق في سرعة الاداء احتاج المونجو الى ثانتين لتنفيذ المهمه بينما الMySQL احتاج الى 3 دقائق تقريبا. 3-التثبيت لتثبيت الـMongoDB قم بالدخول على الرابط واختر ما يناسب نظام جهازك بعد التثبيت إن كنت من متسخدمي الوندوز انشأ مجلد في داخل الـC (في حال تم تثبيت المونجو في السي) أضف المتغير التالي في PATH Environment وتجده في المسار التالي this pc >> proprieties >> Advanced System Settings >> Advanced tab >> Environment Variables >> in System Variables find PATH then Click Edit افتح الـCMD واكتب الكوماند التالي لتفعيل خدمه الـMongoDB في جهازك وستعمل على بورت 27017 بشكل افتراضي ثم افتح CMD أخر واكتب الكوماند التالي للدخول على MongoDB SHELL بالتالي ستكون داخل الـMongoDB SHELL وتستطيع التعامل معه من خلال الاوامر المباشرة وللإطلاع اكثر اكتب help

عالم البرمجة

عالم البرمجة مقالات برمجة و دورات مجانية لإحتراف البرمجة هدفنا تبسيط البرمجة ونشرها بيد الكل بشكل ممتع ومتطور ومحدث بإستمرار لمواكبة جديد تطورات البرمجة الحديثة و المتقدمة بدون مقابل