0

Firebase Data:

{
    "data": {
        "entry-1": {
            "created": 1484634400,
            "status": 1
        },
        "entry-2": {
            "created": 1482612312,
            "status": 0
        },
        "entry-3": {
            "created": 1481623400,
            "status": 1
        },
        "entry-4": {
            "created": 1485613233,
            "status": 1
        },
        "entry-5": {
            "created": 1489513532,
            "status": 0
        },
        "entry-6": {
            "created": 1483123532,
            "status": 1
        },
        "entry-7": {
            "created": 1481282376,
            "status": 1
        },
        "entry-8": {
            "created": 1432321336,
            "status": 1
        },
        "entry-9": {
            "created": 1464282376,
            "status": 0
        }
    }
}

I'm trying to count how many active entries (status = 1) were created before entry-4, and keeping the count updated live.

Today I listen to every change in the database, but it is consuming a lot of unnecessary data. Is there a better way to do this?


Code:

FIRDatabaseQuery *query = [self.firebase child:@"data"];
[query observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
    int count = 0;
    for (FIRDataSnapshot *child in snapshot.children) {
        if (child.value[@"status"] == 1 && child.value[@"created"] < 1485613233) {
             count++;
        }
    }
}];
AL.
  • 36,815
  • 10
  • 142
  • 281
Luciano Nascimento
  • 2,600
  • 2
  • 44
  • 80
  • 1
    There is no count operator in Firebase Database. To prevent having to download all items to get a count, you can keep a separate `count` node - that you then update transactionally. See http://stackoverflow.com/questions/15148803/in-firebase-is-there-a-way-to-get-the-number-of-children-of-a-node-without-load/15149311#15149311 – Frank van Puffelen Feb 09 '17 at 22:15
  • 1
    Firebase has recently released Cloud Functions. Have a look at this [answer](http://stackoverflow.com/a/42713792/5861618) for more details – Rosário Pereira Fernandes Mar 10 '17 at 08:55

1 Answers1

0

I'm providing a Swifty answer but it's easily convertible to Obj-C

Change your data structure to this

{
    "data": {
        "-Yuna99s993m": {
            "created": 1484634400,
            "status": "1"
            "entry": "1"
            "status_entry": "1_1"
        },
        "-YUjns0909ks": {
            "created": 1482612312,
            "status": "0"
            "entry": "2"
            "status_entry": "0_2"
        },
        "-Y8hj98nmswm": {
            "created": 1481623400,
            "status": "1"
            "entry": "3"
            "status_entry": "1_3"
        },
        "-Y78903kjmsk": {
            "created": 1485613233,
            "status": "1"
            "entry": "4"
            "status_entry": "1_4"
        },
        "-YJuikw9klkos": {
            "created": 1489513532,
            "status": 0
            "entry": "5"
            "status_entry": "0_5"
        },

Then a query to retrieve all entries before 4, that have a status of 1

let dataRef = ref.child("data")
let queryRef1 = dataRef.queryOrdered(byChild: "status_entry")
let queryRef2 = queryRef1.queryStarting(atValue: "1_1")
                         .queryEnding(atValue: "1_3")
queryRef2.observeSingleEvent(of: .value, with: { snapshot in
   print(snapshot.childrenCount) 
 })

When run, this returns

2

Which means there are two nodes before entry 4 that have a status of 1; those nodes are

"-Yuna99s993m": {
  "created": 1484634400,
  "status": "1"
  "entry": "1"
  "status_entry": "1_1"
"-Y8hj98nmswm": {
  "created": 1481623400,
  "status": "1"
  "entry": "3"
  "status_entry": "1_3"

*the node names like "-Yuna99s993m" are created with childByAutoId - it's usually best practice to disassociate node key names from the child data they contain.

The thought process here is that by combining two variables, entry # and status, into a single variable, status_entry, we limit what is returned by startingAt and endingAt. So 1_x will eliminate all of the 0_ statuses and we further limit the returned nodes by specifying entries which are from x_1 through x_3.

The trick is getting the node right before x_4 as that will be the one to be .endingAt. If it's always x_3 then it's easy.

Jay
  • 34,438
  • 18
  • 52
  • 81