How to handle when a Firestore document may or may not include a field with Flutter


Asked by edn on November 03, 2021 (source).

I have an existing Firestore database for a project. In a given collection (say "users"), I have the user profile information in each document.

In some documents, I have the field "signupMethod" in the collection while the same field does not exist in some other documents in the same collection.

I need to try to read the signupMethod for each user session in my application. If the document does have the field, the value of the field needs to be used. If the field for the corresponding users document does not exist, I would like to set it to the default value of "Email".

I try the following approach:

try {
  if ("signupMethod")) {
    wpUserProfile.signupMethod =["signupMethod"];
  } else {
    wpUserProfile.signupMethod = "Email";
} on Exception catch (_) {
  wpUserProfile.signupMethod = "Email";

But it gives the following error:

Exception has occurred.
NoSuchMethodError (NoSuchMethodError: Class '_JsonDocumentSnapshot' has no instance method 'call'.
Receiver: Instance of '_JsonDocumentSnapshot'
Tried calling: call())

And I try the following instead:

try {
   wpUserProfile.signupMethod =["signupMethod"];
} on Exception catch (_) {
  wpUserProfile.signupMethod = "Email";

And I get the following error this time:

Exception has occurred.
StateError (Bad state: field does not exist within the DocumentSnapshotPlatform)

I do not understand why it does not run the code in the Exception block and set it to "Email".

Does anyone know how I should handle this situation when reading a field from Firestore which may or may not exist in a given document with flutter?

ADDENDUM: (Answer to Peter's question below)

If I print out, I get the following output:

flutter: Instance of '_JsonDocumentSnapshot'

If I print out, I get the following error:

[] Unhandled Exception: NoSuchMethodError: Class '_JsonDocumentSnapshot' has no instance method 'call'.
Receiver: Instance of '_JsonDocumentSnapshot'
Tried calling: call()
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:63:5)
#1      _UserDataProviderState._setUserProfileData
#2<anonymous closure>
#5      ComponentElement.performRebuild
#6      StatefulElement.performRebuild
#7      Element.rebuild
#8      BuildOwner.buildScope
#9      WidgetsBinding.drawFrame
#10     RendererBinding._handlePersistentFrameCallback
#11     SchedulerBinding._invokeFrameCallback
#12     SchedulerBinding.handleDrawFrame
#13     SchedulerBinding._handleDrawFrame
#14     _rootRun (dart:async/zone.dart:1428:13)
#15 (dart:async/zone.dart:1328:19)
#16     _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#17     _invoke (dart:ui/hooks.dart:166:10)
#18     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#19     _drawFrame (dart:ui/hooks.dart:129:31)

If I just print out["email"], I get the following output:

[email protected]


Question answered by Peter K (source).

In your case I assume that snapshot contains an AsyncSnapshot object. According to the documentation it has a data property. This can be null, so it is always recommended to check hasData / hasError properties before processing the results.

So once you made sure it is not null,! will contain the result of your AsyncSnapshot, in this case this is a DocumentSnapshot.

Looking at documentation, DocumentSnapshot has a data() method that will hold the document itself. So finally!.data() will be your document, and you can get the fields from it like:

  •!.data()["signupMethod"], or
  • (if you need the id of the document, it will be in!.id)

In both cases you will get null if the field does not exists, so you don't need containsKey.

Important: make sure to check if!.exists is true, because Firestore will give you the document snapshot even if the data you are looking for can't be found. If exists is true, you are good to go with the above.