Skip to content

Firestore: Issue with data type of map value in the firestore document #521

@weinamdev

Description

@weinamdev

Hi,

As I working with firestore plugin for the MAUI project, I encountered some issues dealing with the map within the document.

I did a testing of a simple document with map fields as below

Image

For the common data type as the map value I am using (string, number, boolean and DateTimeOffset), I have no issue to create a class which implements IFirestoreObject and set them to cloud Firestore on Android platform.

        public class DataClassWithMaps : IFirestoreObject
        {
            [FirestoreProperty(nameof(StringMaps))]
            public Dictionary<string, string> StringMaps { get; set; } = new Dictionary<string, string>();

            [FirestoreProperty(nameof(NumberMaps))]
            public Dictionary<string, double> NumberMaps { get; set; } = new Dictionary<string, double>();

            [FirestoreProperty(nameof(BooleanMaps))]
            public Dictionary<string, bool> BooleanMaps { get; set; } = new Dictionary<string, bool>();

            [FirestoreProperty(nameof(DateMaps))]
            public Dictionary<string, DateTimeOffset> DateMaps { get; set; } = new Dictionary<string, DateTimeOffset>();
        }

However on Android, I encounter issue getting/retrieving the data.

No exception when calling doc.GetDocumentSnapshotAsync(), however exception occurred when attempt to access IDocumentSnapshot.Data when the class contains Dictionary<string, DateTimeOffset> OR Dictionary<string, bool> property, with the exception below

System.ArgumentException: 'Could not convert object of type Java.Lang.Boolean to Java.Lang.Object. Does it extend IFirestoreObject?'
System.ArgumentException: 'Could not convert object of type Firebase.Timestamp to Java.Lang.Object. Does it extend IFirestoreObject?'

On iOS, the condition is kind of different.
Exception happen on iOS by just calling doc.SetDataAsync to store the data to the cloud Firestore if Dictionary<string, DateTimeOffset> contain data in the class.

Exception has occurred: CLR/System.ArgumentException
An unhandled exception of type 'System.ArgumentException' occurred in Microsoft.iOS.dll: 'Couldn't put object of type System.DateTimeOffset into NSDictionary'
  at ObjCRuntime.Runtime.ThrowException(IntPtr gchandle)
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName)
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)

However, unlike Android. iOS platform has no issue getting the document with these maps.

In summary,
Android has no issue set the document
iOS has no issue get the document
Android cannot get the document (.Data) if the document contains Dictionary<string, bool> OR Dictionary<string, DateTimeOffset>
iOS cannot set the document if the document contains Dictionary<string, DateTimeOffset>

Below is the sample code for further testing and investigation, may comment out part of the code to test the behavior.

Thank you.

  async Task ExcuteTestGetDataWithMap()
  {
      var db = CrossFirebaseFirestore.Current;
      DateTimeOffset dt = DateTimeOffset.Now;

      var doc = db.GetCollection("zzz").GetDocument("docWithMaps");

      var data = new DataClassWithMaps();       
      data.StringMaps.Add("Key1", "Hello World");  // both working
      data.StringMaps.Add("Key2", "Hello Universe"); 
      data.NumberMaps.Add("Key1", 999.99);  // both working
      data.NumberMaps.Add("Key2", -999.99); 
      data.BooleanMaps.Add("Key1", true); // Android can set cannot get, iOS Working
      data.BooleanMaps.Add("Key2", false); 
      data.DateMaps.Add("Key1", dt);  // Android can set cannot get, iOS cannot set can get
      data.DateMaps.Add("Key2", DateTimeOffset.Now); 
      await doc.SetDataAsync(data, SetOptions.Merge());

      var snapshot = await doc.GetDocumentSnapshotAsync<DataClassWithMaps>();
      if (snapshot?.Data != null)
      {
          var dataOutput = snapshot.Data;
          
          if (dataOutput.StringMaps.TryGetValue("Key1", out string? stringValue))
              Debug.WriteLine(stringValue ?? "");

          if (dataOutput.NumberMaps.TryGetValue("Key1", out double numberValue))
              Debug.WriteLine(numberValue);

          if (dataOutput.BooleanMaps.TryGetValue("Key1", out bool booleanValue))
              Debug.WriteLine(booleanValue);

          if (dataOutput.DateMaps.TryGetValue("Key1", out DateTimeOffset dtoValue))
              Debug.WriteLine(dtoValue.ToString());
      }
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions