iOS
Firebase
FirebaseDay 20

Priorityを使ったページングと新着監視の手法

More than 1 year has passed since last update.

Priorityを使ったページングについてご紹介します


Priorityとは

データに対して設定する優先度のことで、

queryOrderedByPriorityを使用してデータを並べ替えることができます。

また、設定する優先度は数値または文字列のみで、並べ替えは以下のルールで行われます。


queryOrderedByPriority



  • 優先度を持たない子(デフォルト)が最初に来ます。

  • 優先度として数値を持つ子が次に来ます。該当する子は優先度の数値で昇順に並べ替えられます。

  • 優先度として文字列を持つ子が最後に来ます。該当する子は優先度で辞書順に並べ替えられます。

  • 2 つの子が同じ優先度を持つ場合(ともに優先度を持たない場合も含む)、キーで並べ替えられます。数値キーが最初に来て(数値で昇順に並べ替えられます)、残りのキーが続きます(辞書順で昇順に並べ替えられます)。


優先度の値に使用できるのは、数値たは文字列だけです。数値の優先度は IEEE 754 倍精度浮動小数点数として保存され、並べ替えられます。キーは常に文字列として保存され、数値として扱われるのは 32 ビット整数として解析できるときだけです。


ページングUnixTimeを使うので、数値のみ利用します。


デフォルトのデータの並び順

Firebaseコンソール上でデータを1から順に追加すると以下のようになります。

スクリーンショット 2016-12-20 15.56.12.png


UnixTimeを元に出した値をpriorityに設定する

データを書き込む際には、TimestampMaxから時間を引いた値を使用します。

Priorityは値が小さいほど優先度が高い仕様のため、TimestampMax - unixtimeをすることで、値は小さくなります。

struct FIRPriority {

static let maxPriority:Int64 = 0
static let timestampMax:Int64 = 9999999999999 // UnixTimeより大きい値
func getPriority() -> Double {
return Double(FIRPriority.timestampMax - Date.currentTimeMillis())
}
}


新着取得方法

Priority順に並び替え先頭からLimit分だけ取得するようにします。

最後のoffsetは次のページングする際に利用するので変数で保持しておきます。

let limit:UInt = 20

var offset = NSNumber(value: 0)
FIRDatabase.database().reference(withPath: "path")
.queryOrderedByPriority() // priority順に並び替え
.queryStarting(atValue: offset)
.queryLimited(toFirst: limit)
.observeSingleEvent(of: .value, with: { snapshot in
guard let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] else {
return
}
offset = snapshot.last?.priority as! NSNumber
})


ページング

1つ前で説明した新着取得方法とほぼ同じですが、offsetの部分が違います。

let limit:UInt = 20

var offset = NSNumber(value: 0)
FIRDatabase.database().reference(withPath: "path")
.queryOrderedByPriority() // priority順に並び替え
.queryStarting(atValue: NSNumber(value: offset.int64Value + 1)) // 最後に取得したデータの次Priorityを設定
.queryLimited(toFirst: limit)
.observeSingleEvent(of: .value, with: { snapshot in
guard let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] else {
return
}
offset = snapshot.last?.priority as! NSNumber
})


新着監視方法

新着のみをイベントで受け取りたい場合、

これから書き込まれた時に設定される未来のpriority値を範囲として監視すれば良いので

以下のようになります。

FIRDatabase.database().reference(withPath: "path")

.queryOrderedByPriority() // priority順に並び替え
.queryStarting(atValue: FIRPriority.maxPriority) // 0から
.queryEnding(atValue: NSNumber(value: offset.int64Value + 1)) // 最新データのpriorityに+1したもの
.observe(.childAdded, with: { snapshot in
var addedCount = 0
if let data = snapshot.value as? NSDictionary {
// MEMO:Dict to Object
addedCount += 1
}
print(addedCount)
})


まとめ

共通化などする余地はありますが、基本的な取得方法はこのようになります。


注意