TinyDB – قاعدة بيانات NoSQL خفيفة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

دليل شامل لـ TinyDB: قاعدة بيانات NoSQL خفيفة للبايثون

مقدمة

لا تحتاج التطبيقات الحديثة دائمًا إلى أنظمة إدارة قواعد بيانات ضخمة ومعقدة. في الحالات التي لا يتطلب فيها المشروع قابلية التوسع أو سرعة عالية في معالجة كميات كبيرة من البيانات، تكفي قاعدة بيانات خفيفة ومضمنة. TinyDB – قاعدة بيانات NoSQL مكتوبة بالكامل بلغة بايثون، تمثل حلاً مريحًا وبسيطًا لتخزين البيانات المنظمة بدون استخدام SQL.

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

التثبيت والإعداد الأساسي

تثبيت TinyDB

يمكن تثبيت TinyDB بسطر واحد عبر pip:

pip install tinydb

لاستخدام ميزات إضافية، تتوفر إضافات:

pip install tinydb[compression]  # لضغط البيانات
pip install tinydb[yaml]         # للعمل مع YAML

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

إنشاء قاعدة بيانات مع الحفظ في ملف:

from tinydb import TinyDB
db = TinyDB('db.json')  # سيتم إنشاء الملف تلقائيًا

إنشاء قاعدة بيانات في الذاكرة:

from tinydb.storages import MemoryStorage
db = TinyDB(storage=MemoryStorage)

ضبط الترميز والإعدادات

from tinydb import TinyDB
from tinydb.storages import JSONStorage

# ضبط الترميز
db = TinyDB('db.json', encoding='utf-8')

# ضبط المسافات في JSON لسهولة القراءة
db = TinyDB('db.json', indent=4, separators=(',', ': '))

أساسيات هيكل البيانات في TinyDB

يستخدم TinyDB نموذج بيانات موجه للمستندات:

  • تُخزَّن البيانات كقائمة من المستندات (قواميس بايثون)
  • كل مستند له doc_id فريد، يتم إنشاؤه تلقائيًا
  • الأنواع المدعومة: نصوص، أرقام، قوائم، قواميس، قيم منطقية، و null
  • يمكن أن يكون للمستندات هياكل مختلفة في نفس الجدول
  • دعم التداخل (nesting) للبيانات بأي عمق

العمليات الأساسية على البيانات

إدراج البيانات

إدراج مستند واحد:

from tinydb import TinyDB
db = TinyDB('db.json')

# إدراج بسيط
db.insert({'name': 'أحمد', 'age': 30, 'city': 'القاهرة'})

# إدراج مع الحصول على المعرف
doc_id = db.insert({'name': 'سارة', 'age': 25})
print(f"تمت إضافة المستند بالمعرف: {doc_id}")

إدراج متعدد:

users = [
    {'name': 'سارة', 'age': 25, 'profession': 'مصممة'},
    {'name': 'بيتر', 'age': 40, 'profession': 'مبرمج'},
    {'name': 'مريم', 'age': 28, 'profession': 'مديرة'}
]

doc_ids = db.insert_multiple(users)
print(f"تمت إضافة مستندات: {len(doc_ids)}")

قراءة البيانات

الحصول على جميع المستندات:

all_users = db.all()
print(f"إجمالي المستخدمين: {len(all_users)}")

الحصول على مستند بواسطة المعرف:

user = db.get(doc_id=1)
if user:
    print(f"تم العثور على المستخدم: {user['name']}")

البحث والتصفية

أساسيات البحث باستخدام Query:

from tinydb import Query
User = Query()

# البحث بالتطابق التام
users = db.search(User.name == 'أحمد')

# البحث بشرط
adults = db.search(User.age >= 30)

# الحصول على أول تطابق
user = db.get(User.name == 'سارة')

شروط بحث معقدة:

# AND منطقي
young_designers = db.search((User.age < 30) & (User.profession == 'مصممة'))

# OR منطقي
managers_or_designers = db.search((User.profession == 'مديرة') | (User.profession == 'مصممة'))

# البحث في القوائم
users_with_skills = db.search(User.skills.any(['Python', 'JavaScript']))

# البحث في النصوص
name_contains = db.search(User.name.search('أح'))

تحديث البيانات

تحديث مستند واحد:

# تحديث باستخدام المعرف
db.update({'age': 31}, doc_ids=[1])

# تحديث باستخدام الشرط
db.update({'city': 'الإسكندرية'}, User.name == 'أحمد')

تحديث متعدد:

# زيادة العمر للجميع
db.update({'age': User.age + 1})

# تحديث حقول متعددة
db.update({'profession': 'مطور', 'salary': 5000}, User.name == 'بيتر')

حذف البيانات

# حذف مستند بواسطة المعرف
db.remove(doc_ids=[1])

# حذف باستخدام الشرط
db.remove(User.age < 18)

# حذف جميع المستندات
db.truncate()

الميزات المتقدمة

الجداول (Tables)

يمكن استخدام جداول متعددة داخل نفس الملف:

# إنشاء أو الوصول إلى جدول
users_table = db.table('users')
products_table = db.table('products')

# إدراج في جدول محدد
users_table.insert({'name': 'خالد', 'role': 'مستخدم'})
products_table.insert({'name': 'لابتوب', 'price': 1500})

# الحصول على جميع الجداول
all_tables = db.tables()
print(f"الجداول المتاحة: {all_tables}")

الفهارس (Indexing)

from tinydb import TinyDB
from tinydb.table import Document

# إنشاء فهرس على حقل
db = TinyDB('db.json')
users = db.table('users')
users.create_index('name')  # فهرس على حقل الاسم

# البحث باستخدام الفهرس
users.search(User.name == 'أحمد')  # أسرع مع الفهرس

التخزين المخصص

from tinydb.storages import JSONStorage, MemoryStorage
from tinydb.middlewares import CachingMiddleware

# استخدام التخزين مع التخزين المؤقت
db = TinyDB('db.json', storage=CachingMiddleware(JSONStorage))

# تخزين مخصص مع ضغط
from tinydb.storages import JSONStorage
import gzip

class CompressedJSONStorage(JSONStorage):
    def __init__(self, path):
        super().__init__(path)
    
    def read(self):
        with gzip.open(self.path, 'rt') as f:
            return self._read(f)
    
    def write(self, data):
        with gzip.open(self.path, 'wt') as f:
            self._write(f, data)

db = TinyDB('db.json', storage=CompressedJSONStorage)

التكامل مع الأطر الشائعة

TinyDB مع Flask

from flask import Flask, jsonify, request
from tinydb import TinyDB, Query

app = Flask(__name__)
db = TinyDB('users.json')
User = Query()

@app.route('/users', methods=['GET'])
def get_users():
    users = db.all()
    return jsonify(users)

@app.route('/users', methods=['POST'])
def add_user():
    data = request.json
    doc_id = db.insert(data)
    return jsonify({'id': doc_id, 'message': 'تمت إضافة المستخدم'}), 201

@app.route('/users/', methods=['GET'])
def get_user(name):
    user = db.get(User.name == name)
    if user:
        return jsonify(user)
    return jsonify({'error': 'المستخدم غير موجود'}), 404

if __name__ == '__main__':
    app.run(debug=True)

TinyDB مع FastAPI

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from tinydb import TinyDB, Query

app = FastAPI()
db = TinyDB('users.json')
User = Query()

class UserModel(BaseModel):
    name: str
    age: int
    profession: str = None

@app.post("/users/")
async def create_user(user: UserModel):
    doc_id = db.insert(user.dict())
    return {"id": doc_id, "message": "تم إنشاء المستخدم"}

@app.get("/users/{user_id}")
async def read_user(user_id: int):
    user = db.get(doc_id=user_id)
    if not user:
        raise HTTPException(status_code=404, detail="المستخدم غير موجود")
    return user

@app.get("/users/")
async def list_users(age: int = None):
    if age:
        return db.search(User.age >= age)
    return db.all()

أفضل الممارسات والنصائح

  • اختيار التخزين المناسب: استخدم MemoryStorage للتطبيقات المؤقتة و JSONStorage للتخزين الدائم
  • إدارة الذاكرة: لملفات JSON الكبيرة، استخدم التخزين المؤقت (CachingMiddleware) لتحسين الأداء
  • النسخ الاحتياطي: انسخ ملف JSON بانتظام لتجنب فقدان البيانات
  • التحقق من البيانات: استخدم Pydantic أو مكتبات مشابهة للتحقق من صحة البيانات قبل الإدراج
  • الفهارس: أنشئ فهارس للحقول التي تبحث عنها بشكل متكرر لتحسين السرعة
  • التعامل مع الأخطاء: استخدم try-except للتعامل مع أخطاء الملفات أو البيانات التالفة

الخلاصة

TinyDB هو حل ممتاز للمشاريع الصغيرة والمتوسطة التي تحتاج إلى قاعدة بيانات بسيطة وسريعة بدون تعقيدات SQL. بفضل سهولة الاستخدام، التثبيت السريع، والتكامل المباشر مع أطر العمل الشائعة مثل Flask و FastAPI، يعتبر TinyDB خيارًا مثاليًا للنماذج الأولية، التطبيقات التعليمية، والأدوات الصغيرة. جربه اليوم في مشروعك القادم!

توصيات