Firebase queryOrderedByChild() method not giving s

2019-01-25 23:52发布

问题:

My database structure is some thing like this:

{
  "users": {
    "alovelace": {
      "name": "Ada Lovelace",
      "score": 4,
    },
    "ghopper": { ... },
    "eclarke": { ... }
  }
}

I am trying to retrieve top 20 scores in descending order.

let queryRef = FIRDatabase.database().reference().child("users").queryOrderedByChild("score").queryLimitedToLast(20)
queryRef.observeSingleEventOfType(.Value, withBlock: { (querySnapShot) in
      print(querySnapShot.value)
})

i am trying to get output like

score": 4
score": 3
score": 2

or 

score": 2
score": 3
score": 4

or 

2
3
4

Please let me know how to solve this.

回答1:

Use method observeEventType instead of observeSingleEventOfType. Also, make FIRDataEventType to ChildAdded.

Last, If you want Top 20 items, use queryLimitedToFirst instead of queryLimitedToLast.

{
  "users" : {
    "alovelace" : {
      "name" : "Ada Lovelace",
      "score" : 4
    },
    "eclarke" : {
      "name" : "Emily Clarke",
      "score" : 5
    },
    "ghopper" : {
      "name" : "Grace Hopper",
      "score" : 2
    }
  }
}

For the dataset above

let queryRef = FIRDatabase.database().reference().child("users").queryOrderedByChild("score").queryLimitedToFirst(20)
queryRef.observeEventType(.ChildAdded, withBlock: { (snapshot) in
    print("key: \(snapshot.key), value: \(snapshot.value)")
})

key: ghopper, value: Optional({ name = Grace Hopper; score = 2; })

key: alovelace, value: Optional({ name = Ada Lovelace; score = 4; })

key: eclarke, value: Optional({ name = Emily Clarke; score = 5; })

Snapshot will returns the contents as native types. Data types returned:

  • NSDictionary
  • NSArray
  • NSNumber (also includes booleans)
  • NSString

So, you can get your scores this way.

    let queryRef = FIRDatabase.database().reference().child("users").queryOrderedByChild("score").queryLimitedToFirst(20)
queryRef.observeEventType(.ChildAdded, withBlock: { (snapshot) in
    if let scores = snapshot.value as? NSDictionary {
        print(scores["score"])
    }
})

Optional(2)

Optional(4)

Optional(5)

Moreover, the default of realtime database return everything in ascending order.

If you want descending order, you can make some tricks(4:40) in your database.



回答2:

When you request the children in a specific order, the resulting snapshot will contain both the data that matches the query and information about the order in which you requested them.

But when you request the .value of the snapshot, the keys+data are converted to a Dictionary<String,AnyObject>. Since a dictionary does not have an extra place to put the information about the order, that information is lost when converting to a dictionary.

The solution is to not convert to a dictionary prematurely and instead loop over the snapshot:

queryRef.observeSingleEventOfType(.Value, withBlock: { (querySnapShot) in
    for childSnapshot in querySnapShot.children {
        print(childSnapshot.value)
    }
})

You can also listen to the .ChildAdded event, instead of .Value, in which case the children will arrive in the correct value:

queryRef.observeSingleEventOfType(.ChildAdded, withBlock: { (childSnapshot) in
    print(childSnapshot.value)
})

Update

I just added this JSON to my database:

{
  "users" : {
    "alovelace" : {
      "name" : "Ada Lovelace",
      "score" : 4
    },
    "eclarke" : {
      "name" : "Emily Clarke",
      "score" : 5
    },
    "ghopper" : {
      "name" : "Grace Hopper",
      "score" : 2
    }
  }
}

And then ran this code:

let queryRef = ref.child("users").queryOrderedByChild("score").queryLimitedToLast(20);
queryRef.observeEventType(.ChildAdded) { (snapshot) in
    print(snapshot.key)
}

The output is:

ghopper

alovelace

eclarke

Which is the users in ascending order of score.

Update to add more on getting the scores in descending order

The above code gets the 20 highest scores in ascending order. There is no API call to return themthem in descending score.

But reversing 20 items client side is no performance concern, you just need to write the code for it. See for example this answer.

If you really are stuck on reversing them client side, you can add an inverted score. See this answer for an example of that.