دليل سريع لكن كامل إلى قاعدة بيانات مفهرسة وتخزين البيانات في المتصفحات

هل أنت مهتم بتعلم JavaScript؟ احصل على كتاب JavaScript الإلكتروني الخاص بي في jshandbook.com

مقدمة إلى قاعدة البيانات المفهرسة

تعد IndexedDB إحدى إمكانات التخزين التي تم تقديمها في المتصفحات على مر السنين.

إنه متجر مفتاح / قيمة (قاعدة بيانات noSQL) يعتبر الحل النهائي لتخزين البيانات في المتصفحات .

إنها واجهة برمجة تطبيقات غير متزامنة ، مما يعني أن إجراء عمليات مكلفة لن يمنع مؤشر ترابط واجهة المستخدم الذي يوفر تجربة قذرة للمستخدمين. يمكنه تخزين كمية غير محددة من البيانات ، على الرغم من أنه بمجرد تجاوز حد معين ، يُطلب من المستخدم إعطاء الموقع حدودًا أعلى.

إنه مدعوم على جميع المتصفحات الحديثة.

وهو يدعم المعاملات وإصدار الإصدارات ويعطي أداءً جيدًا.

داخل المتصفح يمكننا أيضًا استخدام:

  • ملفات تعريف الارتباط : يمكن أن تستضيف كمية صغيرة جدًا من السلاسل
  • تخزين الويب (أو تخزين DOM) ، وهو مصطلح يعرّف عادةً localStorage و sessionStorage ، وهما مخزنان للمفتاح / القيمة. جلسة التخزين ، لا تحتفظ بالبيانات ، والتي يتم مسحها عند انتهاء الجلسة ، بينما يحتفظ التخزين المحلي بالبيانات عبر الجلسات

من عيوب التخزين المحلي / الجلسة أن يتم تحديده بحجم صغير (وغير متسق) ، حيث يوفر تنفيذ المتصفحات من 2 ميجابايت إلى 10 ميجابايت من المساحة لكل موقع.

في الماضي ، كان لدينا أيضًا Web SQL ، وهو عبارة عن غلاف حول SQLite ، ولكن الآن هذا مهمل وغير مدعوم في بعض المتصفحات الحديثة ، لم يكن أبدًا معيارًا معترفًا به ، لذا لا ينبغي استخدامه ، على الرغم من أن 83٪ من المستخدمين لديهم هذه التقنية على الأجهزة وفقًا لـ Can I Use.

بينما يمكنك إنشاء قواعد بيانات متعددة من الناحية الفنية لكل موقع ، فإنك عمومًا تنشئ قاعدة بيانات واحدة ، ويمكنك داخل قاعدة البيانات هذه إنشاء مخازن كائنات متعددة .

تعتبر قاعدة البيانات خاصة بمجال ، لذلك لا يمكن لأي موقع آخر الوصول إلى موقع ويب آخر لمتاجر IndexedDB.

يحتوي كل متجر عادة على مجموعة من الأشياء ، والتي يمكن أن تكون

  • سلاسل
  • أعداد
  • شاء
  • المصفوفات
  • تواريخ

على سبيل المثال ، قد يكون لديك متجر يحتوي على مشاركات ، وآخر يحتوي على تعليقات.

يحتوي المتجر على عدد من العناصر التي لها مفتاح فريد ، والذي يمثل الطريقة التي يمكن من خلالها تحديد العنصر.

يمكنك تغيير تلك المتاجر باستخدام المعاملات ، عن طريق إجراء عمليات الإضافة والتعديل والحذف ، والتكرار على العناصر التي تحتوي عليها.

منذ ظهور Promises في ES6 ، والانتقال اللاحق لواجهات برمجة التطبيقات لاستخدام الوعود ، يبدو أن واجهة برمجة تطبيقات IndexedDB هي مدرسة قديمة بعض الشيء .

على الرغم من عدم وجود خطأ في ذلك ، في جميع الأمثلة التي سأشرحها ، سأستخدم مكتبة IndexedDB الموعودة بواسطة Jake Archibald ، وهي طبقة صغيرة أعلى واجهة برمجة تطبيقات IndexedDB لتسهيل استخدامها.

تُستخدم هذه المكتبة أيضًا في جميع الأمثلة الموجودة على موقع Google Developers فيما يتعلق بقاعدة البيانات المفهرسة

أنشئ قاعدة بيانات مفهرسة

إن أبسط طريقة هي استخدام unpkg ، عن طريق إضافة هذا إلى رأس الصفحة:

 import { openDB, deleteDB } from '//unpkg.com/idb?module'  

قبل استخدام IndexedDB API ، تأكد دائمًا من التحقق من الدعم في المتصفح ، على الرغم من توفره على نطاق واسع ، فأنت لا تعرف أبدًا أي متصفح يستخدمه المستخدم:

(() => { 'use strict' if (!('indexedDB' in window)) { console.warn('IndexedDB not supported') return } //...IndexedDB code })() 

كيفية إنشاء قاعدة بيانات

باستخدام openDB():

(async () => { //... const dbName = 'mydbname' const storeName = 'store1' const version = 1 //versions start at 1 const db = await openDB(dbName, version, { upgrade(db, oldVersion, newVersion, transaction) { const store = db.createObjectStore(storeName) } }) })() 

أول معلمتين هما اسم قاعدة البيانات و verson المعلمة الثالثة ، وهي اختيارية ، هي كائن يحتوي على وظيفة تسمى فقط إذا كان رقم الإصدار أعلى من إصدار قاعدة البيانات المثبتة حاليًا . في جسم الوظيفة ، يمكنك ترقية البنية (المخازن والفهارس) لـ db.

إضافة البيانات إلى المتجر

إضافة البيانات عند إنشاء المخزن وتهيئته

أنت تستخدم putطريقة تخزين الكائن ، لكننا نحتاج أولاً إلى مرجع لها ، والذي يمكننا الحصول عليه من db.createObjectStore()عند إنشائه.

عند الاستخدام put، تكون القيمة هي الوسيطة الأولى ، والمفتاح هو الثاني. هذا لأنه إذا قمت بتحديد keyPathعند إنشاء ملف تخزين العناصر ، فلن تحتاج إلى إدخال اسم المفتاح في كل طلب put () ، يمكنك فقط كتابة القيمة.

يتم ملء هذا store0بمجرد إنشائه:

(async () => { //... const dbName = 'mydbname' const storeName = 'store0' const version = 1 const db = await openDB(dbName, version,{ upgrade(db, oldVersion, newVersion, transaction) { const store = db.createObjectStore(storeName) store.put('Hello world!', 'Hello') } }) })() 

إضافة البيانات عند إنشاء المتجر بالفعل باستخدام المعاملات

لإضافة عناصر لاحقًا على الطريق ، تحتاج إلى إنشاء معاملة قراءة / كتابة ، تضمن سلامة قاعدة البيانات (إذا فشلت إحدى العمليات ، يتم التراجع عن جميع العمليات في المعاملة وتعود الحالة إلى الحالة المعروفة).

لذلك ، استخدم إشارة إلى dbPromiseالكائن الذي حصلنا عليه عند الاتصال openDB، وقم بتشغيل:

(async () => { //... const dbName = 'mydbname' const storeName = 'store0' const version = 1 const db = await openDB(/* ... */) const tx = db.transaction(storeName, 'readwrite') const store = await tx.objectStore(storeName) const val = 'hey!' const key = 'Hello again' const value = await store.put(val, key) await tx.done })() 

الحصول على البيانات من متجر

الحصول على عنصر واحد من متجر: get()

const key = 'Hello again' const item = await db.transaction(storeName).objectStore(storeName).get(key) 

الحصول على جميع العناصر من متجر: getAll()

احصل على جميع المفاتيح المخزنة

const items = await db.transaction(storeName).objectStore(storeName).getAllKeys() 

احصل على جميع القيم المخزنة

const items = await db.transaction(storeName).objectStore(storeName).getAll() 

حذف البيانات من قاعدة البيانات المفهرسة

حذف قاعدة البيانات ومخزن العناصر والبيانات

حذف قاعدة بيانات IndexedDB بأكملها

const dbName = 'mydbname' await deleteDB(dbName) 

لحذف البيانات في ملف تخزين العناصر

نحن نستخدم معاملة:

(async () => { //... const dbName = 'mydbname' const storeName = 'store1' const version = 1 const db = await openDB(dbName, version, { upgrade(db, oldVersion, newVersion, transaction) { const store = db.createObjectStore(storeName) } }) const tx = await db.transaction(storeName, 'readwrite') const store = await tx.objectStore(storeName) const key = 'Hello again' await store.delete(key) await tx.done })() 

الترحيل من الإصدار السابق لقاعدة البيانات

The third (optional) parameter of the openDB() function is an object that can contain an upgrade function called only if the version number is higher than the current installed database version. In that function body you can upgrade the structure (stores and indexes) of the db:

const name = 'mydbname' const version = 1 openDB(name, version, { upgrade(db, oldVersion, newVersion, transaction) { console.log(oldVersion) } }) 

In this callback, you can check from which version the user is updating, and perform some operations accordingly.

You can perform a migration from a previous database version using this syntax

(async () => { //... const dbName = 'mydbname' const storeName = 'store0' const version = 1 const db = await openDB(dbName, version, { upgrade(db, oldVersion, newVersion, transaction) { switch (oldVersion) { case 0: // no db created before // a store introduced in version 1 db.createObjectStore('store1') case 1: // a new store in version 2 db.createObjectStore('store2', { keyPath: 'name' }) } db.createObjectStore(storeName) } }) })() 

Unique keys

createObjectStore() as you can see in case 1 accepts a second parameter that indicates the index key of the database. This is very useful when you store objects: put() calls don't need a second parameter, but can just take the value (an object) and the key will be mapped to the object property that has that name.

The index gives you a way to retrieve a value later by that specific key, and it must be unique (every item must have a different key)

A key can be set to auto increment, so you don't need to keep track of it on the client code:

db.createObjectStore('notes', { autoIncrement: true }) 

Use auto increment if your values do not contain a unique key already (for example, if you collect email addresses without an associated name).

Check if a store exists

You can check if an object store already exists by calling the objectStoreNames() method:

const storeName = 'store1' if (!db.objectStoreNames.contains(storeName)) { db.createObjectStore(storeName) } 

Deleting from IndexedDB

Deleting the database, an object store and data

Delete a database

await deleteDB('mydb') 

Delete an object store

An object store can only be deleted in the callback when opening a db, and that callback is only called if you specify a version higher than the one currently installed:

const db = await openDB('dogsdb', 2, { upgrade(db, oldVersion, newVersion, transaction) { switch (oldVersion) { case 0: // no db created before // a store introduced in version 1 db.createObjectStore('store1') case 1: // delete the old store in version 2, create a new one db.deleteObjectStore('store1') db.createObjectStore('store2') } } }) 

To delete data in an object store use a transaction

const key = 232 //a random key const db = await openDB(/*...*/) const tx = await db.transaction('store', 'readwrite') const store = await tx.objectStore('store') await store.delete(key) await tx.complete 

There's more!

هذه هي الأساسيات فقط. لم أتحدث عن المؤشرات والأشياء الأكثر تقدمًا. هناك المزيد في IndexedDB ولكن آمل أن يمنحك هذا السبق.

هل أنت مهتم بتعلم JavaScript؟ احصل على كتاب JavaScript الخاص بي في jshandbook.com