Search code examples
javascriptjsonfirebaseqmlv-play

handling nested JSON data for ListView


I am looking to access nested JSON data from a firebase database to use within a listView, this is something I have applied throughout my app, but am now having trouble having to access children of the data with dynamic properties.

An export of my JSON data from my data base is;

{
    "T&G Canary Wharf" : {
        "Administrator" : {
            "1550633367665" : {
                "date" : "2019-02-12T12:00:00.000",
                "details" : "Full Day",
                "name" : "Edward Lawrence",
                "status" : "pending"
            },
            "1550633370715" : {
                "date" : "2019-02-13T12:00:00.000",
                "details" : "Full Day",
                "name" : "Edward Lawrence",
                "status" : false
            },
            "1550845072137" : {
                "date" : "2019-02-12T12:00:00.000",
                "details" : "Full Day",
                "name" : "Katie Prescott ",
                "status" : 1
            },
        },
        "Stylist" : {
            "1551222170677" : {
            "date" : "2019-02-19T12:00:00.000",
            "details" : "Full Day",
            "name" : "Stylist Stylist",
            "status" : "pending"
      }
    }
  }
}

Per user of the app, group (in the above example T&G Canary Wharf) will always be set, but the subgroup (in the example Administrator & Stylists) is dynamic for admins, and this is where I am struggling,

My code for my firebase database read is below:

I am using felgo(formerly v-play), a link to their firebase documentation is:

Felgo Firebase Plugin

App {

    property var adminModel: []
    property var groupName //the group name is assigned onLoggedIn, in this example group name === T&G Canary Wharf

    FirebaseDatabase {
        onLoggedIn: { 
        firebaseDb.getValue("groups" + "/" + groupName, {
                                orderByValue: true
                            }, function(success, key, value) {
                            if(success){
                            console.log("ADMIN MODEL: " + JSON.stringify(value))
                            adminModel = value // my array where I intend to push the data too                              
                            }
                        })
                    }
                }
            }

I have been reading through;

access/process nested objects, arrays or JSON

(super helpful by the way) specifically the section of What if the property names are dynamic and I don't know them beforehand?

I can create two list entries, of Administrator and Stylist (the subGroups, but where the child key of this is also dynamic (the time the entry is created, e.g: "1550633367665"), I cannot seem to get further?

to create this model I have the code:

ListPage {
    id: adminPage

    model: Object.keys(adminModel)

delegate: SwipeOptionsContainer {
    id: container

    rightOption:  SwipeButton {
        anchors.fill: parent
        backgroundColor: "red"
        icon: IconType.trash

        onClicked: {
            container.hideOptions()
        }
    }

    SimpleRow {
        id: userRow
        width: parent.width
        text: modelData
        }
    }
}

My question is

How can I create a listView with the delegates being any object containing a "status" : "pending" - done in other areas using a loop of if (value[i].status === pending) { arr.push({...})}, but whilst the subgroup (Stylist/Administrator) is unknown, from the above database example there would be 2 list elements, but in reality will contain many more with multiple subGroup's.


Solution

  • After doing getValue from FireBase, it seems like you need to perform a few things:

    1. Retrieve the subgroups from your group.
    2. Iterate through the subgroups.
    3. For each subgroup, retrieve the time entries.
    4. Filter the time entries based on whether their status is "pending".

    It looks like you've already achieved Step 1 with Object.keys(adminModel). Now we'll take that a couple steps further with a for-loop (Step 2 √).

    var subgroups = Object.keys(adminModel);
    for (var i in subgroups) {
        var subgroup = adminModel[subgroups[i]];
    
        // ...
    }
    

    For convenience, we've defined subgroup_obj which will store the data of a subgroup. E.g.

    "Stylist": {
          "1551222170677" : {
               "date" : "2019-02-19T12:00:00.000",
               "details" : "Full Day",
               "name" : "Stylist Stylist",
               "status" : "pending"
          }
    }
    

    We then go on to Step 3, retrieving time entries by again using Object.keys() but this time on the subgroup.

    var timeEntries = Object.keys(subgroup);
    

    Since Object.keys() returns an array, we can accomplish Step 4 by using the filter() array method to filter entries with a pending status.

    var filteredEntries = timeEntries.filter(function(t) { return subgroup[t].status === "pending"; } );
    

    With newer version of JS, you could do timeEntries.filter(t => subgroup[t].status === "pending") but this doesn't seem to be fully supported by Qt yet.

    And that's that. filteredEntries gives us an array of time entries (e.g. [ "1551222170677" ]) for each subgroup.

    If you want the complete time entry object, you could use the map array method to get

    var filteredEntries2 = filteredEntries.map(function(t) { return subgroup[t]; });
    

    which gives you an array of objects. So something like

    [
    {
        date: "2019-02-19T12:00:00.000"
        details: "Full Day"
        name: "Stylist Stylist"
        status: "pending"
    }
    ]
    

    Hope this helps!