FirestoreDataConverter interface

المحول الذي يستخدمه withConverter() لتحويل كائنات المستخدم من النوع AppModelType إلى بيانات Firestore من النوع DbModelType.

يتيح لك استخدام المحوّل تحديد وسيطات النوع العامة عند تخزين الكائنات واستردادها من Firestore.

في هذا السياق، لا يعرف "AppModel" هي فئة تستخدم في أحد التطبيقات لتجميع المعلومات والوظائف ذات الصلة معًا. ويمكن أن تتضمّن هذه الفئة مثلاً سمات ذات أنواع بيانات معقدة ومدمجة وسمات مستخدَمة للحفظ وسمات من الأنواع غير المتوافقة مع Firestore (مثل symbol وbigint) ودوال مساعدة تؤدي عمليات مركّبة. هذه الفئات ليست مناسبة و/أو من الممكن تخزينها في قاعدة بيانات Firestore. بدلاً من ذلك، يجب تحويل مثيلات هذه الفئات إلى "كائنات JavaScript قديمة عادية" تتضمّن هذه الدالة خصائص أولية بشكل حصري، يُحتمل أن تكون مدمجة داخل POJO أو مصفوفات أخرى من عناصر POJO. وفي هذا السياق، يشار إلى هذا النوع باسم "نموذج قاعدة البيانات" وستكون كائنًا مناسبًا للاحتفاظ بها في Firestore. للتيسير، يمكن للتطبيقات تنفيذ FirestoreDataConverter وتسجيل محوّل الملفات باستخدام عناصر Firestore، مثل DocumentReference أو Query، لتحويل AppModel تلقائيًا إلى DbModel عند تخزينه في Firestore وتحويل DbModel إلى AppModel عند استرداد البيانات من Firestore.

Signature:

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

الطُرق

الطريقة الوصف
fromFirestore(لقطة، خيارات) يتم استدعاء هذه الحزمة بواسطة 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, options) يتم استدعاء هذه الواجهة بواسطة Firestore SDK لتحويل كائن نموذج مخصّص من النوع AppModelType إلى كائن JavaScript عادي (مناسب للكتابة مباشرةً إلى قاعدة بيانات Firestore) من النوع DbModelType. تُستخدم مع setDoc() ومع merge:true أو mergeFields.يمتد النوع PartialWithFieldValue<T> إلى Partial<T> للسماح باستخدام قيم الحقل (FieldValues)، مثل arrayUnion() كقيم سمات. وتتيح أيضًا استخدام Partial المُدمَجة من خلال السماح بحذف الحقول المُدمَجة.

FirestoreDataConverter.fromFirestore()

يتم استدعاء هذه الحزمة بواسطة Firestore SDK لتحويل بيانات Firestore إلى كائن من النوع AppModelType. يمكنك الوصول إلى بياناتك من خلال الاتصال على الرقم: snapshot.data(options).

بشكل عام، يمكن تحويل البيانات التي يتم عرضها من خلال snapshot.data() إلى DbModelType. ومع ذلك، لا يمكن ضمان ذلك لأن Firestore لا يفرض مخططًا على قاعدة البيانات. على سبيل المثال، يمكن أن تكون الكتابة من إصدار سابق من التطبيق أو الكتابة من برنامج آخر لا يستخدم محوّل النوع قد تتضمن بيانات مكتوبة بخصائص و/أو أنواع خصائص مختلفة. سيحتاج التنفيذ إلى اختيار ما إذا كان سيتم الاسترداد بشكل سلس من البيانات غير المطابقة أو عرض خطأ.

لتجاوز هذه الطريقة، راجع .

Signature:

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

المَعلمات

المعلمة النوع الوصف
لقطة QueryDocumentSnapshot<DocumentData، وDocumentData> ملف QueryDocumentSnapshot يتضمّن بياناتك وبياناتك الوصفية
خيارات SnapshotOptions SnapshotOptions من المكالمة الأولية إلى data().

المرتجعات:

نوع نموذج التطبيق

FirestoreDataConverter.toFirestore()

يتم استدعاء هذه الحزمة بواسطة Firestore SDK لتحويل كائن نموذج مخصّص من النوع AppModelType إلى كائن JavaScript عادي (مناسب للكتابة مباشرةً إلى قاعدة بيانات Firestore) من النوع DbModelType. لاستخدام set() مع merge وmergeFields، يجب تحديد toFirestore() من خلال PartialWithFieldValue<AppModelType>.

يمتد النوع WithFieldValue<T> إلى T للسماح أيضًا باستخدام قيم الحقل (FieldValues)، مثل deleteField() كقيم سمات.

Signature:

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

المَعلمات

المعلمة النوع الوصف
كائن النموذج WithFieldValue <AppModelType>

المرتجعات:

WithFieldValue <DbModelType>

FirestoreDataConverter.toFirestore()

يتم استدعاء هذه الحزمة بواسطة Firestore SDK لتحويل كائن نموذج مخصّص من النوع AppModelType إلى كائن JavaScript عادي (مناسب للكتابة مباشرةً إلى قاعدة بيانات Firestore) من النوع DbModelType. تُستخدم مع setDoc()، ومع merge:true أو mergeFields.

يعمل النوع PartialWithFieldValue<T> على توسيع Partial<T> للسماح باستخدام قيم الحقل (FieldValues)، مثل arrayUnion() كقيم سمات. وتتيح أيضًا استخدام Partial المُدمَجة من خلال السماح بحذف الحقول المُدمَجة.

Signature:

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

المَعلمات

المعلمة النوع الوصف
كائن النموذج Partial withFieldValue <AppModelType>
خيارات SetOptions

المرتجعات:

PartialWithFieldValue <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');
    }
}