FirestoreDataConverter interface

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

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

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

إمضاء:

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

طُرق

طريقة وصف
منFirestore (لقطة، خيارات) يتم استدعاؤه بواسطة 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> للسماح باستخدام FieldValues ​​مثل arrayUnion() كقيم خصائص. كما أنه يدعم Partial المتداخل عن طريق السماح بحذف الحقول المتداخلة.

FirestoreDataConverter.fromFirestore()

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

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

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

إمضاء:

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

حدود

معامل يكتب وصف
لمحة QueryDocumentSnapshot < بيانات الوثيقة ، بيانات الوثيقة > QueryDocumentSnapshot الذي يحتوي على بياناتك وبيانات التعريف الخاصة بك.
خيارات خيارات اللقطة SnapshotOptions من الاستدعاء الأولي إلى data() .

عائدات:

AppModelType

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 مع قيمة الحقل <AppModelType>

عائدات:

مع قيمة الحقل <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 PartialWithFieldValue <AppModelType>
خيارات خيارات الضبط

عائدات:

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