الاستعلام عن البيانات

تعرّف على كيفية الاستعلام عن البيانات وتصفيتها من قاعدة بياناتك.

ملاحظة: هذا محتوى تجريبي/مؤقت لأغراض العرض التوضيحي.

استعلم عن البيانات وصفِّها بكفاءة باستخدام أداة بناء الاستعلامات في Supabase.

الاستعلامات الأساسية

تحديد الكل

const { data, error } = await client
  .from('projects')
  .select('*');

تحديد أعمدة معيّنة

const { data, error } = await client
  .from('projects')
  .select('id, name, created_at');

التحديد مع البيانات المرتبطة

const { data, error } = await client
  .from('projects')
  .select(`
    id,
    name,
    account:accounts(id, name),
    tasks(id, title, completed)
  `);

التصفية

يساوي

const { data } = await client
  .from('projects')
  .select('*')
  .eq('status', 'active');

لا يساوي

const { data } = await client
  .from('projects')
  .select('*')
  .neq('status', 'deleted');

أكبر من / أصغر من

const { data } = await client
  .from('projects')
  .select('*')
  .gt('created_at', '2024-01-01')
  .lt('budget', 10000);

ضمن مصفوفة

const { data } = await client
  .from('projects')
  .select('*')
  .in('status', ['active', 'pending']);

Like (مطابقة الأنماط)

const { data } = await client
  .from('projects')
  .select('*')
  .like('name', '%website%');

البحث في النص الكامل

const { data } = await client
  .from('projects')
  .select('*')
  .textSearch('description', 'design & development');

الترتيب

الترتيب حسب عمود

const { data } = await client
  .from('projects')
  .select('*')
  .order('created_at', { ascending: false });

الترتيب حسب أعمدة متعددة

const { data } = await client
  .from('projects')
  .select('*')
  .order('status')
  .order('created_at', { ascending: false });

ترقيم الصفحات

الحدّ الأقصى (Limit)

const { data } = await client
  .from('projects')
  .select('*')
  .limit(10);

النطاق (الإزاحة)

const page = 2;
const pageSize = 10;
const from = (page - 1) * pageSize;
const to = from + pageSize - 1;

const { data, count } = await client
  .from('projects')
  .select('*', { count: 'exact' })
  .range(from, to);

التجميعات

العدّ

const { count } = await client
  .from('projects')
  .select('*', { count: 'exact', head: true });

العدّ مع عوامل التصفية

const { count } = await client
  .from('projects')
  .select('*', { count: 'exact', head: true })
  .eq('status', 'active');

الاستعلامات المتقدمة

عوامل تصفية متعددة

const { data } = await client
  .from('projects')
  .select('*')
  .eq('account_id', accountId)
  .eq('status', 'active')
  .gte('created_at', startDate)
  .lte('created_at', endDate)
  .order('created_at', { ascending: false })
  .limit(20);

شروط OR

const { data } = await client
  .from('projects')
  .select('*')
  .or('status.eq.active,status.eq.pending');

شروط OR المتداخلة

const { data } = await client
  .from('projects')
  .select('*')
  .or('and(status.eq.active,priority.eq.high),status.eq.urgent');

عمليات الربط (Joins)

الربط الداخلي (Inner Join)

const { data } = await client
  .from('projects')
  .select(`
    *,
    account:accounts!inner(
      id,
      name
    )
  `)
  .eq('account.name', 'Acme Corp');

الربط الأيسر (Left Join)

const { data } = await client
  .from('projects')
  .select(`
    *,
    tasks(*)
  `);

التعامل مع القيم الفارغة

القيمة فارغة (Is Null)

const { data } = await client
  .from('projects')
  .select('*')
  .is('completed_at', null);

القيمة غير فارغة (Not Null)

const { data} = await client
  .from('projects')
  .select('*')
  .not('completed_at', 'is', null);

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

إدراج سجل واحد

const { data, error } = await client
  .from('projects')
  .insert({
    name: 'New Project',
    account_id: accountId,
    status: 'active',
  })
  .select()
  .single();

إدراج سجلات متعددة

const { data, error } = await client
  .from('projects')
  .insert([
    { name: 'Project 1', account_id: accountId },
    { name: 'Project 2', account_id: accountId },
  ])
  .select();

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

التحديث مع عامل تصفية

const { data, error } = await client
  .from('projects')
  .update({ status: 'completed' })
  .eq('id', projectId)
  .select()
  .single();

تحديث صفوف متعددة

const { data, error } = await client
  .from('projects')
  .update({ status: 'archived' })
  .eq('account_id', accountId)
  .lt('updated_at', oldDate);

حذف البيانات

الحذف مع عامل تصفية

const { error } = await client
  .from('projects')
  .delete()
  .eq('id', projectId);

حذف سجلات متعددة

const { error } = await client
  .from('projects')
  .delete()
  .in('id', projectIds);

الإدراج أو التحديث (Upsert)

إدراج أو تحديث

const { data, error } = await client
  .from('projects')
  .upsert({
    id: projectId,
    name: 'Updated Name',
    status: 'active',
  })
  .select()
  .single();

RPC (الإجراءات المخزّنة)

استدعاء دالة قاعدة البيانات

const { data, error } = await client
  .rpc('get_user_projects', {
    user_id: userId,
  });

مع معاملات معقّدة

const { data, error } = await client
  .rpc('search_projects', {
    search_term: 'design',
    account_ids: [1, 2, 3],
    min_budget: 5000,
  });

معالجة الأخطاء

معالجة الأخطاء الأساسية

const { data, error } = await client
  .from('projects')
  .select('*');

if (error) {
  console.error('Error fetching projects:', error.message);
  throw error;
}

return data;

معالجة الأخطاء مع الأنواع

import { PostgrestError } from '@supabase/supabase-js';

function handleDatabaseError(error: PostgrestError) {
  switch (error.code) {
    case '23505': // unique_violation
      throw new Error('A project with this name already exists');
    case '23503': // foreign_key_violation
      throw new Error('Invalid account reference');
    default:
      throw new Error('Database error: ' + error.message);
  }
}

أنواع TypeScript

الأنواع المُولَّدة

import { Database } from '~/types/database.types';

type Project = Database['public']['Tables']['projects']['Row'];
type ProjectInsert = Database['public']['Tables']['projects']['Insert'];
type ProjectUpdate = Database['public']['Tables']['projects']['Update'];

الاستعلامات ذات الأنواع المحدّدة

const { data } = await client
  .from('projects')
  .select('*')
  .returns<Project[]>();

نصائح لتحسين الأداء

  1. حدّد الأعمدة المطلوبة فقط - لا تستخدم select('*') دون داعٍ
  2. استخدم الفهارس - أنشئ فهارس على الأعمدة التي يكثر التصفية بها
  3. قيّد النتائج - قسّم مجموعات البيانات الكبيرة إلى صفحات دائمًا
  4. تجنّب استعلامات N+1 - استخدم عمليات الربط بدلًا من الاستعلامات المتعددة
  5. استخدم RPC للاستعلامات المعقّدة - انقل المنطق إلى قاعدة البيانات
  6. استخدم التخزين المؤقت متى أمكن - استخدم React Query أو أداة مماثلة
  7. حلّل أداء الاستعلامات - استخدم EXPLAIN ANALYZE في SQL

أفضل الممارسات

  1. تعامل مع الأخطاء دائمًا - تحقّق من استجابات الأخطاء
  2. تحقّق من صحة المدخلات - استخدم Zod أو أداة مماثلة
  3. استخدم TypeScript - ولِّد الأنواع واستخدمها
  4. تسمية متّسقة - اتّبع اصطلاحات تسمية قاعدة البيانات
  5. وثّق الاستعلامات المعقّدة - أضف التعليقات
  6. اختبر الاستعلامات - اكتب اختبارات وحدة لعمليات قاعدة البيانات
  7. راقب الأداء - تتبّع الاستعلامات البطيئة