MD_Reptile
MD_Reptile

Reputation: 43

Firebase Unity - Get all children into an array/generic list after GetValueAsync?

How can I get data back as an array or generic list from a Firebase database in Unity3D without knowing ahead of time what the name (key) of the children are?

I have been trying out the new Unity Firebase plugin, and I am having an issue figuring out how to get all the children in a specific location, and put the names (the key) and the values into arrays or generic lists so that I can work on the data locally. Forgive me for being so new to Firebase and probably using bad techniques to do this, and this plugin being so new its pretty hard for me to get much outside help, as there are not a lot of docs and tutorials out there on Firebase Unity.

In this particular case I am trying to create "instant messaging" like functionality, without the use of Firebase messaging, and just using regular Firebase database stuff instead. It might have been easier to use Firebase messaging, but mostly for the sake of learning and customization I want to do this on my own with just the Firebase database.

I insert data into the database like this:

public void SendMessage(string toUser, string msg)
{
    Debug.Log(String.Format("Attempting to send message from {0} to {1}", username, toUser));

    DatabaseReference reference = FirebaseDatabase.DefaultInstance.GetReference("Msgs");
    string date = Magnet.M.GetCurrentDate();

    // send data to the DB
    reference.Child(toUser).Child(username).Child(date).SetValueAsync(msg);
    // user receiving message / user sending message > VALUE = "hello dude|20170119111325"

    UpdateUsers();
}

And then I try and get it back like this:

public string[] GetConversation(string userA, string userB)
{
    // get a conversation between two users
    string[] convo = new string[0];

    FirebaseDatabase.DefaultInstance.GetReference("Msgs").GetValueAsync().ContinueWith(task =>
    {
        Debug.Log("Getting Conversation...");

        if (task.IsFaulted || task.IsCanceled)
        {
            Debug.LogError("ERROR: Task error in GetConversation(): " + task.Exception);
        }
        else if (task.IsCompleted)
        {
            DataSnapshot snapshot = task.Result;

            string[] messagesA = new string[0], messagesB = new string[0];

            if(snapshot.HasChild(userA))
            {
                // userA has a record of a conversation with other users
                if(snapshot.Child(userA).HasChild(userB)) // userB has sent messages to userA before
                {
                    Debug.Log("Found childA");
                    long count = snapshot.Child(userA).Child(userB).ChildrenCount;
                    messagesA = new string[count];
                    var kids = snapshot.Child(userA).Child(userB).Children;
                    Debug.Log(kids);
                    for (int i = 0; i < count; i++)
                    {
                        // this won't work, but is how I would like to access the data
                        messagesA[i] = kids[i].Value.ToString(); // AGAIN.... will not work...
                    }
                }
            }

            if(snapshot.HasChild(userB))
            {
                if(snapshot.Child(userB).HasChild(userA)) // userA sent a message to userB before
                {
                    Debug.Log("Found childB");
                    long count = snapshot.Child(userB).Child(userA).ChildrenCount;
                    messagesA = new string[count];
                    var kids = snapshot.Child(userB).Child(userA).Children;
                    Debug.Log(kids);
                    // messy incomplete testing code...
                }
            }

            // HERE I WOULD ASSIGN ALL THE MESSAGES BETWEEN A AND B AS 'convo'...
        }

        Debug.Log("Done Getting Conversation.");
    });


    return convo;
}

But obviously this won't work, because DataSnapshot won't let me access it like an array or generic list using indices, and I can't figure out how to treat the data when I don't know the names (the keys) of all the children, and just want to get them out one by one in any order... and since they are named by the date/time they are entered into the DB, I won't know ahead of time what the childrens names (keys) are, and I can't just say "GetChild("20170101010101")" because that number is generated when its sent to the DB from any client.

FYI here is what the DB looks like:

Database Structure

Upvotes: 1

Views: 8492

Answers (2)

Sarah
Sarah

Reputation: 135

Figured out the answer to your question. Here's my code snippet. Hope this would help!

void InitializeFirebase() {


    FirebaseApp app = FirebaseApp.DefaultInstance;
    app.SetEditorDatabaseUrl ("https://slol.firebaseio.com/");

    FirebaseDatabase.DefaultInstance
        .GetReference ("Products").OrderByChild ("category").EqualTo("livingroom")
        .ValueChanged += (object sender2, ValueChangedEventArgs e2) => {
        if (e2.DatabaseError != null) {
            Debug.LogError (e2.DatabaseError.Message);
        }


        if (e2.Snapshot != null && e2.Snapshot.ChildrenCount > 0) {

            foreach (var childSnapshot in e2.Snapshot.Children) {
                var name = childSnapshot.Child ("name").Value.ToString (); 

                text.text = name.ToString();
                Debug.Log(name.ToString());
                //text.text = childSnapshot.ToString();

            }

        }

    };
}

Upvotes: 2

Benjamin Wulfe
Benjamin Wulfe

Reputation: 1735

Firebase developer here.

Have you tried to use Value at the top level Snapshot? It should return to you an IDictionary where the values can also be lists or nested dictionaries. You will have to use some dynamic inspection to figure out what the values are.

Upvotes: 1

Related Questions