Closed13

Deno KVのcursorを調べる

hashrockhashrock

Deno KVの場合、次のページがあるかどうかを取得するため一つ多めに取る、って聞いたことがあったけど、今それ有効なのかな?saaskitではやってなさそうに見えるが…

hashrockhashrock

ともかく使ってみよう。

const kv = await Deno.openKv("test")

async function insert(num: number){
  for (let i = 0; i < num; i++) {
    await kv.set(["users", i], "hello")
  }
}

// 100個set
await insert(100)

// 取得
const users = await kv.list<string>({prefix: ["users"]}, {limit: 10})

for await (const user of users){
  console.log(user)
}

console.log("cursor:", users.cursor)

cursor: IcAiAAAAAAAA

あ、これもともとbase64表現で入るのか

hashrockhashrock

んん?
limit: 100だとcursorが帰って来るが

const users = await kv.list<string>({prefix: ["users"]}, {limit: 100})

cursor: IcBYwAAAAAAA

limit: 101だと空白が返ってくる

const users = await kv.list<string>({prefix: ["users"]}, {limit: 101})

cursor:

hashrockhashrock

つまりlimit: 100なのに101個目を走査するのはコストが余分にかかるが、limit: 101なら終端であることを返せるのか。であるならissueのコメント通り。

ということは、100個入っているDBでRead moreを出さないようにするには、101個走査しないといけない。ただしmaxの個数をiteratorで読みきらずに、最後から一つ前のcursorを返してあげないと、次のページに行ったときのindexがずれてしまう。

hashrockhashrock

こんな感じにしてみた。
limit = 9なら9個取ったあとにもう一つ読めるcursorを返す。
limit = 10ならcursor=""を返す。

const kv = await Deno.openKv("test")

async function insert(num: number){
  for (let i = 0; i < num; i++) {
    await kv.set(["users", i], "hello")
  }
}

// 100個set
await insert(10)

const limit = 9

// 取得
const iter = await kv.list<string>({prefix: ["users"]}, {limit: limit + 1})
let cursor = ""
const result = []

for(let i = 0; i < limit ; i++){
  const item = await iter.next()
  if(item.done) break
  result.push(item)
  cursor = iter.cursor

  // 末尾なら一つ先まで読み込む
  if(i === limit - 1){
    const next = await iter.next()
    // ひとつ先がなければcursorは空で返す
    if(next.done) {
      cursor = ""
    }
    break
  }
}
console.log("result", result)
console.log("cursor", cursor)


console.log("次が取れるか?")
const nextResult = await kv.list({prefix: ["users"]}, {limit: 10, cursor: cursor})
console.log(await nextResult.next())
hashrockhashrock

まあでも、スクロールをトリガーにした自動fetchをするのであれば、この挙動を実装しなくてもいいかもしれない。fetchもほとんど一瞬で終わるだろうし。

hashrockhashrock

kiviでは面倒になって結局実装しなかった。いきなり100件fetchしてるからあんまりread moreしないだろうとの判断でそこは放っておいた。やるなら何かしらのDBフレームワーク内で処理されたほうがいいような感じだなあ。

このスクラップは4ヶ月前にクローズされました