4

I'm experiencing a behavior where the following call behaves differently when executed for iOS and for Android.

In Android, the following .get() call returns the expected snapshot from the chatRoomID path. However, in iOS, .get() ends up returning a snapshot of the whole node under myUser.userID.

It seems for iOS, the second child node path is disregarded...

DataSnapshot snapshot = await chatsRef
                          .child(myUser.userID!)
                          .child(chatRoomID)
                          .get();
print(snapshot.value);

JSON:

{
"chats" : {
  "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : {
    "c00dca80-9077-11ec-855a-910961fc4253" : {
      "chatAdmin" : "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1",
      "chatImage" : "https://images.pexels.com/photos/887827/pexels-photo-887827.jpeg?auto=compress&cs=tinysrgb&h=650&w=940",
      "chatName" : "chef",
      "chatRoomID" : "c00dca80-9077-11ec-855a-910961fc4253",
      "isActivityChat" : false,
      "isGroupChat" : true,
      "lastMessage" : {
        "lastMessage" : "Hey",
        "lastMessageTime" : "2022-02-18 00:00:56.992308",
        "messageID" : "-MwAC5BUz3GKPmkA1SSQ",
        "nKDsrLrcU0PgtEDV5tKpMumSDuu1" : "true",
        "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : "false",
        "psJQRp96VGWIjTDpNpMUShPNWa82" : "true",
        "sendBy" : "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1",
        "senderName" : "Emily"
      },
      "muted" : {
        "nKDsrLrcU0PgtEDV5tKpMumSDuu1" : false,
        "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : false,
        "psJQRp96VGWIjTDpNpMUShPNWa82" : false
      },
      "users" : {
        "nKDsrLrcU0PgtEDV5tKpMumSDuu1" : true,
        "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : true,
        "psJQRp96VGWIjTDpNpMUShPNWa82" : true
      }
    },
    "nKDsrLrcU0PgtEDV5tKpMumSDuu1_oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : {
      "chatRoomID" : "nKDsrLrcU0PgtEDV5tKpMumSDuu1_oF1b6J4Hz3NGzRb9RmSVFGJdcYi1",
      "isActivityChat" : false,
      "isGroupChat" : false,
      "lastMessage" : {
        "lastMessage" : "Shut",
        "lastMessageTime" : "2022-02-18 00:01:30.161511",
        "messageID" : "-MwACDHlTWpQhhQFh9k8",
        "nKDsrLrcU0PgtEDV5tKpMumSDuu1" : "true",
        "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : "false",
        "sendBy" : "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1",
        "senderName" : "Emily"
      },
      "muted" : {
        "nKDsrLrcU0PgtEDV5tKpMumSDuu1" : false,
        "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : false
      },
      "users" : {
        "nKDsrLrcU0PgtEDV5tKpMumSDuu1" : true,
        "oF1b6J4Hz3NGzRb9RmSVFGJdcYi1" : true
      }
    }
  }
},
}

enter image description here

  • 1
    Hmm... that sounds weird indeed, as the underlying SDKs should work the same on those platforms. Can you edit your question to: 1) Include the JSON as text, so that I can copy/paste it into my own database to test? You can get this by clicking the "Export JSON" link in the overflow menu (⠇) on your [Firebase Database console](https://console.firebase.google.com/project/_/database/data). 2) Show a single code snippet that I can copy/paste into my Flutter test bed to reproduce the problem? – Frank van Puffelen Feb 17 '22 at 18:01
  • Hi Frank, I just edited my question. Another behavior that I found that was different between iOS and Android is whenever I check to see if a node has a child iOS always returns that there is a child even though there isn't while Android does it correctly. Basically Firebase SDK works perfectly like how I expect it to behave on Android but does not behave the same one iOS... await chatsRef.child(myUser.userID!).child(chatRoomID).get().then((DataSnapshot snapshot) async {if (snapshot.value == null) {...then do A}} – ckingprogramming Feb 17 '22 at 23:57
  • Hey @ckingprogramming. Thanks for sharing the JSON . And sorry to hear about the second problem, but I'd like to focus on the first one for the moment. One of our engineers tried to reproduce it in the pure iOS SDK and was unable to. I can give it a try in Flutter, but that'll take some time. Can you change the code to something that logs the different output between iOS and Android, and then include the updated code and its output in your question. – Frank van Puffelen Feb 18 '22 at 01:37
  • Hi Frank, upon further debugging the initial problem I am having and the second issue that I observed I realized they are basically the same issue arising from the following line of code: DataSnapshot snapshot = await chatsRef.child(myUser.userID!).child(chatRoomID).get(); I updated the question to better describe the issue. – ckingprogramming Feb 18 '22 at 05:26
  • That's good to hear @ckingprogramming. I'm still trying to reproduce it, but it'll take more time. To get unstuck more quickly, consider using `once` instead of `get`. They operate *almost* the same, and `once` is less likely to have issues (as it's a much older API). – Frank van Puffelen Feb 18 '22 at 15:06
  • 2
    Frank! It turns out that it is indeed with the get, once works perfectly fine. Thanks for the suggestion. – ckingprogramming Feb 18 '22 at 20:40
  • Good to hear @ckingprogramming. I'll raise the issue to our engineers, and continue to try and reproduce it myself too. – Frank van Puffelen Feb 18 '22 at 22:38
  • Hey @ckingprogramming: I'm having a really hard time reproducing the problem. Can you have a look at the update in my answer below and see if you can spot why I'm not getting both chat threads for the user? – Frank van Puffelen Feb 24 '22 at 00:34

1 Answers1

2

As discussed in the comments

You should be getting the same behavior on both iOS and Android, as the underlying SDKs should work the same on those platforms. That said, since the FlutterFire libraries wrap the native SDKs and the get() API is relatively new, it might be that there is an unintended difference between how the iOS and Android SDKs implement it.

If that is indeed the case, you might want try and see if once() works for you. While it has an annoying side-effect in an edge-case (see here), the once API itself is much older, so more likely to be stable across platforms.


Update: I'm having a really hard time reproducing the problem. I've imported your JSON into a database of mine, and then run this code on startup of my app:

FirebaseDatabase database = FirebaseDatabase.instance;
var chatsRef = database.ref('71163140/chats');
var threadRef = chatsRef.child('oF1b6J4Hz3NGzRb9RmSVFGJdcYi1').child('nKDsrLrcU0PgtEDV5tKpMumSDuu1_oF1b6J4Hz3NGzRb9RmSVFGJdcYi1');
DataSnapshot snapshot = await threadRef.get();
if (snapshot.value != null) {
  print('get: ${snapshot.value}');
}

DatabaseEvent event = await threadRef.once();
if (event.snapshot.value != null) {
  print('once: ${event.snapshot.value}');
}

So it reads a single chat thread out of the data you shared with both get() and once(), and then prints what it gets. Both on iOS and Android, I never see the c00dca80-9077-11ec-855a-910961fc4253 thread showing up in my output, I only get the chat thread where "isGroupChat" : false,.

Can you update the code or data in your question to show how I can get the same faulty result as you get?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Hi Frank, the code and JSON probably isn't the issue since I can't see anything from your posted code that differs from mine. I'm wondering if it's because I'm using an older firebase_database plugin version. I'm currently using firebase_database: ^8.2.0. I held out from updating to the new plugin versions because there were a lot of breaking changes. – ckingprogramming Feb 24 '22 at 18:01
  • I don't think there were recent changes in this part of the SDK, but let me know if the problem disappears once you upgrade to the latest library version. – Frank van Puffelen Mar 13 '22 at 18:15
  • 1
    I also experience this issue with `get()` and `once()` on iOS. [Raised it with flutterfire](https://github.com/firebase/flutterfire/issues/9067) who redirected me here. – SoftWyer Jul 12 '22 at 08:57
  • Interestingly, I set up a periodic `Timer` to query a certain path in the DB every second using `get()` and print the length of the `Map`. Initially it is correct but as I use my app and retrieve other data, the length becomes incorrect, even though the data at that location has not changed. I will raise this as a bug in the ` firebase-ios-sdk` GitHub. – SoftWyer Jul 12 '22 at 21:23
  • 1
    Thanks @SoftWyer. If I understand the team correctly they are working on reimplementing `get` on iOS and Android to get rid of some of these raise conditions. No ETA on when it'll land, but work is actively in progress (on the Android code first). – Frank van Puffelen Jul 12 '22 at 23:37