Хотите безопасно получать данные из cloud-firestore в flutter, даже если запрошенное поле отсутствует в документе?

# #google-cloud-firestore #flutter-web

Вопрос:

У меня в коллекции пользователей есть несколько документов, в которых еще нет всех возможных полей.

Получение моих пользователей из Firestore (с помощью cloud_firestore: ^2.2.1) выдает ошибку.

 Bad state: field does not exist within the DocumentSnapshotPlatform
 

Я спровоцировал эту ошибку внутри блока try-catch.

 ...
  factory User.fromFirestore(DocumentSnapshot doc) {

    try {
      print(doc.get('some-missing-field'));
    } catch (e) {
      print(e);
    }

    return User(
      id: doc.id,
      email: doc.get('email') ?? '',
      displayName: doc.get('displayName') ?? '',
      fieldfoo: doc.get('fieldfoo') ?? '',
      fieldbar: doc.get('fieldbar') ?? [],
    );
  }
}
...
 

В какой момент я пропустил, чтобы сказать flutter, что он должен заполнить недостающие поля фиктивными значениями?

Существуют ли какие-либо лучшие практики? Сталкивался ли кто-нибудь с подобной проблемой?

Ответ №1:

Если вы используете нулевую безопасность, вы можете получить ее следующим образом:

 Map<String, dynamic>? data = docSnapshot.data();
var value = data?['field_name'] ?? '';
 

Комментарии:

1. Возражать? пакет данных (): cloud_firestore/cloud_firestore. dart Содержит все данные этого снимка документа. Значение типа «Объект?» не может быть присвоено переменной типа » Карта<Строка, динамическая>?». Попробуйте изменить тип переменной или присвоить правому типу значение » Сопоставить<Строка, динамическая>?». Похоже, что мой снимок имеет тип <Объект?>, но почему?

2. Можете ли вы показать нам скриншот вашей базы данных в том месте, где вы получаете данные.

Ответ №2:

Решение состояло в том, чтобы сопоставлять DocumentSnapshot с <строкой, динамической> при каждом появлении.

Полученная функция выглядит следующим образом

 ...
  factory User.fromFirestore(DocumentSnapshot<Map<String, dynamic>> doc) {
    Map data = doc.data()!;
    return User(
      id: doc.id,
      email: data['email'] ?? '',
      displayName: data['displayName'] ?? '',
      language: data['language'] ?? '',
      affiliatedOrganizations: data['affiliatedOrganizations'] ?? [],
      isAdmin: data['isAdmin'] ?? false,
      isEditor: data['isEditor'] ?? false,
    );
  }
...
 

Этот «запрос» приводит ко всем пользователям.

   final Stream<QuerySnapshot<Map<String, dynamic>>> _usersStream =
      DatabaseService().usersCollection.snapshots();
  
 

Когда я сортирую по полю, которого нет в некоторых пользовательских документах, эти пользовательские документы не будут отображаться

   final Stream<QuerySnapshot<Map<String, dynamic>>> _usersStream =
  DatabaseService().usersCollection.orderBy('displayName').snapshots();
 

Не у всех пользователей есть «Имя дисплея», поэтому они не указаны в моем результате.

Кто-нибудь знает, как это обойти?