البحث في الموقع
المحتوى عن 'json'.
-
إحدى أسوأ الأسرار التي تمَّ الاحتفاظ بها حول AJAX على الويب هو أنّ الواجهة البرمجية (API) الأساسية لها، XMLHttpRequest، لم توجد للغرض الذي نستخدمه الآن. لقد قمنا بعمل جيد في إنشاء واجهة برمجية جيّدة باستخدام الكائن XHR ولكننا نعرف أنه يمكننا القيام بعمل أفضل. نحن نبذل الجهود لتحقيق الأفضل الذي هو الواجهة البرمجية fetch. لنأخذ فكرة عامة عن التابع window.fetch الجديد، المتوفر الآن في Firefox و Chrome Canary. الكائن XMLHttpRequest إنَّ كائن XHR معقد قليلًا برأيي ولا أريد أن أبدأ بشرح لماذا "XML" تُكتب بأحرف كبيرة بينما "Http" تُكتب بأسلوب سنام الجمل. على أيّة حال، لنلاحظ كيف نستخدم XHR. // فوضى XHR فقط الحصول على if (window.XMLHttpRequest) { // موزيلا، سفاري... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // إنترنت إكسبلورر try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // فتح، إرسال request.open('GET', 'https://davidwalsh.name/ajax-endpoint', true); request.send(null); بالطبع إنَّ أطر عمل جافاسكربت الخاصة بنا تجعل XHR أكثر متعة للعمل، ولكن ما نراه في الأعلى هو مثال بسيط على فوضى XHR. استخدام fetch الأساسي تم توفير دالة fetch في نطاق window العام، الوسيط الأول له هو الرابط URL: // الرابط (إلزامي)، الخيارات (اختيارية) fetch('https://davidwalsh.name/some/url', { method: 'get' }).then(function(response) { }).catch(function(err) { // خطأ :( }); وهذا يشبه إلى حد بعيد الواجهة البرمجية Battery المحدّثة، إذ تستخدم الواجهة البرمجية fetch الوعود في جافاسكربت لمعالجة النتائج/ردود النداء: // معالجة رد بسيط fetch('https://davidwalsh.name/some/url').then(function(response) { }).catch(function(err) { // خطأ :( }); // "تسلسل لمعالجة أكثر "تطورًا fetch('https://davidwalsh.name/some/url').then(function(response) { return //... }).then(function(returnedValue) { // ... }).catch(function(err) { // خطأ :( }); إذا لم تكن معتادًا على استخدام then، يجب أن تعتاد عليه لأنها ستنتشر قريبًا في كلّ مكان. ترويسات الطلب القدرة على ضبط ترويسات الطلب هي أمر مهم في مرونة الطلب. يمكنك العمل مع ترويسات الطلب بتنفيذ new Headers(): // إنشاء كائن ترويسة فارغ var headers = new Headers(); // إضافة بعض الترويسات headers.append('Content-Type', 'text/plain'); headers.append('X-My-Custom-Header', 'CustomValue'); // للترويسة set و get و check قيم headers.has('Content-Type'); // true headers.get('Content-Type'); // "text/plain" headers.set('Content-Type', 'application/json'); // حذف ترويسة headers.delete('X-My-Custom-Header'); // إضافة قيم ابتدائية var headers = new Headers({ 'Content-Type': 'text/plain', 'X-My-Custom-Header': 'CustomValue' }); يمكنك استخدام التوابع append و has و get و set و delete لتعديل ترويسات الطلب. لاستخدام ترويسات الطلب أنشئ الكائن Request: var request = new Request('https://davidwalsh.name/some-url', { headers: new Headers({ 'Content-Type': 'text/plain' }) }); fetch(request).then(function() { /* معالجة الرد*/ }); لنطّلع على عمل الكائنين Response و Request. الكائن Request يمثّل الكائن Request جزء الطلب عند استدعاء التابع fetch، يمكنك إنشاء طلبات مخصصة ومتطورة بتمرير الكائن Request للتابع fetch: method (الطريقة): يمكن أن تكون GET أو POST أو PUT أو DELETE أو HEAD url (الرابط): رابط الطلب headers (الترويسة): ترتبط مع الكائن Headers referrer (المرجع): مرجع الطلب mode (النمط): يكون cors أو no-cors أو same-origin credentials (بيانات الاعتماد): هل تعمل ملفات تعريف الارتباط (cookies) مع الطلب؟ وتأخذ إحدى القيمتين omit، أو same-origin. redirect (إعادة التوجيه): يمكن أن يأخذ القيمة follow أو error أو manual. integrity (التكامل): قيمة تكامل المصدر الفرعي. cache (التخزين المؤقت): وضع التخزين المؤقت ويمكن أن يأخذ إحدى القيم default أو reload أو no-cache عينة عن استخدام الكائن Request: var request = new Request('https://davidwalsh.name/users.json', { method: 'POST', mode: 'cors', redirect: 'follow', headers: new Headers({ 'Content-Type': 'text/plain' }) }); // الآن استخدمه fetch(request).then(function() { /* معالجة الرد */ }); الوسيط الأول URL هو فقط الوسيط الإلزامي، وكل خاصية تصبح للقراءة فقط حالما يتم إنشاء نسخة من الكائن Request، ومن المهم أن نلاحظ أن الكائن Request يملك التابع clone المهم عند استخدام fetch ضمن الواجهة البرمجية Service Worker -- يعد الكائن Request مجرًى ولهذا يجب أن يتم نسخه عند تمريره إلى استدعاء آخر للتابع fetch. بصمة التابع fetch ولكن نفس استخدام الكائن Request لذا يمكنك القيام بما يلي: fetch('https://davidwalsh.name/users.json', { method: 'POST', mode: 'cors', redirect: 'follow', headers: new Headers({ 'Content-Type': 'text/plain' }) }).then(function() { /* معالجة الرد */ }); من المحتمل أن تستخدم نسخًا من الكائن Request فقط ضمن Service Workers بما أن الكائن Request والتابع fetch يؤديان نفس الوظيفة. الكائن Response التابع then الذي يخص fetch مزود بالكائن Response ولكن يمكنك أيضًا إنشاء كائنات Response بنفسك -- حالة أخرى قد تواجهها عند استخدام service workers. يمكنك ضبط ما يلي عند استخدام الكائن Response: type (النوع): يمكن أن يكون basic أو cors url (الرابط) useFinalURL (استخدام الرابط النهائي): قيمة منطقية للرابط url إذا كان رابطًا نهائيًا أم لا status (الحالة): رمز الحالة (مثلًا 200، 400) ok: قيمة منطقية للاستجابة الناجحة (الحالة في المجال بين 200- 299) statusText (نص الحالة): نص يعبّر عن الحالة وفقًا للرمز (مثلًا: OK) headers (الترويسة): كائن Headers المرتبط بالاستجابة // service worker أنشئ ردك لاختبار // جديد (الجسم، الخيارات) Response كائن var response = new Response('.....', { ok: false, status: 404, url: '/' }); // Response يجلب مجدَّدًا نسخة من الكائن fetch الذي يخص then التابع fetch('https://davidwalsh.name/') .then(function(responseObj) { console.log('status: ', responseObj.status); }); يوفر الكائن Response أيضًا التوابع التالية: clone(): تُنشئ نسخة من الكائن Response ()error: تعيد كائن Response جديد مرتبط مع خطأ في الشبكة ()redirect: تنشئ استجابة جديدة مع رابط URL مختلف ()arrayBuffer: تعيد وعدًا يُقبل (resolve) مع ArrayBuffer ()blob: تعيد وعدًا يُقبل (resolve) مع Blob ()formData: تعيد وعدًا يُقبل (resolve) مع كائن FormData ()json: تعيد وعدًا يُقبل (resolve) مع كائن JSON ()text: تعيد وعدًا يُقبل (resolve) مع القيمة النصية USVString التعامل مع JSON بفرض أنّك أنشأت طلب لـJSON -- معلومات نتيجة ردود النداء لديها التابع json لتحويل البيانات الخام إلى كائن جافاسكربت: fetch('https://davidwalsh.name/demo/arsenal.json').then(function(response) { // JSON التحويل إلى return response.json(); }).then(function(j) { // هو كائن جافاسكربت j console.log(j); }); بالطبع هذا أسهل من (JSON.parse(jsonString لكن طريقة json تعد اختصارًا سهلًا أيضًا. التعامل مع استجابات Text/HTML الأساسية ليست دائما JSON هي صيغة رد الطلب المرغوبة لذا إليك كيف نجعل الاستجابة على شكل نص أو HTML: fetch('/next/page') .then(function(response) { return response.text(); }).then(function(text) { // <!DOCTYPE .... console.log(text); }); بإمكانك الحصول على استجابة نصية عبر تسلسل طريقة then للوعد مع طريقة text(). التعامل مع استجابات بشكل بيانات ثنائية إذا كنت ترغب مثلًا بتحميل صورة باستخدام التابع fetch فإن هذا سيكون مختلفًا. fetch('https://davidwalsh.name/flowers.jpg') .then(function(response) { return response.blob(); }) .then(function(imageBlob) { document.querySelector('img').src = URL.createObjectURL(imageBlob); }); يأخذ التابع blob() تدفق الاستجابة وتقرأه حتى يكتمل. الحصول على بيانات النموذج استخدام آخر شائع للـAJAX وهو إرسال بيانات نموذج، وإليك كيف يمكن أن نستخدم التابع fetch للحصول على بيانات نموذج مرسلة بالطريقة POST: fetch('https://davidwalsh.name/submit', { method: 'post', body: new FormData(document.getElementById('comment-form')) }); وإذا أردت إرسال البيانات بصيغة JSON إلى الخادم: fetch('https://davidwalsh.name/submit-json', { method: 'post', body: JSON.stringify({ email: document.getElementById('email').value, answer: document.getElementById('answer').value }) }); سهل جدًا ومريح للعينين أيضًا. قصة لم تُكتب رغم أن fetch هي واجهة برمجية سهلة الاستخدام، إلا أنّ الواجهة البرمجية الحالية -تاريخ ترجمة المقال- لا تسمح بإلغاء الطلب مما يجعلها غير مستخدمة لكثير من المطورين. إن الواجهة البرمجية fetch الجديدة تبدو أفضل وأسهل استخدامًا من XHR. وبعد كل ذلك تمّ إنشاؤها حتى نتمكّن من استخدام AJAX بالطريقة الصحيحة. تملك fetch فوائد الخبرات السابقة، ولا أطيق الانتظار حتى يتم استخدامها على نطاق واسع. ترجمة -وبتصرف- للمقال fetch API لصاحبه David Walsh
-
- fetch
- xmlhttprequest
- (و 4 أكثر)
-
اكتشفت مؤخرًا المتعة الكبيرة في استخدام مكتبة [Fractal المقدّمة من PHP League] لإنشاء استجابات للواجهات البرمجية التي تعطي مخرجات من نوع JSON وذلك عند العمل على نماذج Eloquent في إطاري العمل Laravel و Lumen للحصول على المخرجات التي أرغب بها. هذه الحزمة مشابهة إلى حدٍّ كبير لمكتبة ActiveModel Serializer في إطار العمل Rails، إذ إنّها تتيح لك التحكّم الدقيق بالمخرجات التي ترغب في وصولها إلى المستخدم، إضافة إلى أنّها تفصل الشيفرة المسؤولة عن إنشاء كائن JSON عن نموذج Eloquent وهذا أمر في غاية الأهمية. والآن بعد أن أتيح لي تطوير عدد من الواجهات البرمجية لفترة زمنية لا بأس بها، خطر لي أن أتحدّث عن الطرق التي اتبعتها في ربط Fractal مع تطبيقات Laravel و Lumen (تختلف طريقة الربط في إطار Lumen لأنّه لا يدعم ماكروات Response). المُسَلسِلات المخصّصة Costum Serializers بادئ ذي بدء، تدعم Fractal عددًا من المُسَلسِلات Serializers لتكوين بنية خاصة بالاستجابة، وتستخدم بصورة افتراضية المسَلسِل الذي يدعى بـ DataArraySerializer والذي يضيف مفتاح جذر root key يحمل الاسم data إلى الاستجابة، لذا إن كنت لا تمانع من استخدام هذا المُسَلسِل فيمكنك تجاوز هذه الخطوة. أما لو كنت ترغب في استخدام مُسَلسِل آخر فعليك تسجيل الصنف Manager مع حاوية IoC في مزوّد الخدمة AppServiceProvider أو في مزوّد خدمة آخر إن كنت ترى أنّه يناسبك أكثر، ولكن عليك الانتباه إلى أنّ دعم JSON-API غير مكتمل حتى الآن (المقالة الأصلية نشرت سنة 2015. (المترجم)). public function register() { $this->app->bind('League\Fractal\Manager', function($app) { $manager = new \League\Fractal\Manager; // Use the serializer of your choice. $manager->setSerializer(new \App\Http\Serializers\RootSerializer); return $manager; }); } إنشاء المحوّلات Transformers بعد ذلك سنحتاج إلى إنشاء بعض المحوّلات - محوّل لكل نوع من أنواع نماذج Eloquent التي ترغب في تخريجها بواسطة الواجهة البرمجية - وفي مثالنا هذا سأستخدم مدوّنة حيث يضمّ النموذج AppUser عددًا من نماذج AppPost وسنعرض المستخدم مع المقالات الخاصّة به. أنشأت مجلّدً للتحويلات داخل مجلّد Http: app/Http/Transoformers، والآن يمكنني إنشاء محوّلين، الأول لنموذج User والثاني لنموذج Post. محوّل المستخدمين User سيكون سهلًا، إذ أنّه سيُرجع الحقول المطلوبة من قبل واجهتي البرمجية. في هذا المثال، يمتلك النموذج User خاصّية is_admin وهي عبارة عن قيمة منطقية boolean. ويمكنني التعبير عن ذلك في المحوّل بواسطة العبارة (bool) $user->is_admin ولكن اعتبارًا من الإصدار 5.0 وما بعده من Laravel أصبح بالإمكان استخدام خاصّية $casts في النموذج وسيكون Eloquent قادرًا بعدها على معالجة عملية الوصف بالنيابة عنك. يستحسن معالجة مثل هذه الأمور ضمن النموذج لأنّها ستكون متاحة في التطبيق برمّته. <?php namespace App\Http\Transformers; use App\User; use League\Fractal\TransformerAbstract; class UserTransformer extends TransformerAbstract { /** * Turn this item object into a generic array. * * @param \App\User $user * @return array */ public function transform(User $user) { return [ 'id' => $user->id, 'first_name' => $user->first_name, 'last_name' => $user->last_name, 'email' => $user->email, 'is_admin' => $user->is_admin, 'created_at' => $post->created_at->toDateTimeString(), 'updated_at' => $post->updated_at->toDateTimeString() ]; } } بما أنّ خصائص التاريخ في نماذج Eloquent هي نسخ من مكتبة Carbon يمكن إذًا استخدام الدوال المساعدة التي تقدّمها هذه المكتبة لإرجاع التاريخ بالصيغة التي نرغب بها. وفي مثالنا سنستخدم الدالة toDateTimeString() وسيكون التاريخ بالصيغة التالية: Y-m-d H:i:s (السنة - الشهر - اليوم الساعة:الدقائق:الثواني). والآن سنحتاج إلى محوّل لأجل نموذج Post، وسيكون هذا المحوّل مختلفًا عن السابق لأنّنا نرغب في تضمين النموذج User المرتبط بنموذج Post مع هذه الاستجابة. <?php namespace App\Http\Transforers; use App\Post; use League\Fractal\TransformerAbstract; class PostTransformer extends TransformerAbstract { /** * List of resources possible to include * * @var array */ protected $availableIncludes = ['user']; /** * List of resources to automatically include. * * @var array */ protected $defaultIncludes = ['user']; /** * Turn this item object into a generic array. * * @param \App\Post $post * @return array */ public function transform(Post $post) { return [ 'id' => $post->id, 'title' => $post->title, 'content' => $post->content, 'created_at' => $post->created_at->toDateTimeString(), 'updated_at' => $post->updated_at->toDateTimeString(), 'published_at' => $post->published_at->toDateTimeString() ]; } /** * Include user. * * @param \App\Post $post * @return League\Fractal\ItemResource */ public function includeLevels(Post $post) { return $this->item($post->user, new UserTransformer); } } لاحظ أنّه بالإمكان إرجاع $this->collection داخل المحوّل إن كنت ترغب في ربط مجموعة بدل من عنصر واحد. إنشاء الاستجابات في Laravel عادة ما أنشئ مزوّد خدمة Fractal FractalServiceProvider والذي يضمّ التابع register() الذي قمت بوصفه سابقًا، ثم أسجّل بعض الماكروات في التابع boot() كما تلاحظ هنا. سيؤدي ذلك إلى إضافة تابعين إضافيين إلى معمل (factory) Response في Laravel وسيسهّل إرجاع الاستجابات على هيئة عناصر أو مجموعات. لاحظ أنّي حدّدت نوع (type hint) المحوّل ليكون نسخة من الصنف TransformerAbstract وذلك لأنّي أنشئ دائمًا المحوّلات من الاستجابات بدلًا من صيغة الدالة المغلقة closure لأنّي أرى بأنّ هذه الطريقة ستحافظ على ترتيب الشيفرات التي أكتبها. لكن إن كنت تفضل استخدام الدوال المغلقة بدلًا من المحوّلات فيمكنك بكل ساطة أن لا تحدد نوع المحوّل ضمن المعاملات. public function boot() { $fractal = $this->app->make('League\Fractal\Manager'); response()->macro('item', function ($item, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) use ($fractal) { $resource = new \League\Fractal\Resource\Item($item, $transformer); return response()->json( $fractal->createData($resource)->toArray(), $status, $headers ); }); response()->macro('collection', function ($collection, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) use ($fractal) { $resource = new \League\Fractal\Resource\Collection($collection, $transformer); return response()->json( $fractal->createData($resource)->toArray(), $status, $headers ); }); } والآن أصبح من السهل إنشاء استجابة واحدة (لمستخدم واحد مثلًا) ومجموعة من الاستجابات (لجميع مقالات المدوّنة مثلًا). /** * GET /users/1 * * @param int $userId * @return \Illuminate\Http\Response */ public function showUser($userId) { $user = \App\User::findOrFail($userId); return response()->item($user, new \App\Http\Transformers\UserTransformer); } /** * GET /posts * * @return \Illuminate\Http\Response */ public function showPosts() { $posts = \App\Post::with('user')->get(); return response()->collection($posts, new \App\Http\Transformers\PostTransformer); } إن كنت ترغب في استخدام حالة استجابة HTTP أخرى مثل 201 (تم الإنشاء) أو 204 (لا يوجد محتوى) يمكنك وبكل سهولة تمرير رمز الحالة كمعامل ثالث إلى الماكرو. إنشاء الاستجابات في Lumen يتطلّب إنشاء الاستجابات في Lumen اتباع أسلوب مختلف قليلًا؛ ذلك لأنّ Lumen لا يدعم الماكروات في معمل Response؛ لذا سأضيف هذه التوابع إلى المتحكّم الرئيسي في الواجهة البرمجية. /** * Create the response for an item. * * @param mixed $item * @param \League\Fractal\TransformerAbstract $transformer * @param int $status * @param array $headers * @return Response */ protected function buildItemResponse($item, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) { $resource = new \League\Fractal\Resource\Item($item, $transformer); return $this->buildResourceResponse($resource, $status, $headers); } /** * Create the response for a collection. * * @param mixed $collection * @param \League\Fractal\TransformerAbstract $transformer * @param int $status * @param array $headers * @return Response */ protected function buildCollectionResponse($collection, \League\Fractal\TransformerAbstract $transformer, $status = 200, array $headers = []) { $resource = new \League\Fractal\Resource\Collection($collection, $transformer); return $this->buildResourceResponse($resource, $status, $headers); } /** * Create the response for a resource. * * @param \League\Fractal\Resource\ResourceAbstract $resource * @param int $status * @param array $headers * @return Response */ protected function buildResourceResponse(\League\Fractal\Resource\ResourceAbstract $resource, $status = 200, array $headers = []) { $fractal = app('League\Fractal\Manager'); return response()->json( $fractal->createData($resource)->toArray(), $status, $headers ); } يمكنك الآن استدعاء أي تابع من هذه التوابع في أي متحكّم موروث من هذا المتحكّم لإنشاء نفس الاستجابات التي أنشأناها مع Laravel. return $this->buildItemResponse($user, new \App\Http\Transformers\UserTransformer); return $this->buildCollectionResponse($posts, new \App\Http\Transformers\PostTransformer); ترجمة - وبتصرّف - للمقال Using Fractal with Laravel and Lumen لصاحبه Dwight Conrad Watson.
-
ما هي JSON؟ كلمة JSON و تلفظ جيسون هي اختصار ل JavaScript Object Notation. سميت بهذا الاسم لأن لغة جافا سكربت(javascript) كانت أول لغة تستفيد من هذه الصيغة. JSON هي طريقة لتخزين المصفوفات (arrays) و الكائنات (objects) بقيم نصية (string)، و تستخدم بشكل أساسي في نقل البيانات وأقل عرضة للخطر و أسهل من طرق أخرى كطريقة xml. تستخدم عادةً عندما يطلب جزء من تطبيق الويب بعض المعلومات من الخادم (server) من دون إعادة تحميل الصفحة. عادة تتم هذه العملية عن طريق جافا سكربت وطلبات AJAX. منذ النسخة 5.2.0، لغة PHP أصبحت قادرة على تحويل الكائنات والمصفوفات إلى JSON. وقد كانت إضافة رائعة لهذه اللغة. إذا كنت تعمل مع PHP لفترة من الزمن ففي الغالب أنك قمت باستعمال دالة ()serialize لعرض كائنات PHP كنصوص، و تستخدم لتحويل كائنات PHP إلى نصوص، و يمكنك فيما بعد استخدام دالة ()unserialize لتحويل هذا النص إلى الحالة السابقة بالقيم الأصلية. وليس فقط لغة PHP التي يمكن أن تتعامل مع JSON بل معظم لغات البرمجة يمكنها التعامل مع JSON وتحويل بياناتها إلى JSON. صيغة JSON {"name":"Lushui","species":"Panda","diet":"Green Things","age":7,"colours":["red","brown","white"]} افتراضيًا يتم تخزين JSON بلا أي فراغات (white space) مما يجعل قراءة JSON صعبة قليلًا، من أجل توفير الذاكرة عند نقل البيانات، لكن يمكنك أن تضع مهما كان من فراغات أو أسطر لجعلها مقروءة بالنسبة لك. لكن هل من المعقول أن نقوم بوضع فراغات في هذ الملف يدويًا إذا كان لدينا العديد من الأسطر، هناك العديد من الأدوات التي تتوفر على الإنترنت التي تقوم بتجميل ملف JSON ليصبح أكثر قابلية للقراءة. لنقم بإضافة بعض الفراغات: { "name": "Lushui", "species": "Panda", "diet": "Green Things", "age": 7, "colours": ["red", "brown", "white"] } كما ترى في هذا المثال أنه لدينا عدد من المفاتيح والقيم. كل مفتاح يجب أن تكون له قيمة مقابلة، إذا كنت قد تعاملت مع جافا سكربت من قبل فسوف ترى أن JSON لا تختلف كثيرًا عن جافا سكربت. var lushui = { name: 'Lushui', species: 'Panda', diet: 'Green Things', age: 7, colours: ['red', 'brown', 'white'] }; في جافا سكربت يتم تعيين هذا الكائن لمتغير كالتالي: var lushui = { .. }; لكن JSON هي صيغة لنقل البيانات، وليست لغة برمجة، لا تملك أي مفاهيم برمجية لذلك لا نحتاج إلى المتغيرات أو ما شابه في JSON. في جافا سكربت وفي JSON الكائنات يتم احتوائها داخل { } وكل مفتاح له قيمة، في جافا سكربت المفاتيح لا تتطلب وضعها بين إشارتي " " لأنها تمثل متغيرات. في جافا سكربت و JSON المفتاح و قيمته يفصل بينهما بـ ":" و كل مفتاح و قيمته مفصولان عن المفاتيح و القيم الآخرى بـ "," . JSON تدعم أنواع القيم التالية: Double Float String Boolean Array Object Null القيم العددية تمثل بلا إشارتي " " ، القيم المنطقية تمثل بـ true أو false و بلا إشارتي " " كما PHP ، و يجب التشديد مرة أخرى أن النصوص تمثل بإشارتي " " . القيمة null تعمل كعملها في php وتمثل في JSON بوضع الكلمة فقط غير محاطة بأي شيء. المصفوفات في JSON وجافا سكربت هي نفسها. // JavaScript ['red', 'brown', 'white'] ["red", "brown", "white"] لاحظ أنني لم أضع تعليق قبل المصفوفة الثانية، لأن JSON لا تدعم التعليق بسبب أنها تستخدم لنقل البيانات وليس هناك حاجة للتعليق لأنك لا تكتب أوامر برمجية لأنك لو عدت لملف JSON لاحقًا فكل ما فيه بيانات سوف تعرفها عند قراءتها مباشرةً. JSON تدعم المصفوفات و الكائنات المتداخلة. { "an_object": { "an_array_of_objects": [ { "The": "secret" }, { "is": "that" }, { "I": "still" }, { "love": "shoes!" } ] } } لدينا في المثال السابق كائن JSON يحتوي كائن آخر يحتوي مصفوفة من الكائنات. JSON و PHP كما ذكرت سابقًا، منذ النسخة 5.2.0 وفرت الدعم لتحويل البيانات إلى JSON والآن سوف نلقي نظرة على هذه الميزة في PHP عن قرب. لتحويل قيمة في PHP إلى JSON فقط نحتاج إلى دالة ()json_encode كما التالي: <?php $truth = array('panda' => 'Awesome!'); echo json_encode($truth); نتيجة تنفيذ التعليمات السابقة. {"panda":"Awesome!"} رائع هذا بالضبط ما كما نريده، لنقم الآن بتحويل هذه البيانات إلى مرة آخرى إلى صيغة مفهومة من قبل PHP. <?php $truth = json_decode('{"panda":"Awesome!"}'); echo $truth['panda']; لنلقي نظرة على النتيجة؟ Fatal error: Cannot use object of type stdClass as array in ... كما ترى، دالة ()json_decode لا تتحول إلى مصفوفة PHP. بدلًا من ذلك تستخدم كائن stdClass لتمثيل بياناتنا، لنصل إلى بياناتنا بشكل صحيح سندخل إلى خصائص هذا الكائن بهذه الطريقة. <?php $truth = json_decode('{"panda":"Awesome!"}'); echo $truth->panda; // Awesome! لكن إذا ما زلت ترغب في الحصول على هذه البيانات كمصفوفة فقط أضف وسيط آخر إلى هذه الدالة وهو true. <?php $truth = json_decode('{"panda":"Awesome!"}', true); echo $truth['panda']; // Awesome! ترجمة –وبتصرّف- للمقال Laravel 4 Primer: JSON لصاحبه Dayle Rees
-
- 1
-
- javascript
- json
-
(و 1 أكثر)
موسوم في:
-
بما أنّ JSON مشتقة من لغة JavaScript البرمجية، فمن الطبيعي إذًا أن تُستخدم كتنسيق للبيانات في هذه اللغة. JSON هي اختصار لـ JavaScript Object Notation (تنويت كائنات JavaScript) وتلفظ غالبًا كما يلفظ اسم (Jason). يمكن استخدام JSON في: تخزين البيانات. إنشاء بنى المعلومات من خلال المعلومات التي يدخلها المستخدم. نقل البيانات من الخادوم إلى العميل، ومن العميل إلى الخادوم، ومن العميل إلى العميل. ترتيب البيانات والتحقق منها. يمثّل هذا المقال مقدّمة للعمل على JSON من خلال لغة JavaScript، ويجب أن تكون مطّلعًا على هذه اللغة لتحصل على الفائدة المرجوة من المقال. صيغة JSON صيغة JSON مشتقة من صيغة الكائنات في JavaScript، ولكنّها صيغة نصّية بالكامل، وهي عبارة عن أزواج من المفاتيح والقيم التي تحاط عادة بأقواس معقوفة. عادة ما تخزّن كائنات JSON في ملف بامتداد .json ولكن يمكن أن تجد هذه الكائنات ضمن سياق البرنامج. تكون ملفات .json بالصيغة التالية: { "first_name" : "Sammy", "last_name" : "Shark", "online" : true } إما إن كانت كائنات JSON موجودة في ملف بامتداد .js أو .html فستكون على اﻷغلب مسندة إلى متغير وبالصورة التالية: var sammy = { "first_name" : "Sammy", "last_name" : "Shark", "online" : true } إضافة إلى ذلك، يمكن أن ترى JSON على هيئة سلسلة نصية لا عنصر وذلك ضمن شيفرة JavaScript، ويمكن كتابة الصيغة في سطر واحد كما يلي: var sammy = '{"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"}'; تحويل كائنات JSON إلى سلاسل نصّية مفيد في نقل البيانات بصورة سريعة. مقارنة JSON مع كائنات JavaScript من المهمّ جدًّا الانتباه إلى أنّ JSON قد طُوّرت لكي تستخدم من قبل أي لغة برمجية، في حين أن التعامل مع كائنات JavaScript يكون بواسطة هذه اللغة حصرًا. أما بالنسبة إلى الصياغة، فإن كائنات JavaScript مشابهة لـ JSON، ولكن الفرق هو أنّ المفاتيح في كائنات JavaScript ليست سلاسل نصّية ضمن علامات اقتباس، إضافة إلى أنّه يمكن استخدام الدوال كقيم في هذه الكائنات. لنأخذ المثال التالي لكائن JavaScript الخاص بالمستخدم Sammy Shark والمتّصل حاليًا بالإنترنت: var user = { first_name: "Sammy", last_name : "Shark", online : true, full_name : function() { return this.first_name + " " + this.last_name; } }; من الواضح جدًّا أن هذا الكائن مشابه جدًّا لكائن JSON، ولكن لا وجود لعلامات الاقتباس حول أيٍّ من المفاتيح (first_name, last_name, online, أو full_name)، إضافة إلى أنّ قيمة المفتاح الأخير عبارة عن دالّة. يمكن استخدام التنويت النقطي للوصول إلى البيانات الموجودة في كائن JavaScript السابق، فلاستدعاء قيمة الاسم الأول نستخدم الصيغة: user.first_name وسنحصل على سلسلة نصّية، أما لو أردنا الوصول إلى الاسم الكامل، ونظرًا لكون القيمة دالّة، فستكون صيغة الاستدعاء بالصورة التالية: user.full_name(). كائنات JavaScript موجودة فقط ضمن هذه اللغة، لذا إن كنت بحاجة للوصول إلى البيانات عن طريق لغات برمجية أخرى، فعليك حينئذ استخدام JSON لتخزين البيانات. الوصول إلى بيانات JSON يمكن الوصول إلى بيانات JSON بنفس الطريقة المتّبعة في كائنات JavaScript، ولتوضيح ذلك لاحظ المثال التالي: var sammy = { "first_name" : "Sammy", "last_name" : "Shark", "online" : true } لتتمكن من الوصول إلى أيّ من القيم السابقة يمكن استخدام التنويت النقطي بالصورة التالية: sammy.first_name sammy.last_name sammy.online يأتي اسم المتغير sammy في البداية متبوعًا بنقطة متبوعة بالمفتاح الذي ترغب في الوصول إليه. فمثلًا، لإطلاق مربع تنبيه يعرض القيمة المرتبطة بالمفتاح first_name يمكن استدعاء دالّة alert() في JavaScript بالشكل التالي: alert(sammy.first_name); Output Sammy كذلك يمكن استخدام الأقواس المربعة [] للوصول إلى البيانات في JSON، وذلك بكتابة اسم المفتاح ضمن علامتي اقتباس محاطًا بقوسين مربعين. فيصبح المثال السابق بالشكل التالي: alert(sammy["online"]); Output true وفي حال استخدام المصفوفات المتشعبة Nested Arrays يجب حينئذ استدعاء رقم العنصر ضمن المصفوفة. لنأخذ المثال التالي: var user_profile = { "username" : "SammyShark", "social_media" : [ { "description" : "twitter", "link" : "https://twitter.com/digitalocean" }, { "description" : "facebook", "link" : "https://www.facebook.com/DigitalOceanCloudHosting" }, { "description" : "github", "link" : "https://github.com/digitalocean" } ] } لتتمكن من الوصول إلى السلسلة النصية facebook يجب عليك استدعاء العنصر ضمن المصفوفة مع استخدام النقطة وبالصورة التالية: alert(user_profile.social_media[1].description); Output facebook لاحظ أنّنا نستخدم نقطة إضافية للوصول إلى العنصر المتشعّب ضمن المصفوفة. بعض الدوال التي تساعد في التعامل مع JSON سنستعرض دالّتين مهمّتين في التعامل مع بيانات JSON، الأولى تعمل على تحويل البيانات إلى سلاسل نصية والأخرى تقوم بتحليلها. إن إمكانية تحويل JSON من كائن إلى سلسلة نصّية مفيد جدًّا في تحويل البيانات وتخزينها. JSON.stringify() تحوّل هذه الدالة الكائن إلى سلسلة JSON نصية. يمكن الاستفادة من السلاسل النصّية لتحويل البيانات من العميل إلى الخادوم وذلك من خلال خزن المعلومات أو تمريرها بصورة سهلة وسريعة. فعلى سبيل المثال، يمكنك مثلًا الحصول على الإعدادات الخاصّة بالمستخدم من طرف العميل ثم إرسالها إلى الخادوم، وفي وقت لاحق يمكنك قراءة تلك المعلومات وتحليلها بواسطة دالّة JSON.parse() واستخدام البيانات حسب الحاجة. في المثال التالي نسند كائن JSON إلى المتغير obj، ثم نحوّله إلى سلسلة نصية من خلال تمريره إلى الدالة JSON.stringify() وإسناد القيمة إلى المتغيّر s: var obj = {"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"} var s = JSON.stringify(obj) والآن يمكن التعامل مع المتغيّر s والذي يضمّ معلومات JSON على هيئة سلسلة نصّية. '{"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"}' JSON.parse() قلنا أنّ السلاسل النصية مفيدة في نقل المعلومات، ولكن يجب أن تتوفّر إمكانية تحويل هذه السلاسل مرّة أخرى إلى كائنات JSON سواء من طرف العميل أو الخادوم. يمكن تحويل السلال النصّية إلى كائنات باستخدام الدالة eval() ولكن هذه الطريقة غير آمنة، لذا سنستخدم الدالة JSON.parse() بدلًا عنها. لتحويل السلسلة النصّية في المثال السابق إلى كائن JSON نقوم بتمرير المتغيّر s إلى الدالّة وإسناد القيمة المستحصلة إلى متغيّر جديد: var o = JSON.parse(s) أصبح لدينا الآن الكائن o وهو مطابق تمامًا للعنصر obj. لتوضيح الفكرة بشكل أكبر سنأخذ المثال التالي والذي نستخدم فيه دالة JSON.parse() في ملف HMTL. <p id="user">Name: Sammy Shark<br>Location: Ocean</p> <script> var s = '{"first_name" : "Sammy", "last_name" : "Shark", "location" : "Ocean"}'; var obj = JSON.parse(s); document.getElementById("user").innerHTML = "Name: " + obj.first_name + " " + obj.last_name + "<br>" + "Location: " + obj.location; </script> Output Name: Sammy Shark Location: Ocean لاحظ كيف حوّلنا السلسلة النصّية s إلى كائن JSON يمكن استدعاء القيم التي يتضمّنها وتصييرها على صفحة الإنترنت. الخلاصة JSON هي الصيغة الافتراضية التي تستخدم في JavaScript ويمكن تضمين هذه الصيغة في العديد من اللغات البرمجية الشائعة. ويمكنك الاطلاع على اللغات التي تدعم هذه الصيغة من خلال الموقع الإلكتروني الخاص بهذه الصيغة. ونظرًا لصغر حجم JSON وسهولة نقل المعلومات بين لغات البرمجة والأنظمة المختلفة، تستخدم هذه الصيغة بصورة واسعة في الواجهات البرمجية APIs، مثل واجهة Twitter البرمجية. تجدر الإشارة إلى أنّك لن تنشئ ملفات .json بنفسك على الأغلب بل ستحصل عليها من مصادر أخرى، مثل ملفات CSV التي تستخدم لتخزين البيانات المجدولة، أو ملفات XML أو غيرها. وسواء أكتبت JSON بنفسك أو حصلت عليها من مصدر آخر، يمكن التأكد من صحّة الصيغة التي كتبتها باستخدام الأداة JSONLint. ترجمة - وبتصرّف - للمقال How To Work with JSON in JavaScript لصاحبته Lisa Tagliaferri.
-
هنالك الكثير من الواجهات البرمجية المبنية على JSON التي توفر وصولًا عبر دوال من جهة الخادوم فقط، فلو أردنا استخدام عميل JavaScript مع تلك الواجهات البرمجية الخارجية، فسنحتاج إلى ضبط خادومنا للوصول إلى تلك الواجهات البرمجية الخارجية ثم تخديم تلك البيانات عبر Ajax أو عبر نقطة نهاية (endpoint) خاصة بك. ولحسن الحظ، فعل ذلك سهلٌ جدًا في ووردبريس. سأريك في هذا الدرس كيفية الحصول على أجور الشحن عبر Easy Post API باستخدام نقطة نهاية في ووردبريس. لتبسيط هذا الدرس (وجعله قصيرًا) فسنرسل ستة معاملات (وهو عدد كاف لواجهة Easy Post البرمجية لإعادة أجور الشحن): عرض الطرد ارتفاع الطرد طول الطرد وزن الطرد كود Zip للمرسل كود Zip للمستقبل ضبط نقطة نهاية JSON أوّل خطوة هي ضبط المسار الذي ستُخدَّم منه بيانات JSON، وفي هذه الحالة هو: /wp-json/easy-post/v1/rates/ الشيفرة: /** * Sets up a JSON endpoint at /wp-json/easy-post/v1/rates/ */ function easy_post_api_init() { $namespace = 'easy-post/v1'; register_rest_route( $namespace, '/rates/', array( 'methods' => 'GET', 'callback' => 'easy_post_return_rates', ) ); } add_action( 'rest_api_init', 'easy_post_api_init' ); عرض البيانات تتوقع نقطة النهاية إرسال ست قيم من البيانات كطلبية، وستستخدمها للحصول على البيانات من الواجهة البرمجية الخارجية، فلو لم تكن تلك القيم موجودةً فستستعمل القيم الافتراضية، وسنحرص أن تكون تلك القيم رقميةً فقط. مثال عن رابط URL مع قيم لكل المعاملات: /wp-json/easy-post/v1/rates/?zip=78701&width=10&length=10&height=10&weight=10&shipping_zip=78751 الشيفرة: /** * عرض مخرجات Easy Post عبر النهاية الطرفية * * نستخدم القيم المبدئية في حال عدم ذكر بيانات في الطلب، إلا أن إعادة خطأ ربما تكون فكرة أفضل. * Valid URL: /wp-json/easy-post/v1/rates/?zip=78701&width=10&length=10&height=10&weight=10&shipping_zip=78751 */ function easy_post_return_rates( WP_REST_Request $request ) { // الإعدادات المبدئية للشحن $defaults = array( 'zip' => 78701, 'width' => 10, 'length' => 10, 'height' => 10, 'weight' => 16, 'shipping_zip' => 94105 ); // الحصول على المعطيات من الطلب $params = $request->get_query_params(); // التأكد من توفر جميع المعطيات $params = array_replace( $defaults, $params ); // تنظيف المفاتيح $params = array_map( "absint", $params ); // إنشاء قيم مفاتيح فريدة لتحديد قيم البيانات المؤقتة transient أو العثور عليها $key = 'easy_post_' . implode( "_", $params ); /** * نحتفظ بالإجابة في قيمة مؤقتة transient ضمن قاعدة بيانات ووردبريس * لتجنب إرسال الكثير من الطلبات في وقت قصير * * تنتهي صلاحية هذه البيانات بعد عشر دقائق */ if ( false === ( $data = get_transient( $key ) ) ) { $data = easy_post_make_request( $params ); $response = new WP_REST_Response( $data ); // التخبئة لمدة عشر دقائق set_transient( $key, $response, 60 * 10 ); } else { // إرجاع القيمة المخبّأة return get_transient( $key ); } return $response; } الحصول على البيانات الدالة easy_post_make_request() هي الدالة التي تطلب البيانات من الواجهة البرمجية الخارجية، والغرض من أغلبية الشيفرات التي هنا هي تجهيز الطلبية ضمن مصفوفة يمكن لواجهة Easy Post البرمجية أن تعالجها: /** *العثور على البيانات من الواجهة البرمجية لـ Easy Post باستخدام الدالة wp_remote_post */ function easy_post_make_request( $params ) { $to_address = array( 'zip' => $params['shipping_zip'], 'country' => 'US' ); $from_address = array( 'zip' => $params['zip'], 'country' => 'US' ); $parcel = array( 'length' => $params['length'], 'width' => $params['width'], 'height' => $params['height'], 'weight' => $params['weight'] ); $request = array( 'shipment' => array( 'to_address' => $to_address, 'from_address' => $from_address, 'parcel' => $parcel ) ); $args = array( 'method' => 'POST', 'blocking' => true, 'headers' => array( 'Content-Type' => 'application/json' ), 'timeout' => 15, 'sslverify' => false, 'body' => json_encode( $request ) ); // ضع مفتاح API الخاص بك مكان EASYPOST_TEST_API_KEY $api_url = 'https://' . EASYPOST_TEST_API_KEY . ':@api.easypost.com/v2/shipments'; $response = wp_remote_post( $api_url, $args ); if ( ! is_wp_error( $response ) ) { $response = json_decode( $response['body'] ); } return $response; } استخدام البيانات عندما نحاول الوصول إلى نقطة النهاية التي أنشأناها، فإن بيانات JSON التي جلبناها من Easy Post ستظهر لنا: يمكنك الآن الحصول على أجور الشحن ديناميكيًا في موقعك باستخدام نقطة النهاية التي أنشأناها في هذا الدرس. يمكنك الاطلاع على كامل الشيفرة هنا. ترجمة –وبتصرّف– للمقال How to Set JSON Endpoints in WordPress to Access an External API لصاحبه Devin Price حقوق الصورة البارزة محفوظة لـ Freepik
-
سهّل محرك قواعد بيانات MySQL من استخدام قواعد البيانات العلاقية Relational، وألغى – إلى حدٍ ما – الخطوط التي تفصل بين قواعد بيانات SQL و NoSQL بعد أن أضاف حقلًا لنوع البيانات JSON. في يومٍ من الأيام السالفة، كان هناك حاسوب وحيدٌ، ثم أتى أحدهم وبنى آخر، وأراد أن ينقل بعض الشفرات من الحاسوب الأول، ولهذا السبب احتجنا إلى طريقةٍ لنقل المعلومات دون اعتمادها على العتاد الذي يُشغِّلُها؛ ومن ذلك الوقت وإلى الآن انتشرت الكثير من ترميزات المحارف مثل ASCII و EBCIDC و SGML و XML …إلخ. وسطع نجمها لفترةٍ من الزمن. ولكن في السنوات الأخيرة اشتهرت صيغة JSON (أي JavaScript Object Notation) التي تستعمل لتبادل البيانات بصيغةٍ مهيكلة. كان نظام قواعد البيانات MySQL قبل الإصدار 5.7 يخزّن مستندًا مُصاغًا بصيغة JSON في حقلٍ نصي، لكن من الصعب البحث في السلاسل النصية الطويلة، وكتابة تعبير نمطي Regular expression للعثور على القيم ضمن تلك السلاسل سيكون أمرًا صعبًا، وإذا غيّرت قيمة من القيم المخزنة ضمن سلسلة JSON فعليك إعادة كتابة السلسلة كلها، وهذا لا يصب في صالح الأداء، لكنه ضروريٌ إذا كنت تعمل على إصدار MySQL 5.6 وما قبله. نوع البيانات JSON في قواعد MySQL أُضيفَ نوعٌ جديدٌ من أنواع البيانات في الإصدار MySQl 5.7 ألا وهو JSON، فقد أصبح مثل الأرقام الصحيحة، والسلاسل النصية …إلخ. وبهذا أصبحت هنالك طريقةٌ لتخزين مستند JSON كامل في عمودٍ من أعمدة جدول في قاعدة البيانات، وقد يكون حجم هذا المستند مقدرًا بالغيغابايت! يتحقق الخادوم أنَّ القيمة المُراد تخزينها في هذا الحقل هي مستند JSON صالح، ومن ثم يحفظه بصيغةٍ ثنائية Binary صُمِّمَت خصيصًا لتسهيل البحث فيها؛ يجدر بالذكر أنَّ نوع البيانات الجديد كان السبب في تحديث نسخة MySQL العاملة في مختلف الخواديم أكثر من أيّ ميزة أخرى. يأتي نوع البيانات الجديد مدعّمًا بأكثر من 20 دالة، وهذه الدوال تستطيع أن تستخلص أزواج «المفتاح-القيمة» Key-value من المستند، أو تحدِّث البيانات، أو توفِّر بيانات وصفية Metadata حول البيانات المخزنة، وتخرج الأعمدة التي ليست بصيغة JSON إلى صيغة JSON، والكثير… إصدار MySQL 8 أصبح في مرحلة Milestone release وسيضيف ميزات ودوال جديد. الدالة JSON_PRETTY_PRINT ستؤدي إلى إظهار المخرجات بتنسيق يُسهِّل فهمها؛ وستُضاف تحسينات أخرى مثل إمكانية تعديل البيانات دون إعادة كتابة المستند بأكمله. كان حفظ البيانات بصيغةٍ غير منسقة يعدّ من ميزات NoSQL، لكن الكثير من قواعد البيانات العلاقية مثل Oracle و SOL Server و PostgreSQL وغيرها قد أضافت نوع البيانات JSON، مما يُصعِّب تعريف الفرق بين قواعد بيانات NoSQL و SQL. لماذا علينا الاهتمام بميزة Document Store بعد أن ظهر نوع البيانات JSON بفترةٍ قصيرة، ظهرت ميزة MySQL Document Store، والتي صُمِّمَت للمبرمجين الذين لا يعرفون لغة الاستعلام البنيوية (SQL) لكنهم يريدون استخدام قواعد البيانات. يُنشِئ المُطوِّر بنى البيانات ويُطبِّق دوال إنشاء البيانات والحصول عليها وتحديثها وحذفها (تُختَصر هذه العمليات عادةً بالاختصار CRUD) على البيانات وفقًا لحاجته باستعمال لغة البرمجة التي يشاء (مثل Java و JavaScript و Node.js و Python و C++ وستُتاح الميزة للغات الأخرى قريبًا). ليس من الضروري أن يعرف المُطوِّر لغةَ SQL، ولن يلقيَ بالًا إلى أنَّ لغة SQL ستُستعمَل وراء الكواليس؛ حيث ستُخزَّن البيانات في عمود JSON، وبهذه الطريقة يستطيع المطورون استخدام البيانات وحفظها دون الحاجة إلى إنشاء جداول في قاعدة البيانات، ولا إلى تضييع الوقت في التخطيط لقاعدة البيانات، ولا إلى انتظار مدير قواعد البيانات لكي يُنشِئها لهم. يجب ألّا ننسى أنَّ أغلبية المشاريع تبدأ دون معرفة كيف ستبدو البيانات بعد إطلاق المشروع، وستتطور بنية تلك البيانات مع مرور الزمن لملائمة مختلف الظروف والحاجات. إذا احتجنا إلى إنشاء قاعدة بيانات علاقية تقليدية من مستندات JSON، فمن السهل استخراج المفاتيح وتحويلها إلى أعمدة لكي تعمل عليها SQL القياسية، ويلي ذلك فهرسة الأعمدة الناتجة لتسريع عملية البحث فيها. الجوانب السلبية إنَّ صيغة JSON ممتازةٌ لتخزين البيانات بصيغةٍ «غير رسمية»، لكن قواعد البيانات العلاقية ملائمةٌ للبيانات المُقسَّمة إلى أقسام صغيرة يسهل الوصول إليها. أضف إلى ذلك عدم القدرة على فرض معايير دقيقة لتخزين البيانات، فيمكن أن يكون اسم المفتاح الذي يُخزِّن عنوان البريد الإلكتروني email أو eMail أو e-mail أو غير ذلك؛ لكن لا أظن أنَّ هذا الأمر سيُشكِّل عائقًا أمامك إذا كنتَ مدركًا له مسبقًا. إذا كنتَ جاهزًا لتجربة حقل JSON، فنزِّل MySQL، ونزِّل بطريقك برمجية MySQL Workbench حيث تدعم أعمدة JSON، وكلا البرمجيتين متاحتان مجانًا. ترجمة – بتصرّف – للمقال What you need to know about JSON in MySQL لصاحبه Dave Stokes.
-
يُعدّ MongoDB أحد أشهر محركات قواعد البيانات من نوع NoSQL، فهو شهير بمرونته، فعاليّته، موثوقيته وسهولة استخدامه، وسنستعرض في المقال كيفية استيراد وتصدير قواعد بيانات MongoDB. تجدر الإشارة إلى أنّه عند حديثنا عن الاستيراد والتصدير فالمقصود التعامل مع البيانات بصيغة مقروءة من قبل البشر، ومتوافقة مع باقي المنتجات البرمجية. بالمقابل، فإن عمليات النسخ الاحتياطي واستعادة النسخ الاحتياطية تُنشئ أو تَستخدم نمط بيانات ثنائية binary خاصّة بـ MongoDB، وتحافظ بالتالي على تناسق وسلامة البيانات إضافة إلى سمات MongoDB الخاصة. بناء على ما سبق، فإنّه من المفضّل استخدام النسخ الاحتياطي عند الحاجة لنقل/تهجير migration قاعدة البيانات طالما أن هناك توافقية ما بين النظام المصدر والنظام الهدف، وهذا الموضوع خارج إطار حديثنا. المتطلبات الأولية قبل أن نتابع، يرجى التأكّد من توفر المتطلبات التالية بشكل كامل: نظام تشغيل Ubuntu 14.04، مستخدم عادي بدون صلاحيات مدير نظام، لكنّه يملك صلاحية تنفيذ أمر sudo. يمكن مراجعة الإعداد الابتدائي لخادوم أوبنتو 14.04 لمزيد من المعلومات، تثبيت وإعداد MongoDB. وعدا عمّا قد يستثنى بوضوح، فإنّ جميع الأوامر التي تحتاج لصلاحيات مدير نظام root في المقال، يجب أن يتم تنفيذها من قبل مستخدم عادي يملك صلاحيات sudo. فهم الأساسيات سنحتاج لفهم بعض الأمور قبل أن نتابع المقال، وإن كنت تملك بعض الخبرة مع قواعد البيانات العلائقية relational المشهورة مثل MySQL، فربّما تجد بعض التشابه عند العمل مع MongoDB. إنّ أول ما تحتاج معرفته حول MongoDB هو أنها تستخدم صيغتي json و bson (الصيغة الثنائية binary من json) بغرض تخزين المعلومات. إنّ Json هي صيغة مقروءة من قبل البشر وبالتالي مناسبة جدًا لتصدير واستيراد البيانات في نهاية الأمر، ومن الممكن أيضًا التعديل على البيانات المصدّرة باستخدام أيّ أداة تدعم json، بما في ذلك أي محرر نصوص بسيط. يبدو أحد الأمثلة عن مستند json على الشكل التالي: {"address":[ {"building":"1007", "street":"Park Ave"}, {"building":"1008", "street":"New Ave"}, ]} إنّ Json مناسبة جدًا للعمل معها، لكنها لا تدعم جميع أنماط البيانات المتاحة في bson، وهذا يعني بأنّه سيكون لدينا "فقدان في الدقّة" في البيانات عند استخدام json، ولهذا السبب فإنّه من الأفضل استخدام الصيغة الثنائية bson في حالة النسخ الاحتياطي والاستعادة لأنّها ستساعد في استعادة قاعدة بيانات MongoDB بشكل أدق. ثانيًا، ليس هناك داعٍ للقلق حول إنشاء قاعدة البيانات إن لم تكن موجودة أصلًا عند القيام باستعادة نسخة احتياطية، حيث سيتم إنشاؤها بشكل تلقائي. إضافة لذلك، فإنّ هيكل المجموعات collections (التي تُقابل الجداول) في القاعدة -بخلاف محركات قواعد البيانات الأخرى- سيتم إنشاؤها أيضًا بشكل تلقائي عند إدراج insert أول سطر. ثالثًا، إن قراءة وإدراج كمّية كبيرة من البيانات في MongoDB، قد يستهلك مصادر النظام كقدرة المعالج، الذاكرة ومساحة التخزين بشكل كبير جدًا وهذه نقطة حساسة على اعتبار أن MongoDB تُستخدم عادة مع قواعد البيانات الكبيرة والبيانات الضخمة، والحل الأسهل لهذه المشكلة هو تنفيذ عمليات التصدير والنسخ الاحتياطي ليلًا. رابعًا، فقد يكون هناك مشكلة في تناسق البيانات consistency إن كنت تملك خادوم MongoDB معرّض لضغط العمل باستمرار وبالتالي قد تتغير البيانات أثناء عملية التصدير، حيث لا يوجد حل بسيط لهذه المشكلة ولكن في نهاية المقال سنتحدث حول استنساخ البيانات replication. استيراد المعلومات إلى قاعدة بيانات MongoDB لنتعلّم كيفية استيراد المعلومات إلى قاعدة بيانات MongoDB، سنقوم باستخدام عيّنة قاعدة بيانات معروفة حول المطاعم. إنّ القاعدة بصيغة json ويمكن تحميلها باستخدام الأمر wget بالشكل التالي: $ wget https://raw.githubusercontent.com/mongodb/docs-assets/primer-dataset/primer-dataset.json وحالما ينتهي التحميل ستحصل على ملف حجمه 12 ميغابايت يُدعى primer-dataset.json في المجلّد الذي قمت بتنفيذ الأمر فيه. سنقوم باستيراد البيانات من هذا الملف إلى قاعدة بيانات جديدة سنسمّيها newdb وضمن جدول سنسمّيه restaurants. للقيام بعملية الاستيراد سنستخدم الأمر mongoimport على الشكل التالي: $ sudo mongoimport --db newdb --collection restaurants --file primer-dataset.json ويُفترض أن تكون نتيجة تنفيذ الأمر السابق على الشكل التالي: 2016-01-17T14:27:04.806-0500 connected to: localhost 2016-01-17T14:27:07.315-0500 imported 25359 documents وكما يظهر في الناتج السابق، فقد تم استيراد 25359 مستند، ولأننا لم نكن نملك قاعدة بيانات باسم newdb، فقد قام محرّك MongoDB بإنشائها بشكل تلقائي، وللتأكّد من نجاح عملية الاستيراد سنقوم بالاتصال بقاعدة البيانات newdb على الشكل التالي: $ sudo mongo newdb سنلاحظ عند تنفيذ الأمر بأن شكل مِحرف سطر الأوامر قد تغيّر، مما يشير إلى نجاح الاتصال بقاعدة البيانات، وللتحقق الآن من عدد المستندات التي تم استيرادها، سنقوم بتنفيذ الأمر التالي: > db.restaurants.count() ويفترض أن تكون النتيجة 25359، وهو مطابق تمامًا لعدد المستندات المستوردة. وللتحقق بشكل أفضل من نجاح الاستيراد، سنقوم باختيار المستند الأول من مجموعة المطاعم بتنفيذ الأمر التالي: > db.restaurants.findOne() وينبغي أن تكون النتيجة على الشكل التالي: { "_id" : ObjectId("569beb098106480d3ed99926"), "address" : { "building" : "1007", "coord" : [ -73.856077, 40.848447 ], "street" : "Morris Park Ave", "zipcode" : "10462" }, "borough" : "Bronx", "cuisine" : "Bakery", "grades" : [ { "date" : ISODate("2014-03-03T00:00:00Z"), "grade" : "A", "score" : 2 }, ... ], "name" : "Morris Park Bake Shop", "restaurant_id" : "30075445" } إنّ مثل هذا التحقق قد يظهر أيّ مشاكل في محتوى المستندات أو ترميزها أو ما شابه ذلك، فصيغة json تستخدم ترميز UTF-8 ويجب أن تكون البيانات المصدّرة والمستوردة بهذا الترميز. تذكّر هذا الأمر دومًا عند القيام بتحرير ملفات json بشكل يدوي، وفيما عدا ذلك فإنّ محرك MongoDB سيتولّى الأمر عنك بشكل تلقائي. أخيرًا، للخروج من سطر أوامر MongoDB نقوم بتنفيذ الأمر exit على الشكل: > exit وسيتم الخروج والعودة إلى سطر أوامر النظام كمستخدم عادي. تصدير المعلومات من قاعدة بيانات MongoDB كما ذكرنا سابقًا، فإنّه من الممكن الحصول على بيانات مقروءة ومفهومة عند القيام بتصدير المعلومات من قاعدة MongoDB، وتكون صيغة الملف المصدّر بشكل افتراضي هي json، ولكن من الممكن أيضًا الحصول على البيانات في ملف بصيغة (csv (comma separated value. نستخدم الأمر mongoexport لتصدير البيانات من قاعدة MongoDB، ويسمح أمر التصدير باختيار قاعدة بيانات، مجموعة من المجموعات collection، حقل من الحقول، وحتّى استخدام استعلام من أجل التصدير. وكمثال بسيط على أمر التصدير mongoexport، سنقوم بتصدير مجموعة المطاعم من قاعدة newdb التي قمنا باستيرادها سابقًا، ويبدو الأمر على النحو التالي: $ sudo mongoexport --db newdb -c restaurants --out newdbexport.json حيث قمنا في الأمر السابق باستخدام المُعامل db-- لتحديد القاعدة، والمُعامل c- لتحديد المجموعة، والمُعامل --out لتحديد اسم الملف الذي سيتم تصدير البيانات إليه، وستكون نتيجة تنفيذ الأمر السابق بشكل ناجح على النحو التالي: 2016-01-20T03:39:00.143-0500 connected to: localhost 2016-01-20T03:39:03.145-0500 exported 25359 records ويظهر الأمر السابق أنه قد تم تصدير 25359 مستند، وهو مماثل تمامًا لعدد المستندات التي قمنا باستيرادها سابقًا. قد نحتاج في بعض الأحيان إلى تصدير جزء من مجموعة، وبالأخذ بعين الاعتبار هيكل ومحتوى مستند المطاعم بصيغة json، سنقوم بتصدير معلومات جميع المطاعم التي تحقق الشرط الذي يقول بأنها موجودة في المنطقة الإدارية المسمّاة Bronx والتي تقدّم الطعام الصيني. للحصول على هذه المعلومات بشكل مباشر في حال كنّا متصلين بقاعدة MongoDB من خلال سطر أوامر MongoDB، فسنقوم بالاتصال بقاعدة البيانات مجددًا: $ sudo mongo newdb ومن ثم سنستخدم الاستعلام: > db.restaurants.find( { borough: "Bronx", cuisine: "Chinese" } ) وسيتم عرض النتيجة مباشرة، وللخروج من سطر أوامر MongoDB سننفّذ الأمر exit كما ذكرنا سابقًا. أمّا لتصدير البيانات من سطر أوامر النظام دون أن نكون متصلين بقاعدة البيانات مسبقًا، فسنقوم بتمرير الاستعلام السابق كمُعامل لأمر mongoexport باستخدام المُعامل q- على الشكل التالي: $ sudo mongoexport --db newdb -c restaurants -q "{ borough: 'Bronx', cuisine: 'Chinese' }" --out Bronx_Chinese_retaurants.json لاحظ في الأمر السابق بأنّا قمنا باستخدام علامات الاقتباس الفرديّة ' داخل علامات الاقتباس الزوجيّة " لأنّ هذا شرط من شروط كتابة الاستعلام في سطر الأوامر، ولو احتجنا لاستخدام علامات اقتباس زوجيّة أو إشارة $ فسنحتاج لتخطي المحارف الخاصة باستخدام \ بإدراجها قبل المحرف الخاص في الاستعلام. إن تمت عملية التصدير بنجاح فينبغي أن تكون النتيجة على الشكل التالي: 2016-01-20T04:16:28.381-0500 connected to: localhost 2016-01-20T04:16:28.461-0500 exported 323 records تُظهر النتيجة السابقة بأنّ هناك 323 سجل قد تم تصديره، ويمكن إيجادها ضمن ملف Bronx_Chinese_retaurants.json الذي قمنا بتحديده. الخلاصة تعرفّنا في المقال على أساسيات استيراد وتصدير المعلومات من وإلى قاعدة بيانات MongoDB. إنّ عملية الاستنساخ replication مفيدة في حالة التوسعة، ولكنّها مهمة أيضًا للنواحي التي تحدثنا عنها، حيث تسمح باستمرارية تشغيل خدمات MongoDB دون انقطاع عبر خادوم MongoDB ثانوي بينما نقوم باستعادة نسخة احتياطية إلى الخادوم الرئيسي عند حدوث فشل. إن جزءًا من عملية الاستنساخ هو سجل العمليات (oplog)، الذي يقوم بتسجيل جميع العمليات التي تقوم بتغيير البيانات، ويمكن استخدام هذا السجل كما في MySQL، لاستعادة البيانات بعد أن تكون آخر عملية نسخ احتياطي قد بدأت. تذكّر بأن عمليات النسخ الاحتياطي تحصل في الليل عندما يكون نشاط قاعدة البيانات في حدّه الأدنى، وإن قررت استعادة نسخة احتياطية لقاعدة البيانات في الفترة المسائية (أي قبل أن تبدأ عملية النسخ الاحتياطي الليلية) فإنّك ستفقد بذلك جميع التعديلات التي تمت على القاعدة منذ آخر عملية نسخ احتياطي. ترجمة -وبتصرّف- للمقال How To Import and Export a MongoDB Database on Ubuntu 14.04 لصاحبه Anatoliy Dimitrov.
-
MemSQL عبارة عن قاعدة بيانات تعمل مُباشرة من الذاكرة in-memory تستطيع أن تُخدِّم القراءة والكتابة بشكل أسرع من قواعد البيانات التقليديّة، وبالرغم من أنّها تقنية حديثة إلّا أنّها تتعامل بميفاق protocol قاعدة بيانات MySQL لذلك يكون التعامل معها مألوفًا. تضم MemSQL أحدث قدرات MySQL مع ميّزات حديثة مثل دعم JSON والقدرة على عمل upsert للبيانات (تعني كلمة upsert إدراج صف جديد إن لم يكن موجودًا أي insert، أو تحديث هذا الصف إن كان موجودًا أي update). إنّ أحد أهم نقاط تفوّق MemSQL على MySQL هي قدرتها على فصل الاستعلام query عبر عدّة عقد nodes، والمعروفة أيضًا باسم المعالجة المتوازية على نطاق واسع massively parallel processing، ممّا يؤدي إلى سرعة أكبر في قراءة الاستعلامات. سنقوم في هذا الدّرس بتثبيت MemSQL على خادوم Ubuntu، تنفيذ تجارب قياس الأداء benchmarks، والتعامل مع إدراج بيانات JSON عبر عميل سطر الأوامر في MySQL. المتطلبات الأساسيةسنحتاج لمتابعة هذا الدّرس إلى: Ubuntu 14.04 x64 Droplet مع ذاكرة RAM 8 غيغابايت على الأقل (أو خادوم محلّي بنفس المواصفات)مستخدم غير جذري non-root مع صلاحيّات sudo، والذي يُمكِن إعداده عن طريق درس الإعداد الأولي للخادوم مع Ubuntu.الخطوة الأولى – تثبيت MemSQLسنقوم في هذا القسم بتحضير بيئة العمل من أجل تثبيت MemSQL. يتم عرض آخر إصدار من MemSQL على صفحة تحميله، سنقوم بتحميل وتثبيت MemSQL Ops، والذي هو برنامج يدير تحميل وتحضير خادومنا لتشغيل MemSQL بشكل صحيح، الإصدار الأحدث من MemSQL Ops لدى كتابة هذا الدّرس هو 4.0.35. نقوم في البداية بتنزيل ملف حزمة تثبيت MemSQL من موقعها على الإنترنت: wget http://download.memsql.com/memsql-ops-4.0.35/memsql-ops-4.0.35.tar.gzنستخرج extract بعدها الحزمة: tar -xzf memsql-ops-4.0.35.tar.gzأنشأ استخراج الحزمة مجلّدًا يُدعى memsql-ops-4.0.35، نلاحظ أنّ اسم المجلّد يحتوي على رقم الإصدار، لذلك إن قمت بتنزيل إصدار أحدث من الإصدار المحدّد في هذا الدّرس فستملك مجلّدًا مع رقم الإصدار الذي نزّلته. نغير الدليل إلى هذا المجلّد: cd memsql-ops-4.0.35ثم نقوم بتنفيذ script التثبيت والذي هو جزء من حزمة التثبيت التي استخرجناها للتو: sudo ./install.shسنرى بعض الخَرْج output من الـ script، وسيسألنا بعد لحظات إذا ما كنّا نرغب بتثبيت MemSQL على هذا المُضيف host فقط، سنتعلّم تثبيت MemSQL على عدّة أجهزة في درس لاحق، لذا من أجل غرض هذا الدّرس فلنقل نعم yes عن طريق إدخال الحرف y: Installation script prompt and output . . . Do you want to install MemSQL on this host only? [y/N] y 2015-09-04 14:30:38: Jd0af3b [INFO] Deploying MemSQL to 45.55.146.81:3306 2015-09-04 14:30:38: J4e047f [INFO] Deploying MemSQL to 45.55.146.81:3307 2015-09-04 14:30:48: J4e047f [INFO] Downloading MemSQL: 100.00% 2015-09-04 14:30:48: J4e047f [INFO] Installing MemSQL 2015-09-04 14:30:49: Jd0af3b [INFO] Downloading MemSQL: 100.00% 2015-09-04 14:30:49: Jd0af3b [INFO] Installing MemSQL 2015-09-04 14:31:01: J4e047f [INFO] Finishing MemSQL Install 2015-09-04 14:31:03: Jd0af3b [INFO] Finishing MemSQL Install Waiting for MemSQL to start...نمتلك الآن مجموعة MemSQL مُثبَّتة على خادوم أوبونتو لدينا، ولكن نلاحظ من السجلّات السّابقة أنّه تم تثبيت MemSQL مرتين. تستطيع MemSQL أن تعمل بدورين مختلفين: عقدة مُجمِّع aggregator node وعقدة ورقة leaf node، إنّ سبب تثبيت MemSQL مرتين هو أنّها تحتاج على الأقل إلى عقدة مُجمِّع واحدة وعقدة ورقة واحدة لكي يعمل العنقود cluster. إنّ عقدة المُجمِّع aggregator node هي واجهتنا إلى MemSQL، وهي تبدو بالنسبة للعالم الخارجي مشابهة كثيرًا لـ MySQL، فهي تستمع إلى نفس المنفذ port، وبإمكاننا أن نربط إليها أدوات تتوقّع أن تتعامل مع MySQL ومكتبات MySQL المعياريّة، وظيفة المُجمِّع هي أن يعرف عن كافّة عُقَد الورقة leaf nodes لـ MemSQL، يتعامل مع عُملاء MySQL، ويترجم استعلاماتهم إلى MemSQL. تُخزِّن عقدة الورقة leaf node البيانات فعليًّا، فعندما تستقبل عقدة الورقة طلبًا من عقدة المُجمِّع لقراءة أو كتابة البيانات تقوم بتنفيذ هذا الاستعلام وتُعيد النتائج إلى عقدة المُجمِّع، تسمح MemSQL لنا بمشاركة بياناتنا عبر عدّة مضيفين، وتمتلك كل عقدة ورقة قسمًا من تلك البيانات (حتى مع وجود عقدة ورقة واحدة تكون البيانات تكون البيانات مُقسَّمة ضمن تلك العقدة). عندما نملك عدة عقد ورقة يكون المُجمِّع مسؤولًا عن ترجمة استعلامات MySQL لجميع عقد الورقة التي ينبغي أن تشارك في هذا الاستعلام، ومن ثمّ يتلقى الردود من جميع عقد الورقة ويُجمِّع النتيجة في استعلام واحد يعود إلى عميل MySQL لدينا، وهكذا تتم إدارة الاستعلامات المتوازية. يمتلك إعداد المضيف الوحيد لدينا عقدة مُجمِّع وورقة تعملان على نفس الجهاز، ولكن نستطيع إضافة المزيد من عقد الورقة عبر العديد من الأجهزة الأخرى. الخطوة الثانية – تنفيذ تجربة قياس أداءفلنرى مدى السّرعة التي تستطيع أن تعمل بها MemSQL باستخدام الأداة MemSQL Ops والتي تم تثبيتها كجزء من script تثبيت MemSQL. نذهب إلى http://you_server_ip:9000 في متصفحنا: تعطينا الأداة MemSQL Ops لمحة عامّة عن العنقود cluster لدينا، نمتلك عقدتي MemSQL: المُجمِّع الرئيسي وعقدة الورقة. فلنقم بإجراء اختبار السّرعة Speed Test على عقدة MemSQL في جهازنا المفرد، نضغط على Speed Test من القائمة الموجودة على اليسار، وبعدها نضغط على START TEST، وهذا مثال عن النتائج التي قد نراها: لن نشرح في هذا الدّرس كيفيّة تثبيت MemSQL على خواديم متعددة، ولكن من أجل المقارنة أدرجنا هنا قياس أداء من عنقود MemSQL على نظام Ubuntu يملك 8 جيجابايت من الذّاكرة Ram وعدّة عقد (عقدة مُجمِّع وعقدتا leaf): نكون قادرين بزيادة عدد عقد leaf أن نُضاعِف مُعدَّل الإدراج insert، وبالنظر إلى أقسام قراءة الصفوف Rows Read نستطيع أن نرى أنّ عنقود العقد الثلاثة لدينا قادر على قراءة الصفوف بشكل متزامن أكثر بمقدار 12 مليون صف من عنقود العقدة الواحدة وفي نفس المدة الزمنية. الخطوة الثالثة – التعامل مع MemSQL من خلال mysql-clientتبدو MemSQL بالنسبة للعملاء مثل MySQL، فكلاهما تتعامل بنفس الميفاق protocol، ولبدء التخاطب مع عنقود MemSQL لدينا نقوم بتثبيت mysql-client. في البداية نقوم بتحديث apt لكي نُثبِّت الإصدار الأخير من العميل client في الخطوة التالية: sudo apt-get updateنُثبِّت الآن عميل MySQL والذي سيُمكّننا من تنفيذ الأمر mysql: sudo apt-get install mysql-client-core-5.6نحن الآن على استعداد للاتصال بـ MemSQL باستخدام عميل MySQL، سنتصل باستخدام المستخدم الجذري root إلى المضيف 127.0.0.1 (والذي هو عنوان IP للمضيف المحلّي localhost لدينا) على المنفذ 3306، سنقوم بتخصيص رسالة المُحث prompt لتكون <memsql: mysql -u root -h 127.0.0.1 -P 3306 --prompt="memsql> "سنشاهد بعض أسطر الخَرْج متبوعة بالمُحث <memsql. فلنقم بسرد list قواعد البيانات: memsql> show databases; سنشاهد هذا الخَرْج: +--------------------+ | Database | +--------------------+ | information_schema | | memsql | | sharding | +--------------------+ 3 rows in set (0.01 sec)نُنشِئ قاعدة بيانات جديدة تُدعى tutorial: memsql> create database tutorial;ثم نتحوّل لاستخدام قاعدة البيانات الجديدة باستخدام الأمر use: memsql> use tutorial;نقوم بعدها بإنشاء جدول users والذي يملك الحقلين id و email، يجب علينا تحديد نوع لكلا هذين الحقلين، فلنجعل id من نوع bigint و email من نوع varchar بطول 255، سنخبر أيضًا قاعدة البيانات أنّ الحقل id هو مفتاح أساسي primary key والحقل email لا يُمكن أن يكون عَدم Null. memsql> create table users (id bigint auto_increment primary key, email varchar(255) not null);ربّما تلاحظ زمن تنفيذ بطيء للأمر الأخير (15-20 ثانية)، هناك سبب رئيسي يجعل من MemSQL بطيئة في إنشاء هذا الجدول الجديد وهو: توليد الشيفرة code generation. تستخدم MemSQL توليد الشيفرة لتنفيذ الاستعلامات، وهذا يعني أنّه في كل مرة تتم فيها مصادفة نوع جديد من الاستعلامات تحتاج MemSQL توليد وتصريف compile الشيفرة التي تُمثِّل الاستعلام، يتم بعدها نقل الشيفرة إلى العنقود لتنفيذها، وهذا يُسرِّع عمليّة معالجة البيانات الفعليّة ولكن هناك تكلفة من أجل التحضير، تبذل MemSQL جهدها لإعادة استخدام الاستعلامات المُولَّدة مُسبقًا pre-generated queries، ولكن تبقى الاستعلامات الجديدة ذات البُنية التي لم تشاهدها MemSQL من قبل بطيئة. وبالعودة إلى جدول users نقوم بإلقاء نظرة على تعريفه: memsql> describe users;+-------+--------------+------+------+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+------+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | email | varchar(255) | NO | | NULL | | +-------+--------------+------+------+---------+----------------+ 2 rows in set (0.00 sec)فلنقم الآن بإدراج بعض أمثلة عناوين البريد الإلكتروني في الجدول users، وهي نفس الصياغة syntax التي نستخدمها لقاعدة بيانات MySQL: memsql> insert into users (email) values ('one@example.com'), ('two@example.com'), ('three@example.com');Inserting emails output Query OK, 3 rows affected (1.57 sec) Records: 3 Duplicates: 0 Warnings: 0نستعلم الآن عن الجدول users: memsql> select * from users;بإمكاننا رؤية البيانات التي أدخلناها للتو: +----+-------------------+ | id | email | +----+-------------------+ | 2 | two@example.com | | 1 | one@example.com | | 3 | three@example.com | +----+-------------------+ 3 rows in set (0.07 sec) الخطوة الرابعة – إدراج واستعلام JSONتوفِّر MemSQL نوع JSON، لذا سنقوم في هذه الخطوة بإنشاء جدول أحداث events لاستخدام الأحداث الواردة، يمتلك هذا الجدول حقل id (كما فعلنا مع جدول users) وحقل event والذي سيكون من النوع JSON: memsql> create table events (id bigint auto_increment primary key, event json not null);فلنقم بإدراج حدثين، سنقوم في JSON بإرجاع حقل email والذي بدوره يقوم بإعادة الإرجاع إلى مُعرِّفات IDs المستخدمين الذين أدخلناهم في الخطوة الثالثة: memsql> insert into events (event) values ('{"name": "sent email", "email": "one@example.com"}'), ('{"name": "received email", "email": "two@example.com"}');نقوم الآن بإلقاء نظرة على الأحداث events التي أدرجناها للتو: memsql> select * from events;+----+-----------------------------------------------------+ | id | event | +----+-----------------------------------------------------+ | 2 | {"email":"two@example.com","name":"received email"} | | 1 | {"email":"one@example.com","name":"sent email"} | +----+-----------------------------------------------------+ 2 rows in set (3.46 sec)نستطيع بعدها الاستعلام عن كل الأحداث events التي تكون خاصّية JSON لها التي تُدعى name هي النّص “received email”: memsql> select * from events where event::$name = 'received email';+----+-----------------------------------------------------+ | id | event | +----+-----------------------------------------------------+ | 2 | {"email":"two@example.com","name":"received email"} | +----+-----------------------------------------------------+ 1 row in set (5.84 sec)نحاول تغيير هذا الاستعلام لإيجاد تلك الأحداث التي خاصيّة name لها هي النّص “sent email”: memsql> select * from events where event::$name = 'sent email';+----+-------------------------------------------------+ | id | event | +----+-------------------------------------------------+ | 1 | {"email":"one@example.com","name":"sent email"} | +----+-------------------------------------------------+ 1 row in set (0.00 sec)تم تنفيذ هذا الاستعلام الأخير بشكل أسرع من الاستعلام الذي سبقه لأنّنا غيّرنا فقط مُعامِل في الاستعلام، لذا كانت MemSQL قادرة على تخطّي توليد الشيفرة. فلنقم بعمل شيء أكثر تقدّمًا بالنسبة لقاعدة بيانات SQL مُوزَّعة، وهو ضم جدولين على أساس مفاتيح غير أساسيّة non-primary حيث يتم تداخل قيمة ما من الانضمام join بداخل قيمة JSON ولكن يكون الترشيح filter على أساس قيمة JSON مختلفة. نسأل في البداية عن كافّة حقول جدول المستخدمين users مع ضم جدول الأحداث events بمطابقة حقل البريد الإلكتروني email حيث يكون اسم الحدث هو “received email”. memsql> select * from users left join events on users.email = events.event::$email where events.event::$name = 'received email';+----+-----------------+------+-----------------------------------------------------+ | id | email | id | event | +----+-----------------+------+-----------------------------------------------------+ | 2 | two@example.com | 2 | {"email":"two@example.com","name":"received email"} | +----+-----------------+------+-----------------------------------------------------+ 1 row in set (14.19 sec)نجرب بعد ذلك نفس الاستعلام ولكن مع ترشيح الأحداث “sent email” فقط: memsql> select * from users left join events on users.email = events.event::$email where events.event::$name = 'sent email'; +----+-----------------+------+-------------------------------------------------+ | id | email | id | event | +----+-----------------+------+-------------------------------------------------+ | 1 | one@example.com | 1 | {"email":"one@example.com","name":"sent email"} | +----+-----------------+------+-------------------------------------------------+ 1 row in set (0.01 sec)وكما وجدنا سابقًا فإنّ الاستعلام الثاني أسرع بكثير من الأول، تظهر فائدة توليد الشيفرة عند تنفيذ أكثر من مليون صف، كما رأينا في قياس الأداء، إنّ مرونة استخدام قواعد بيانات SQL تفهم JSON وكيفيّة الانضمام بين الجداول هي ميزة قوية للمستخدمين. الخاتمةلقد قمنا بتثبيت MemSQL، تنفيذ تجربة قياس أداء العقد لدينا، التعامل مع العقدة من خلال عميل MySQL المعياري، وتعاملنا مع بعض الميّزات المتقدمة غير الموجودة في MySQL، ينبغي أن يعطينا هذا فكرة واضحة عمّا يمكن أن تفعله قاعدة بيانات SQL داخل الذاكرة لنا. لا يزال هناك الكثير لتعلّمه حول كيفيّة توزيع MemSQL لبياناتنا فعليًّا، كيفية بناء الجداول من أجل أفضل أداء، كيفيّة توسيع MemSQL عبر عدّة عقد، كيفيّة تكرار بياناتنا من أجل توافريّة عالية للبيانات، وكيفيّة تأمين MemSQL. ترجمة -وبتصرّف- لـ How to Install MemSQL on Ubuntu 14.04 لصاحبه Ian Hansen.