Firebase Realtimedatabase

Status
Not open for further replies.

fredo

Well-Known Member
Licensed User
Longtime User
Thanks for the update.
"updateChildren" throws no error - great! :)

For testing I used your example project and modified it a bit.
EDIT: This is old code. It is better to use the code from #35 below.

B4X:
#Region  Project Attributes
   #ApplicationLabel: FirebaseDB
   #VersionCode: 2
   #VersionName: px
   'SupportedOrientations possible values: unspecified, landscape or portrait.
   #SupportedOrientations: unspecified
   #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
   #FullScreen: False
   #IncludeTitle: True
#End Region

'#AdditionalJar: com.google.firebase:firebase-core

Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub



Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim realtime As FirebaseDatabase
   Dim ref As DatabaseReference
End Sub

Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:
   'Activity.LoadLayout("Layout1")
   realtime.Initialize("Realtime")
   realtime.PersistenceEnabled = True
   realtime.goOnline
   Dim strTopNode As String = "testnode1"
   ref.Initialize("Reference",realtime.getReferencefromUrl($"https://yyyyyyyymyidyyyyyyyy.firebaseio.com/${strTopNode}/"$) )
   'ref.Initialize("Reference",realtime.getReferencefromUrl("https://tactical-patrol-603.firebaseio.com/"))
   ref.addChildEventListener
   ref.addListenerForSingleValueEvent
   ref.addValueEventListener
   'Log("ref testnode1 = " & ref.Child("testnode1"))
End Sub

Sub Activity_Resume
   Testfunction_updateChildren

End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

Sub Reference_onCancelled(errnum As Int,error As String)
   Log($"ref_onCancelled(${errnum},${error})"$)
End Sub
Sub Reference_onChildAdded(snapshot As Object, child As String)
   Log($"ref_onChildAdded(${child})"$)
End Sub
Sub Reference_onChildChanged(snapshot As Object, child As String)
   Log($"ref_onChildchanged(${child})"$)
End Sub
Sub Reference_onChildMoved(snapshot As Object, child As String)
   Log($"ref_onChildMoved(${child})"$)
End Sub
Sub Reference_onChildRemoved(snapshot As Object)
   Log($"ref_onChildRemoved()"$)
End Sub
Sub Reference_onDataChange(snapshot As Object)
   Log($"ref_onDatachange()"$)

   Dim snap As DataSnapshot = snapshot
    'Log("Value="&snap.Value)
    Dim x As String = snap.Value
    If x.Length > 0 Then
      x = x.SubString2(0, Min(32, x.Length -1)) & "..."
    End If
    Log("  Value=" & x)


   'Dim json As JSONParser
   'json.Initialize(snap.Value)
   'Dim root As Map = json.NextObject
   'Log(root)
   'Dim keys As List = snap.Children
   'Log(keys.Size)
   'Log(snap.Children)
End Sub


Sub Testfunction_updateChildren
   ' This is an extract from "Sub writeNewPost(...)" from here: https://www.b4x.com/android/forum/threads/firebase-database-rest-and-realtime-testproject.70156/

   '### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
   '### Sub writeNewPost(strUid As String, strUNam As String, strTitle As String, strBody As String) As Boolean
   Dim strUid As String     = "-KXY123"
   Dim strUNam As String     = "Mike Testuser"
   Dim strTitle As String     = "This is a testtitle"
   Dim strBody As String     = $"TimeStamp=${DateTime.Now} BodyText."$
   '### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
   Dim mapPostValues As Map
   mapPostValues.Initialize
   mapPostValues.Put("Uid", strUid)
   mapPostValues.Put("UNam", strUNam)
   mapPostValues.Put("Title", strTitle)
   mapPostValues.Put("Body", strBody)
   Dim strPostValues As String = raMapToJson(mapPostValues)
   Log("#-  strPostValues=" & strPostValues)

   Dim key As String = ref.push     ' Creates this -->    ' https://fbdbzzzz-xyxyxyx.firebaseio.com/testnode1/-KT4Xi6oGKr0wye-zOoO ' The last part this is what we need = OK
   Log("#-  raw key=" & key)
   If key.Length < 2 Then
     Return False
   End If
   '
   ' Extract the autogenerated optimized Firebase-key
   key = key.SubString(key.LastIndexOf("/") +1)  '#- creates this -->  -KT4Xi6oGKr0wye-zOoO
   Log("#-  key=" & key)
   ' Fanout the data to different paths   --> https://firebase.googleblog.com/2015/10/client-side-fan-out-for-data-consistency_73.html
   Dim strUk1 As String = "/posts/" & key
   Dim strUk2 As String = "/user-posts/" & strUid & "/" & key
   Log("#-  strUk1=" & strUk1)
   Log("#-  strUk2=" & strUk2)
   Dim childUpdates As Map
   childUpdates.Initialize
   ' childUpdates.Put(strUk1, strPostValues) ' <<--str... was incorrect, it needs to be the map
   ' childUpdates.Put(strUk2, strPostValues )
   childUpdates.Put(strUk1, mapPostValues)
   childUpdates.Put(strUk2, mapPostValues)
   ' The JSON data that send up in a more readable format
   Log("#-  childUpdates=" & CRLF &  raJsonPretty(raMapToJson(childUpdates )) )
   ref.updateChildren(childUpdates)
End Sub
'
Sub raJsonToMap(strJSON As String) As Map
  Dim jMap As Map  : jMap.Initialize
  Dim JSON As JSONParser  : JSON.Initialize(strJSON)
  jMap = JSON.NextObject
  Return jMap
End Sub
Sub raMapToJson(mapX As Map) As String
   Dim jsonGen As JSONGenerator
   jsonGen.Initialize(mapX)
   Return jsonGen.ToString
End Sub
Sub raJsonPretty(strJson As String) As String
   Dim j As JSONGenerator
   j.Initialize(raJsonToMap(strJson))
   Return j.ToPrettyString(4)
End Sub

Sub Reference_onComplete(errorCode As Int, errorMessage As String, errObj As Object)
   Log($"Reference_onComplete(...)"$)
   'Log($"Reference_onComplete(${errorCode},${errorMessage})"$)
End Sub

The structure of the map in the green rectangle is the way it should look like,
the yellow framed part is what is generated by the example code.

04-10-_2016_10-47-25.jpg

I like the way how we're working at this (do you know the movie of two guys where one is blind and the other is deaf?)

I hope we can bring this together to 100% in the next few weeks...
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
the yellow framed part is what is generated by the example code.
Can you put in a log of the map which is used for the updatechildren
B4X:
   Log("#-  childUpdates=" & CRLF &  childUpdates )

The values in your db looks like it is the result of your "json2map" routine or so....

Check where the "\"´s are coming from! It should not be in a json string as it ends in an incompatible json
 
Last edited:

fredo

Well-Known Member
Licensed User
Longtime User
...the output of ...strPostValues...
That was a good idea!

After I modified the testcode to...
B4X:
    Dim childUpdates As Map
    childUpdates.Initialize
'    childUpdates.Put(strUk1, strPostValues)
'    childUpdates.Put(strUk2, strPostValues )
    childUpdates.Put(strUk1, mapPostValues)
    childUpdates.Put(strUk2, mapPostValues)
...its correct. This is great.

As Attachment there is a short dynamic screenshot of the Database and the log.

Preview:
04-10-_2016_13-13-08.jpg
 

Attachments

  • 04-10-_2016_13-18-20.zip
    334.6 KB · Views: 316

DonManfred

Expert
Licensed User
Longtime User
the error you get (red) seems to be inside the event sub.... check if errObj <> null
It is expected to get null if there was no error.

B4X:
Sub Reference_onComplete(errorCode As Int, errorMessage As String, errObj As Object, dbref As Object)
    Log($"ref_onCancelled(${errorCode},${errorMessage})"$)
    If errObj <> Null Then
        Dim err As DatabaseError = errObj
    End If
    If dbref <> Null Then
        Dim ref As DatabaseReference = dbref
    End If

End Sub

Maybe you need new lib as i changed the signature i have in mind.... there is an exception in the lib too if there is no error...

Will attach the new version to test here.
Note that the databasereference can now be concenated...
B4X:
Dim postsref As String = userref.push.Key
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
Since this change the key is somehow incorrect.
It's now the name of the TopNode instead of the correct autogenerated key from 1.22.
ohh... Will do a step back and report back....
That was my last changes yesterday late in the evening
 

DonManfred

Expert
Licensed User
Longtime User
Have a short look at this and this to get an idea what would be best to set a reference.
Thank you for that... I watched them both but i must honestly say: I really like the second one!
It is a great demonstration (AND explanation) on the "workflow".. Really great video.

A must see in regard to the realtime database!

To talk about the second video... We are getting much closer to this ;-)
 

DonManfred

Expert
Licensed User
Longtime User
Creates this --> ' https://fbdbzzzz-xyxyxyx.firebaseio.com/testnode1/-KT4Xi6oGKr0wye-zOoO ' The last part this is what we need = OK
B4X:
    Dim userref As DatabaseReference = ref.Child("posts")
    Dim posts As DatabaseReference = userref.push ' Just need this reference to get the key for it. you´ll update the children of userref
    Log("userref.push.key = "&posts.Key)
  Dim key As String = posts.Key    '
  Log("#-  key=" & key)

this will directly give me the key
#- key=-KTFl_1ls1cg8zOOjY3r
 

fredo

Well-Known Member
Licensed User
Longtime User
Ok. V1.24

Yesss! It works. Great work @DonManfred.

05-10-_2016_08-56-39.jpg

05-10-_2016_08-56-18.jpg

B4X:
#Region  Project Attributes
    #ApplicationLabel: FirebaseDB
    #VersionCode: 3
    #VersionName: rx
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region
'#AdditionalJar: com.google.firebase:firebase-core
'
' ║ ***** ***** ***** ***** ***** ***** ***** *****
' ║  Testproject for first steps with the
' ║  Firebase Realtime Database
' ║ ***** ***** ***** ***** ***** ***** ***** *****
' ║
' ║   Info for first time users:
' ║
' ║     1. Open your App in the Firebase console: https://console.firebase.google.com and select "Database" on the left
' ║     2. Select the RULES tab and set the rules for your access (e.g. the rules below for test purposes)
' ║     3. Select the DATA tab to watch the database changes later
' ║        4. Make sure you have the correct "google-services.json"-file in your B4X project folder
' ║        5. Make sure you have the correct packagename [Ctl+B] to match with your Firebase settings
' ║     6. Set your Firebase project id in  Activity_Create
' ║     7. Open the IDE Logs window [F6]
' ║     8. Compile and Run with [F5]
' ║
' ║
' ║   Just in case you need the rules for easy access (make sure the "true" words are lowercase!)
 
    '        // These rules give ANYONE, even people who are not users of your app,
    '        // read and write access to your database
    '        {
    '          "rules": {
    '            ".read": true,
    '            ".write": true
    '          }
    '        }
' ║
' ║ If you see an errormessage like the one below, then it's propably due to step 6 above:
'         main_activity_create (java line: 349)
'         com.google.firebase.database.DatabaseException: Invalid URL (....)
' ║
' ║
' ║ --- --- --- ---
' ║ USE ALWAYS @DonManfreds MOST RECENT Wrap of the Firebase-Realtime-Database-Library --> https://www.b4x.com/android/forum/threads/firebase-realtimedatabase.69773/
' ║ --- --- --- ---


Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

End Sub



Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
 
    Dim realtime As FirebaseDatabase
    Dim ref As DatabaseReference
 
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Activity.LoadLayout("Layout1")

    realtime.Initialize("Realtime")
    realtime.PersistenceEnabled = True
    realtime.goOnline
 

' ║
    Dim strMyProjectId As String = "yyyymyid" ' <-- At first put YOUR Firebase project id HERE <-- <-- <-- <-- <-- <-- <-- <-- <-- <--
    '                  - correct --> "mytestapp-4c1f8"
    '                  - wrong   --> "https://mytestapp-4c1f8"
    '                  - wrong   --> "https://mytestapp-4c1f8/"
' ║
    Dim strTopNode As String = "testnode1"
    ref.Initialize("Reference",realtime.getReferencefromUrl($"https://${strMyProjectId}.firebaseio.com/${strTopNode}/"$) )
    ref.addChildEventListener
    ref.addListenerForSingleValueEvent
    ref.addValueEventListener
 
    ''Log("ref testnode1 = " & ref.Child("testnode1"))
 
End Sub

Sub Activity_Resume
 
    Testfunction_updateChildren
     
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

Sub Reference_onCancelled(errnum As Int,error As String)
    Log($"ref_onCancelled(${errnum},${error})"$)
End Sub
Sub Reference_onChildAdded(snapshot As Object, child As String)
    Log($"ref_onChildAdded(${child})"$)
End Sub
Sub Reference_onChildChanged(snapshot As Object, child As String)
    Log($"ref_onChildchanged(${child})"$) 
End Sub
Sub Reference_onChildMoved(snapshot As Object, child As String)
    Log($"ref_onChildMoved(${child})"$) 
End Sub
Sub Reference_onChildRemoved(snapshot As Object)
    Log($"ref_onChildRemoved()"$)
End Sub
Sub Reference_onDataChange(snapshot As Object)
    Log($"ref_onDatachange()"$)
    Try
        Dim snap As DataSnapshot = snapshot
        'Log("    Value="&snap.Value)
        Dim x As String = snap.Value
        If x.Length > 0 Then  
            x = x.SubString2(0, Min(32, x.Length -1)) & "..."
        End If
        Log("#-  Value=" & x)
    Catch
        Log("#-  ERROR..." & CRLF & LastException.Message)
     
    End Try
End Sub


Sub Testfunction_updateChildren
    Log("#-Testfunction_updateChildren")
    '### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
    ' This is an extract from "Sub writeNewPost(...)" from here: https://www.b4x.com/android/forum/threads/firebase-database-rest-and-realtime-testproject.70156/
    '### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
    'Sub writeNewPost(strUid As String, strUNam As String, strTitle As String, strBody As String) As Boolean
    Dim strUid As String      = "-KXY123"        ' <-- This is normally defined at the login
    Dim strUNam As String      = "Mike Testuser"  ' <-- Comes from the login
    Dim strTitle As String      = "This is a testtitle"
    Dim strBody As String      = "Bodytext-Bodytext-Bodytext."
    '### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
 
 
    Dim userref As DatabaseReference = ref.Child("posts") ' <-- One node we want to write the data to
    Dim posts As DatabaseReference = userref.push         ' <-- We just need this reference to get the autogenerated KEY
    Dim key As String = posts.Key 
    Log("#-  key=" & key) 

    Dim mapPostValues As Map
    mapPostValues.Initialize
    mapPostValues.Put("Uid", strUid)
    mapPostValues.Put("UNam", strUNam)
    mapPostValues.Put("tstamp", DateTime.Now)
    mapPostValues.Put("tstamp2", DateTime.Date(DateTime.Now) & ", " & DateTime.Time(DateTime.Now))
    mapPostValues.Put("Title", strTitle)
    mapPostValues.Put("Body", strBody)

    ' Fanout the data to different paths ("NoSQL" recommendation for up to 1 million simultanous users)  --> https://firebase.googleblog.com/2015/10/client-side-fan-out-for-data-consistency_73.html
    Dim strUk1 As String = "/posts/" & key
    Dim strUk2 As String = "/user-posts/" & strUid & "/" & key
    Log("#-  strUk1=" & strUk1) 
    Log("#-  strUk2=" & strUk2) 
 
    Dim childUpdates As Map
    childUpdates.Initialize
    childUpdates.Put(strUk1, mapPostValues)
    childUpdates.Put(strUk2, mapPostValues)
    ref.updateChildren(childUpdates)      ' <-- This is the "atomic" update. One start of transaction no matter how many elements the map has
    Log("#-  childUpdates=" & childUpdates)
 
End Sub

Sub Reference_onComplete(errorCode As Int, errorMessage As String, errObj As Object, dbref As Object)
    Log($"Reference_onComplete(${errorCode},${errorMessage})"$)
    If errObj <> Null Then
        Dim err As DatabaseError = errObj
        Log($"  err.Code   =${err.Code}"$)
        Log($"  err.Details=${err.Details}"$)
        Log($"  err.Message=${err.Message}"$)
    End If
    If dbref <> Null Then
        Dim ref As DatabaseReference = dbref
        Log($"  ref.Key=${ref.Key}"$)
    End If

End Sub

Now I can go ahead to build a demo project with user login over RULES settings.
 

fredo

Well-Known Member
Licensed User
Longtime User
...We are getting much closer to this...

"ref.setValue" would be my next wish to inspect in the next few days since I need it for "...demo project with user login over RULES..."

In the attached project I try to set a value in the way as in the Firebase guide mentioned
09-10-_2016_18-28-49.jpg

but I couldn't find the member "setValue".

B4X:
Sub btnTest_user_Click
    '  Make sure the UserId is in the "users" list of the {topnode} branch
    Log(" ")
    Log("#-btnTest_user_Click")  

    ' Testvalues instead of real auth data
    Dim strFirebaseSignedInUserID As String = "100"
    Dim strFirebaseSignedInUser As String   = "person100"

    Dim refOfTopNode As DatabaseReference = ref
       Dim tempuserref As DatabaseReference = refOfTopNode.Child("users")
  
    ' tempuserref.Child(strFirebaseSignedInUserID).Child("username").setValue(strFirebaseSignedInUser) ' <<--"setValue" not working

    ' ...since chaining is not available I tried it stepwise
    tempuserref = tempuserref.Child(strFirebaseSignedInUserID)
    tempuserref = tempuserref.Child("username")
'    tempuserref.setValue(strFirebaseSignedInUser)
    Log("<<--")
  
End Sub
 

Attachments

  • RealtimeDbEx_fredo15.zip
    10.2 KB · Views: 342

DonManfred

Expert
Licensed User
Longtime User
"ref.setValue" would be my next wish to inspect
It is working. While "Creating" a new Member you need to set a mapfor the content (value)

Start with creating the user itself.
B4X:
    ref.Value = CreateMap("DisplayName":User.DisplayName,"isAnonymous":User.Anonymous,"email":User.Email,"photourl":User.PhotoUrl,"EmailVerified":User.EmailVerified,"ProviderId":User.ProviderId,"Uid":User.Uid)

Now you can add your posts (or whatever) to them

Value is a property of the databasereference. Due to b4a architecture this, in fact, is a shortcut for the method ref.setValue...

fbuser0081.png
 
Status
Not open for further replies.
Top