LoginSignup
9
5

More than 3 years have passed since last update.

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

Last updated at Posted at 2016-12-20

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)
    })

まとめ

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

注意

Original

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5