React Native Academy · บทเรียน

การอ่านและเขียนเอกสาร Firestore

เพิ่ม อ่าน แก้ไข และลบเอกสารในคอลเลกชัน Firestore โดยใช้โมดูล Firestore จัดโครงสร้างข้อมูลด้วยคอลเลกชันย่อย และใช้กฎความปลอดภัย

บทเรียน 3 จาก 413 ขั้นตอน

การอ่านและเขียนเอกสาร Firestore เป็นบทเรียน React Native Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน React Native Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ

Firestore Data Model

Cloud Firestore is a NoSQL document database. Data is organized in collections (like folders) that contain documents (like JSON files). Each document has a unique ID and a set of key-value fields. Documents can contain sub-collections for nested data.

For example, a posts collection contains many post documents, each with fields like title, content, and userId. A post document can have a nested comments sub-collection for its replies. This model scales differently from SQL — think about access patterns first, then model data accordingly.

Getting a Collection Reference

Access a Firestore collection using firestore().collection('collection-name'). This returns a CollectionReference that you use to read documents, add new ones, or listen for changes. Collection references are lightweight and do not trigger any network calls on their own.

To reference a specific document within a collection, chain .doc('document-id'). If you want Firestore to generate a random ID, omit the argument when creating a new document with .add().

import firestore from '@react-native-firebase/firestore';

// Reference to the 'posts' collection
const postsRef = firestore().collection('posts');

// Reference to a specific post document
const postRef = firestore().collection('posts').doc('post-id-123');

// Reference to a sub-collection
const commentsRef = firestore()
  .collection('posts')
  .doc('post-id-123')
  .collection('comments');

Adding a Document

Use .add(data) on a collection reference to create a new document with a Firestore-generated ID. Use .doc(id).set(data) to create or overwrite a document with a specific ID.

The firestore.FieldValue.serverTimestamp() utility sets a timestamp on the server side, ensuring all clients see the same creation time regardless of device clock differences. Always use server timestamps for createdAt and updatedAt fields.

// Add with auto-generated ID
const newPost = await firestore().collection('posts').add({
  title: 'Hello Firestore',
  content: 'My first post!',
  userId: auth().currentUser?.uid,
  createdAt: firestore.FieldValue.serverTimestamp(),
});
console.log('New post ID:', newPost.id);

// Set with specific ID
await firestore().collection('users').doc(userId).set({
  displayName: 'Alice',
  email: 'alice@example.com',
  createdAt: firestore.FieldValue.serverTimestamp(),
});

Reading a Single Document

Call .get() on a DocumentReference to fetch it once. The result is a DocumentSnapshot. Check snapshot.exists before reading data — if the document was never created, exists is false and snapshot.data() returns undefined.

The snapshot.data() method returns a plain JavaScript object with all the document's fields. The document ID is accessed via snapshot.id, not via the data object.

async function getPost(postId: string) {
  const snapshot = await firestore().collection('posts').doc(postId).get();

  if (!snapshot.exists) {
    console.log('Post not found');
    return null;
  }

  const data = snapshot.data();
  return { id: snapshot.id, ...data };
}

Querying a Collection

Use .where(field, operator, value) to filter documents, .orderBy(field, 'desc') to sort, and .limit(n) to cap results. Chain multiple .where calls for AND logic. Call .get() to execute the query and receive a QuerySnapshot.

Iterate the results with snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })). Firestore requires composite indexes for queries that filter and order by different fields — Firestore will print a link in the logs to create the required index if one is missing.

async function getUserPosts(userId: string) {
  const snapshot = await firestore()
    .collection('posts')
    .where('userId', '==', userId)
    .orderBy('createdAt', 'desc')
    .limit(20)
    .get();

  return snapshot.docs.map((doc) => ({
    id: doc.id,
    ...doc.data(),
  }));
}

Updating a Document

Use .update() to modify specific fields without overwriting the entire document. Only the fields you specify are changed — all other fields remain intact. This is different from .set(), which replaces the whole document by default.

Use firestore.FieldValue.increment(n) to atomically increment a numeric field without reading it first. Use firestore.FieldValue.arrayUnion(item) and arrayRemove(item) to add or remove items from array fields atomically.

// Update specific fields
await firestore().collection('posts').doc(postId).update({
  title: 'Updated Title',
  updatedAt: firestore.FieldValue.serverTimestamp(),
});

// Atomic increment (e.g., a like counter)
await firestore().collection('posts').doc(postId).update({
  likesCount: firestore.FieldValue.increment(1),
});

// Add a tag to an array without duplicates
await firestore().collection('posts').doc(postId).update({
  tags: firestore.FieldValue.arrayUnion('react-native'),
});

Deleting a Document

Call .delete() on a DocumentReference to remove the document. This only deletes the document itself, not any sub-collections it may contain. To delete sub-collections, you must recursively delete each document in them — Firestore does not cascade deletes automatically.

To delete a single field from a document without deleting the document itself, use firestore.FieldValue.delete() in an .update() call with the field name as the key.

// Delete a document
await firestore().collection('posts').doc(postId).delete();

// Delete a specific field within a document
await firestore().collection('users').doc(userId).update({
  temporaryData: firestore.FieldValue.delete(),
});

Batch Writes

A batch write lets you execute multiple create, update, and delete operations as a single atomic transaction. Either all operations succeed or none of them do. This is essential for operations that must stay consistent, like transferring credits between users.

Create a batch with firestore().batch(), add operations with batch.set(), batch.update(), and batch.delete(), then commit with batch.commit(). Batches support up to 500 operations at once.

const batch = firestore().batch();

// Create a post
const postRef = firestore().collection('posts').doc();
batch.set(postRef, { title: 'Batch Post', userId });

// Increment user post count
const userRef = firestore().collection('users').doc(userId);
batch.update(userRef, { postCount: firestore.FieldValue.increment(1) });

// Execute both operations atomically
await batch.commit();
console.log('Batch write complete');

Firestore Security Rules

Firestore Security Rules control who can read and write documents. Rules are defined in the Firebase console under Firestore > Rules using a declarative DSL. The request.auth object gives you access to the authenticated user's UID inside rule expressions.

Always start with deny all as the default and explicitly allow only what is needed. A rule that allows a user to write only to their own user document looks like: allow write: if request.auth.uid == userId;

// firestore.rules
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Deny all by default
    match /{document=**} {
      allow read, write: if false;
    }

    // Users can read/write their own profile
    match /users/{userId} {
      allow read: if request.auth != null;
      allow write: if request.auth.uid == userId;
    }

    // Posts are public to read, but only the author can write
    match /posts/{postId} {
      allow read: if true;
      allow create: if request.auth != null;
      allow update, delete: if request.auth.uid == resource.data.userId;
    }
  }
}

Merging Data with set and merge

By default, .set(data) overwrites the entire document. To merge new data with existing fields instead of overwriting, pass { merge: true } as the second argument.

This is useful when you want to create a document if it does not exist, or update it if it does — without knowing all its current fields. It is a more flexible alternative to .update(), which throws an error if the document does not exist.

// set WITHOUT merge: overwrites the entire document
await firestore().collection('profiles').doc(userId).set({
  displayName: 'Alice',
});
// Existing fields like 'bio' would be DELETED

// set WITH merge: only updates specified fields
await firestore().collection('profiles').doc(userId).set({
  displayName: 'Alice',
}, { merge: true });
// Existing fields like 'bio' are preserved

Handling Offline Writes

Firestore has a built-in local cache and queues writes when the device is offline. When connectivity returns, Firestore automatically sends the queued writes to the server in order. From the app's perspective, writes succeed immediately — the UI updates without waiting for the server.

This means your React Native app can remain fully functional with no internet connection for reads and writes, and Firestore handles syncing transparently. You can detect the online/offline state using a NetInfo listener if you need to show connectivity status in the UI.

// Firestore enables offline persistence by default on mobile.
// This write succeeds even without internet connection:
await firestore().collection('drafts').doc(draftId).set({
  content: 'Work in progress...',
  savedAt: firestore.FieldValue.serverTimestamp(),
});
// When connectivity returns, Firestore syncs automatically.
// No additional code required.

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: the Firestore collection/document data model, how to add, read, update, and delete documents using the React Native Firebase SDK, and how batch writes ensure atomic multi-document operations. Next up we add real-time listeners to receive live Firestore updates and configure offline persistence.

เริ่มต้นได้ฟรี

เรียนรู้ JavaScript ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
30
บทเรียน
120

คำถามที่พบบ่อย

บทเรียน “การอ่านและเขียนเอกสาร Firestore” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การอ่านและเขียนเอกสาร Firestore” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส React Native Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การอ่านและเขียนเอกสาร Firestore”

เพิ่ม อ่าน แก้ไข และลบเอกสารในคอลเลกชัน Firestore โดยใช้โมดูล Firestore จัดโครงสร้างข้อมูลด้วยคอลเลกชันย่อย และใช้กฎความปลอดภัย คุณปฏิบัติ React Native Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน React Native Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน React Native Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การอ่านและเขียนเอกสาร Firestore” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน React Native Academy นี้ได้ไหม

ได้ บทเรียน React Native Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การเชื่อม React Native Firebase กับโปรเจกต์
  2. การยืนยันตัวตนด้วยอีเมลและโทรศัพท์ผ่าน Firebase
  3. การอ่านและเขียนเอกสาร Firestore
  4. ตัวรับฟังแบบเรียลไทม์และการคงข้อมูลออฟไลน์
← กลับไปที่ React Native Academy