Working with
Firebase Arrays
INTRO
I have dusted off a little known / used corner of the Firebase realtime database which is working with Firebase arrays. Firebase have hardly any documentation on this, and they do not like to make use of it, however it may have some uses and benefits when working with "lists" (JSON arrays) in App Inventor. The main premise is that you work directly with the data on Firebase, instead of needing to bring the data down to work with it, then re-upload it, very similar to how you might work with tinyWebDB or cloudDB.
We will look at:
What is a firebase array?
Using the experimental Firebase component to create an array
Using the web component and the Firebase REST api to create and work with arrays
For this guide and the examples I have a top node named firebaseArrays (what we might know as the ProjectBucket), with a sub node, also called firebaseArrays, where we create the array. I have rules set as read/write to true.
What is a firebase array?
In simple terms, and usually when using the REST api or other framework, you can upload a list of data, and Firebase converts this to a set of nodes, and automatically numbers them. For example, take this list of data:
cat,dog,pig,hen,cow
This list can be uploaded directly to a firebase node, and firebase will make this of it
Notice first that Firebase starts the numbering at 0 (zero), we will need to bear this in mind that the list is 'zero based' and not 'one based' like App Inventor. I have surmised that this is why some users have had problems when setting their data with number based keys, starting at 1, Firebase thinks it is getting an array, and gets confused.
We can now work with this array in much the same way as we would work with other data.
Call back firebaseArrays and you get a JSON array of data
["cat","dog","pig","hen","cow"]
Call back firebaseArrays/1 and you get
"dog"
Applying the web component JSONTextDecode block will just return
dog
Now comes the interesting part. If we delete an element in the middle of the array, let us choose "pig", and then return the array we would usually expect this:
["cat","dog","hen","cow"]
but we actually get this:
["cat","dog","null","hen","cow"] or ["cat","dog","nothing","hen","cow"]
Firebase reserves the place for node 2, even though in the console it shows it as not there
This has benefits and consequences. We see this similar behaviour in sqlite and mysql, records 1 & 3 are always records 1 & 3, unless you, to use sqlite terminology, 'vacuum' the data to remove the empty records. To do this with firebase arrays, we would need to edit the list in our app to remove the "null" from the list, then re-upload the entire list, overwriting the current data. Alternatively, you can keep '2' in reserve, to replace with another value.
If you remove the last element, there is no placeholder. I do not suggest you remove the first element (0)....
Using the experimental Firebase component to create an array
Creating and working with arrays can be done using the Firebase component, but it can be a slow and ponderous activity, given the need to set each node individually. You should always start with '0', which helps Firebase to know that this is an array, and not json based key:value pairs.
Using the firebase component you will see that you also get the extra set of double quotes around your value.
You can hopefully see that this will be a tiresome way to work.
Note also that, invariably, calling a taglist on the array will not return anything
Using the web component and the Firebase REST api to create and work with arrays
The Firebase REST api exposes many more features and methods for interacting with arrays - POST(which we won't be using)/PUT/PATCH, and filtering/querying. we can use the web component and a set of urls to create, read,update and delete elements in the array. I have put together a series of screenshots that hopefully demonstrates each function. in each image on the left is the example app, which shows the output from the commands run, and also the changes made in the firebase console, and on the right are the blocks.
First up, we need some variables, I set the firebase url, and then the node to work with (firebaseArrays/firebaseArrays), and an AI2 list as a starting point.
Run the PUT base array. This uses the web component PUT option to set the list to an array in Firebase. Note that in the image I uses a JSON array string, which I converted to a list with the JSONTextDecode block. I could have used the global arrayList instead for the PutText text. note that we only have one set of double quotes (these are strings). Numbers would have no quotes.
Let us develop our array, and add a sub array to element 1. You can see that Firebase returns the data we provided as a JSON array, and that new numbering, all starting from 0, have been created for our data. Now, firebaseArray/1/1/1 would return labrador
We can also add a subJSON, normal key:pair values. I don't recommend you do this in the main array area, this will upset the auto numbering which Firebase uses to identify the data as an array. It should be OK in a nested array though.
And we can add a new element to the end of the array. Notice that I use the PATCH option here. I will show how we get the arrayLength next.
To get the length of the array, I used a parameter - shallow=true - with a GET, which just returns all the keys for all the data in the array. The length of the returned list is counted and displayed. I could get the last item, which would be 5, then add one, if I need to add an element to the array.
Having made a few changes, we now call back the contents of the array. It is returned as a JSON array, or list of lists, and uses GET
We can delete elements in the arrays, using the web component's DELETE option. Here we delete element 2:"pig". As mentioned previously, 2 is gone from the console, but returned as "null" in the data.
We can now put back element 2, again using the PATCH option
You probably wanted to know what was going on in the Web1.GotText event. For the most part, I have been returning the raw responseContent, but in a couple of places encoding to an AI2 list for further processing, you can see we we get the length of the array from.
Filtering and Querying
I won't go into great detail here, it is probably easier to follow the firebase documentation:
https://firebase.google.com/docs/database/rest/retrieve-data