FirestoreDataConverter interface

withConverter() ใช้ตัวแปลงเพื่อแปลงออบเจ็กต์ผู้ใช้ประเภท AppModelType เป็นข้อมูล Firestore ประเภท DbModelType

การใช้ตัวแปลงช่วยให้คุณระบุอาร์กิวเมนต์ประเภททั่วไปเมื่อจัดเก็บและเรียกออบเจ็กต์จาก Firestore

ในบริบทนี้ "AppModel" เป็นคลาสที่ใช้ในแอปพลิเคชันเพื่อรวมข้อมูลและฟังก์ชันการทำงานที่เกี่ยวข้องเข้าด้วยกัน คลาสดังกล่าวอาจมีพร็อพเพอร์ตี้ที่มีประเภทข้อมูลที่ซ้อนกันและซับซ้อน พร็อพเพอร์ตี้ที่ใช้สำหรับบันทึก พร็อพเพอร์ตี้ของประเภทที่ Firestore ไม่รองรับ (เช่น symbol และ bigint) รวมถึงฟังก์ชันตัวช่วยดำเนินการแบบผสม คลาสดังกล่าวไม่เหมาะสมและ/หรือสามารถจัดเก็บในฐานข้อมูล Firestore โดยจะต้องแปลงอินสแตนซ์ของคลาสดังกล่าวเป็น "ออบเจ็กต์ JavaScript เก่าธรรมดา" แทน (POJO) ที่มีพร็อพเพอร์ตี้พื้นฐานเท่านั้น ซึ่งอาจฝังอยู่ใน POJO อื่นๆ หรืออาร์เรย์ของ POJO อื่นๆ ในบริบทนี้ ประเภทนี้จะเรียกว่า "DbModel" และเป็นออบเจ็กต์ที่เหมาะสำหรับการคงอยู่ใน Firestore เพื่อความสะดวก แอปพลิเคชันสามารถใช้ FirestoreDataConverter และลงทะเบียนตัวแปลงด้วยออบเจ็กต์ Firestore เช่น DocumentReference หรือ Query เพื่อแปลง AppModel เป็น DbModel โดยอัตโนมัติเมื่อจัดเก็บใน Firestore และแปลง DbModel เป็น AppModel เมื่อเรียกข้อมูลจาก Firestore

ลายเซ็น:

export declare interface FirestoreDataConverter<AppModelType, DbModelType extends DocumentData = DocumentData> 

เมธอด

วิธีการ คำอธิบาย
fromFirestore(snapshot, ตัวเลือก) เรียกใช้โดย Firestore SDK เพื่อแปลงข้อมูล Firestore เป็นออบเจ็กต์ประเภท AppModelType คุณเข้าถึงข้อมูลได้โดยโทรไปที่ snapshot.data(options)โดยทั่วไปแล้ว ข้อมูลที่แสดงผลจาก snapshot.data() จะแคสต์ไปยัง DbModelType ได้ แต่วิธีนี้ไม่รับประกันเนื่องจาก Firestore ไม่ได้บังคับใช้สคีมาในฐานข้อมูล ตัวอย่างเช่น การเขียนจากแอปพลิเคชันเวอร์ชันก่อนหน้าหรือการเขียนจากไคลเอ็นต์อื่นที่ไม่ได้ใช้ตัวแปลงประเภทอาจมีข้อมูลที่เขียนด้วยพร็อพเพอร์ตี้และ/หรือประเภทพร็อพเพอร์ตี้ที่แตกต่างกัน การใช้งานนี้จะต้องเลือกว่าจะกู้คืนข้อมูลที่ไม่เป็นไปตามข้อกำหนดหรือแสดงข้อผิดพลาดอย่างค่อยเป็นค่อยไปหากต้องการลบล้างวิธีนี้ โปรดดู
toFirestore(modelObject) เรียกใช้โดย Firestore SDK เพื่อแปลงออบเจ็กต์โมเดลที่กำหนดเองของประเภท AppModelType เป็นออบเจ็กต์ JavaScript แบบธรรมดา (เหมาะสำหรับการเขียนในฐานข้อมูล Firestore โดยตรง) ประเภท DbModelType หากต้องการใช้ set() กับ merge และ mergeFields จะต้องกำหนด toFirestore() ด้วย PartialWithFieldValue<AppModelType>ประเภท WithFieldValue<T> ขยาย T เพื่ออนุญาตให้ใช้ FieldValues เช่น deleteField() เป็นค่าพร็อพเพอร์ตี้ได้ด้วย
toFirestore(modelObject, ตัวเลือก) เรียกใช้โดย Firestore SDK เพื่อแปลงออบเจ็กต์โมเดลที่กำหนดเองของประเภท AppModelType เป็นออบเจ็กต์ JavaScript แบบธรรมดา (เหมาะสำหรับการเขียนในฐานข้อมูล Firestore โดยตรง) ประเภท DbModelType ใช้กับ setDoc() และกับ merge:true หรือ mergeFieldsประเภท PartialWithFieldValue<T> ขยาย Partial<T> เพื่ออนุญาตให้ใช้ FieldValue เช่น arrayUnion() เป็นค่าพร็อพเพอร์ตี้ได้ นอกจากนี้ยังรองรับ Partial ที่ฝังไว้ด้วยการอนุญาตให้ละเว้นช่องที่ซ้อนกันได้ด้วย

FirestoreDataConverter.fromFirestore()

เรียกใช้โดย Firestore SDK เพื่อแปลงข้อมูล Firestore เป็นออบเจ็กต์ประเภท AppModelType คุณสามารถเข้าถึงข้อมูลได้โดยโทรไปที่หมายเลข snapshot.data(options)

โดยทั่วไปแล้ว ข้อมูลที่แสดงผลจาก snapshot.data() จะแคสต์ไปยัง DbModelType ได้ แต่วิธีนี้ไม่รับประกันเนื่องจาก Firestore ไม่ได้บังคับใช้สคีมาในฐานข้อมูล ตัวอย่างเช่น การเขียนจากแอปพลิเคชันเวอร์ชันก่อนหน้าหรือการเขียนจากไคลเอ็นต์อื่นที่ไม่ได้ใช้ตัวแปลงประเภทอาจมีข้อมูลที่เขียนด้วยพร็อพเพอร์ตี้และ/หรือประเภทพร็อพเพอร์ตี้ที่แตกต่างกัน การนำไปใช้จะต้องเลือกว่าจะกู้คืนข้อมูลที่ไม่สอดคล้องกับรูปแบบอย่างค่อยเป็นค่อยไปหรือเกิดข้อผิดพลาดขึ้น

หากต้องการลบล้างเมธอดนี้ โปรดดู

ลายเซ็น:

fromFirestore(snapshot: QueryDocumentSnapshot<DocumentData, DocumentData>, options?: SnapshotOptions): AppModelType;

พารามิเตอร์

พารามิเตอร์ ประเภท คำอธิบาย
สแนปชอต QueryDocumentSnapshot<DocumentData, DocumentData> QueryDocumentSnapshot ที่มีข้อมูลและข้อมูลเมตาของคุณ
ตัวเลือก ตัวเลือกสแนปชอต SnapshotOptions จากการโทรครั้งแรกถึง data()

การคืนสินค้า:

ประเภทรุ่นของแอป

FirestoreDataConverter.toFirestore()

เรียกใช้โดย Firestore SDK เพื่อแปลงออบเจ็กต์โมเดลที่กำหนดเองของประเภท AppModelType เป็นออบเจ็กต์ JavaScript ธรรมดา (เหมาะสำหรับการเขียนในฐานข้อมูล Firestore โดยตรง) ประเภท DbModelType หากต้องการใช้ set() กับ merge และ mergeFields คุณต้องกำหนด toFirestore() ด้วย PartialWithFieldValue<AppModelType>

ประเภท WithFieldValue<T> ขยาย T เพื่ออนุญาตให้ใช้ FieldValues เช่น deleteField() เป็นค่าพร็อพเพอร์ตี้ได้ด้วย

ลายเซ็น:

toFirestore(modelObject: WithFieldValue<AppModelType>): WithFieldValue<DbModelType>;

พารามิเตอร์

พารามิเตอร์ ประเภท คำอธิบาย
ModelObject WithFieldValue<AppModelType>

การคืนสินค้า:

WithFieldValue<DbModelType>

FirestoreDataConverter.toFirestore()

เรียกใช้โดย Firestore SDK เพื่อแปลงออบเจ็กต์โมเดลที่กำหนดเองของประเภท AppModelType เป็นออบเจ็กต์ JavaScript แบบธรรมดา (เหมาะสำหรับการเขียนในฐานข้อมูล Firestore โดยตรง) ประเภท DbModelType ใช้กับ setDoc() และกับ merge:true หรือ mergeFields

ประเภท PartialWithFieldValue<T> ขยาย Partial<T> เพื่ออนุญาตให้ใช้ FieldValues เช่น arrayUnion() เป็นค่าพร็อพเพอร์ตี้ นอกจากนี้ยังรองรับ Partial ที่ฝังไว้ด้วยการอนุญาตให้ละเว้นช่องที่ซ้อนกันได้ด้วย

ลายเซ็น:

toFirestore(modelObject: PartialWithFieldValue<AppModelType>, options: SetOptions): PartialWithFieldValue<DbModelType>;

พารามิเตอร์

พารามิเตอร์ ประเภท คำอธิบาย
ModelObject บางส่วนของWithFieldValue<AppModelType>
ตัวเลือก SetOptions

การคืนสินค้า:

partWithFieldValue<DbModelType>

ตัวอย่าง

ตัวอย่างแบบง่าย

const numberConverter = {
    toFirestore(value: WithFieldValue<number>) {
        return { value };
    },
    fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
        return snapshot.data(options).value as number;
    }
};

async function simpleDemo(db: Firestore): Promise<void> {
    const documentRef = doc(db, 'values/value123').withConverter(numberConverter);

    // converters are used with `setDoc`, `addDoc`, and `getDoc`
    await setDoc(documentRef, 42);
    const snapshot1 = await getDoc(documentRef);
    assertEqual(snapshot1.data(), 42);

    // converters are not used when writing data with `updateDoc`
    await updateDoc(documentRef, { value: 999 });
    const snapshot2 = await getDoc(documentRef);
    assertEqual(snapshot2.data(), 999);
}

ตัวอย่างขั้นสูง

// The Post class is a model that is used by our application.
// This class may have properties and methods that are specific
// to our application execution, which do not need to be persisted
// to Firestore.
class Post {
    constructor(
        readonly title: string,
        readonly author: string,
        readonly lastUpdatedMillis: number
    ) {}
    toString(): string {
        return `${this.title} by ${this.author}`;
    }
}

// The PostDbModel represents how we want our posts to be stored
// in Firestore. This DbModel has different properties (`ttl`,
// `aut`, and `lut`) from the Post class we use in our application.
interface PostDbModel {
    ttl: string;
    aut: { firstName: string; lastName: string };
    lut: Timestamp;
}

// The `PostConverter` implements `FirestoreDataConverter` and specifies
// how the Firestore SDK can convert `Post` objects to `PostDbModel`
// objects and vice versa.
class PostConverter implements FirestoreDataConverter<Post, PostDbModel> {
    toFirestore(post: WithFieldValue<Post>): WithFieldValue<PostDbModel> {
        return {
            ttl: post.title,
            aut: this._autFromAuthor(post.author),
            lut: this._lutFromLastUpdatedMillis(post.lastUpdatedMillis)
        };
    }

    fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions): Post {
        const data = snapshot.data(options) as PostDbModel;
        const author = `${data.aut.firstName} ${data.aut.lastName}`;
        return new Post(data.ttl, author, data.lut.toMillis());
    }

    _autFromAuthor(
        author: string | FieldValue
    ): { firstName: string; lastName: string } | FieldValue {
        if (typeof author !== 'string') {
            // `author` is a FieldValue, so just return it.
            return author;
        }
        const [firstName, lastName] = author.split(' ');
        return {firstName, lastName};
    }

    _lutFromLastUpdatedMillis(
        lastUpdatedMillis: number | FieldValue
    ): Timestamp | FieldValue {
        if (typeof lastUpdatedMillis !== 'number') {
            // `lastUpdatedMillis` must be a FieldValue, so just return it.
            return lastUpdatedMillis;
        }
        return Timestamp.fromMillis(lastUpdatedMillis);
    }
}

async function advancedDemo(db: Firestore): Promise<void> {
    // Create a `DocumentReference` with a `FirestoreDataConverter`.
    const documentRef = doc(db, 'posts/post123').withConverter(new PostConverter());

    // The `data` argument specified to `setDoc()` is type checked by the
    // TypeScript compiler to be compatible with `Post`. Since the `data`
    // argument is typed as `WithFieldValue<Post>` rather than just `Post`,
    // this allows properties of the `data` argument to also be special
    // Firestore values that perform server-side mutations, such as
    // `arrayRemove()`, `deleteField()`, and `serverTimestamp()`.
    await setDoc(documentRef, {
        title: 'My Life',
        author: 'Foo Bar',
        lastUpdatedMillis: serverTimestamp()
    });

    // The TypeScript compiler will fail to compile if the `data` argument to
    // `setDoc()` is _not_ compatible with `WithFieldValue<Post>`. This
    // type checking prevents the caller from specifying objects with incorrect
    // properties or property values.
    // @ts-expect-error "Argument of type { ttl: string; } is not assignable
    // to parameter of type WithFieldValue<Post>"
    await setDoc(documentRef, { ttl: 'The Title' });

    // When retrieving a document with `getDoc()` the `DocumentSnapshot`
    // object's `data()` method returns a `Post`, rather than a generic object,
    // which would have been returned if the `DocumentReference` did _not_ have a
    // `FirestoreDataConverter` attached to it.
    const snapshot1: DocumentSnapshot<Post> = await getDoc(documentRef);
    const post1: Post = snapshot1.data()!;
    if (post1) {
        assertEqual(post1.title, 'My Life');
        assertEqual(post1.author, 'Foo Bar');
    }

    // The `data` argument specified to `updateDoc()` is type checked by the
    // TypeScript compiler to be compatible with `PostDbModel`. Note that
    // unlike `setDoc()`, whose `data` argument must be compatible with `Post`,
    // the `data` argument to `updateDoc()` must be compatible with
    // `PostDbModel`. Similar to `setDoc()`, since the `data` argument is typed
    // as `WithFieldValue<PostDbModel>` rather than just `PostDbModel`, this
    // allows properties of the `data` argument to also be those special
    // Firestore values, like `arrayRemove()`, `deleteField()`, and
    // `serverTimestamp()`.
    await updateDoc(documentRef, {
        'aut.firstName': 'NewFirstName',
        lut: serverTimestamp()
    });

    // The TypeScript compiler will fail to compile if the `data` argument to
    // `updateDoc()` is _not_ compatible with `WithFieldValue<PostDbModel>`.
    // This type checking prevents the caller from specifying objects with
    // incorrect properties or property values.
    // @ts-expect-error "Argument of type { title: string; } is not assignable
    // to parameter of type WithFieldValue<PostDbModel>"
    await updateDoc(documentRef, { title: 'New Title' });
    const snapshot2: DocumentSnapshot<Post> = await getDoc(documentRef);
    const post2: Post = snapshot2.data()!;
    if (post2) {
        assertEqual(post2.title, 'My Life');
        assertEqual(post2.author, 'NewFirstName Bar');
    }
}