أساسيات Cloud Firestore
اقرأ البيانات الآنية واكتبها
أساسيات Cloud Firestore درس مجاني في Android Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Android Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Android Academy 4 دروس في المجموع.
ما هي Cloud Firestore؟
Cloud Firestore هي قاعدة بيانات NoSQL مرنة وقابلة للتوسع من Firebase. تخزّن البيانات على شكل مستندات مجمّعة ضمن مجموعات.
- المستند هو مجموعة من الحقول ذات المفتاح والقيمة (مثل كائن JSON).
- المجموعة هي حاوية للمستندات.
- يمكن أن تحتوي المستندات على مجموعات فرعية، لتشكّل شجرة.
توفر Firestore أيضًا تحديثات آنية وتعمل دون اتصال مباشرةً.
الحصول على نسخة Firestore
يمكنك الوصول إلى قاعدة البيانات من خلال Firebase.firestore. ومن هناك تصل إلى مجموعة باستخدام collection("name") وإلى مستند محدد باستخدام document("id").
إنشاء المراجع منخفض التكلفة — فهي تصف موقعًا، لا البيانات نفسها.
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
val db = Firebase.firestore
val usersRef = db.collection("users")
val oneUser = db.collection("users").document("abc123")نمذجة البيانات
تتوافق Firestore بسلاسة مع فئات البيانات في Kotlin. وتصبح كل خاصية حقلًا في المستند.
زوّد الفئة بـ منشئ بلا معاملات (وتتكفل القيم الافتراضية بذلك) حتى تتمكن Firestore من إلغاء تسلسل المستندات وإعادتها إلى كائنات.
data class Note(
val title: String = "",
val body: String = "",
val done: Boolean = false,
val createdAt: Long = 0L
)كتابة مستند
استخدم set لإنشاء مستند أو استبداله. دع Firestore تنشئ معرّفًا باستخدام add، أو اختر معرّفك بنفسك باستخدام document(id).set(...).
تُرجع هذه الاستدعاءات كائنات Tasks؛ ومع coroutines يمكنك استخدام await() عليها.
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await
suspend fun addNote(note: Note): String {
val ref = Firebase.firestore
.collection("notes")
.add(note) // auto-generated ID
.await()
return ref.id
}قراءة مستند
تجلب get() مستندًا مرة واحدة. حوّله إلى فئة البيانات باستخدام toObject(Note::class.java).
تحقق دائمًا من exists() — إذ يُرجع المرجع إلى مستند مفقود لقطةً لا يكون المستند فيها موجودًا ببساطة.
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await
suspend fun loadNote(id: String): Note? {
val snapshot = Firebase.firestore
.collection("notes")
.document(id)
.get()
.await()
return if (snapshot.exists()) snapshot.toObject(Note::class.java) else null
}التحديث والحذف
يغيّر update حقولًا محددة دون المساس ببقية المستند. أما delete فيحذف المستند بالكامل.
استخدم set(..., SetOptions.merge()) إذا أردت كتابة جزئية تنشئ المستند أيضًا عند عدم وجوده.
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await
suspend fun markDone(id: String) {
Firebase.firestore.collection("notes").document(id)
.update("done", true)
.await()
}
suspend fun removeNote(id: String) {
Firebase.firestore.collection("notes").document(id)
.delete()
.await()
}الاستعلام عن مجموعة
أنشئ الاستعلامات بضم عوامل التصفية: whereEqualTo وwhereGreaterThan وorderBy وlimit وغير ذلك.
يُرجع الاستعلام كائن QuerySnapshot؛ كرّر على مستنداته لتحويل كل مستند إلى نموذجك.
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await
suspend fun pendingNotes(): List<Note> {
val snap = Firebase.firestore.collection("notes")
.whereEqualTo("done", false)
.orderBy("createdAt")
.limit(20)
.get()
.await()
return snap.documents.mapNotNull { it.toObject(Note::class.java) }
}مستمعو البيانات الآنية
تكمن قوة Firestore في البيانات الآنية. يقدّم addSnapshotListener البيانات الحالية فورًا، ثم يرسل كل تغيير تلقائيًا.
ويُرجع كائن ListenerRegistration — استدعِ remove() عند الانتهاء لإيقاف تلقي التحديثات.
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
val registration = Firebase.firestore.collection("notes")
.whereEqualTo("done", false)
.addSnapshotListener { snapshot, error ->
if (error != null || snapshot == null) return@addSnapshotListener
val notes = snapshot.toObjects(Note::class.java)
println("Now have ${notes.size} pending notes")
}
// Later: registration.remove()البيانات الآنية كـ Flow
من الأساليب الاصطلاحية في Compose إتاحة بيانات Firestore على شكل Kotlin Flow. يربط callbackFlow استدعاء المستمع بـ flow، بينما يزيل awaitClose المستمع عند توقف الجمع.
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
fun notesFlow(): Flow<List<Note>> = callbackFlow {
val reg = Firebase.firestore.collection("notes")
.addSnapshotListener { snap, err ->
if (err == null && snap != null) {
trySend(snap.toObjects(Note::class.java))
}
}
awaitClose { reg.remove() }
}عرض البيانات في Compose
اجمع flow باستخدام collectAsStateWithLifecycle() واعرضه في LazyColumn. ستتحدّث القائمة تلقائيًا كلما تغيّرت Firestore — دون تحديث يدوي.
@Composable
fun NotesScreen(viewModel: NotesViewModel) {
val notes by viewModel.notes.collectAsStateWithLifecycle()
LazyColumn {
items(notes) { note ->
ListItem(
headlineContent = { Text(note.title) },
supportingContent = { Text(note.body) }
)
}
}
}أهمية قواعد الأمان
تكون Firestore مقفلة افتراضيًا. تحدد قواعد الأمان من يمكنه قراءة كل مسار أو الكتابة إليه — إذ تعمل على الخادم ولا يمكن للعميل تجاوزها.
من القواعد الشائعة: لا يجوز للمستخدم الوصول إلا إلى بياناته الخاصة، والمحددة بواسطة uid الخاص بالمصادقة.
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{document=**} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
}
}تحقق سريع
تريد قائمة Compose تتحدّث فورًا كلما تغيّرت بيانات Firestore الأساسية، دون تحديث يدوي. ما واجهة برمجة التطبيقات التي تستخدمها؟
مراجعة: Firestore
يمكنك الآن تخزين البيانات ومزامنتها باستخدام Cloud Firestore:
- توجد البيانات على شكل مستندات داخل مجموعات؛ ونمذجها باستخدام فئات بيانات Kotlin.
- اكتب باستخدام
add/set، واقرأ باستخدامget، وغيّر باستخدامupdate/delete. - أجرِ الاستعلامات باستخدام
whereEqualToوorderByوlimit. - استخدم
addSnapshotListener(أوcallbackFlow) لإنشاء واجهة مستخدم آنية. - احمِ البيانات باستخدام قواعد الأمان المعتمدة على
request.auth.uid.
التالي: الوصول إلى المستخدمين عندما يكون التطبيق مغلقًا باستخدام Cloud Messaging.
الأسئلة الشائعة
هل درس «أساسيات Cloud Firestore» مجاني؟
نعم — نص درس «أساسيات Cloud Firestore» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Android Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Android Academy 4 دروس في المجموع.
ماذا ستتعلم في «أساسيات Cloud Firestore»؟
اقرأ البيانات الآنية واكتبها تتمرن على Android Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Android Academy؟
لا تُشترط خبرة سابقة. Android Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «أساسيات Cloud Firestore»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Android Academy هذا؟
نعم. كل درس في Android Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- إعداد Firebase
- المصادقة باستخدام Firebase
- أساسيات Cloud Firestore
- الدفع باستخدام Cloud Messaging