You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI + CosmosDB场景下基于Python SDK按指定页码获取分页数据

Cosmos DB Python SDK 实现按指定页码查询的方案

Cosmos DB 底层采用延续令牌(Continuation Token)实现分页,本身不支持原生的 OFFSET 分页语法,无法直接通过指定页码一步查询到对应数据,你贴的官方示例已经展示了延续令牌的核心用法,我们可以基于该能力做二次封装实现按页码查询。

方案1:小数据量场景直接遍历到目标页码

适合页码数值小、分页查询频率低的场景,实现最简单,不需要额外存储。

from fastapi import FastAPI
from azure.cosmos import CosmosClient

app = FastAPI()
# 初始化Cosmos客户端,参数替换为自身配置即可
cosmos_client = CosmosClient("<你的Cosmos DB服务端点>", "<你的访问密钥>")
db = cosmos_client.get_database_client("<数据库名称>")
container = db.get_container_client("<容器名称>")

def get_page_by_num(partition_key: str, query: str, page_size: int, target_page: int):
    # 构造查询迭代器,指定单页返回数据量
    query_iterable = container.query_items(
        query=query,
        partition_key=partition_key,
        max_item_count=page_size
    )
    pager = query_iterable.by_page()
    current_page = 1
    target_page_items = []
    # 逐页遍历直到到达目标页码
    while current_page <= target_page:
        try:
            current_page_items = list(pager.next())
            # 已经遍历完所有数据仍未到目标页码,返回空
            if not current_page_items:
                return []
            target_page_items = current_page_items
            current_page += 1
        except StopIteration:
            return []
    return target_page_items

# FastAPI接口调用示例
@app.get("/items")
def list_items(page: int = 1, page_size: int = 10, partition_key: str = "pk"):
    query = "SELECT * FROM c"
    items = get_page_by_num(partition_key, query, page_size, page)
    return {"items": items, "page": page, "page_size": page_size}
  • 优点:实现逻辑简单无额外依赖,不需要额外存储资源
  • 缺点:页码越大查询耗时越长,需要从第一页开始逐页遍历到目标页,不适合大页码、高频查询的场景

方案2:生产级方案:缓存页码与延续令牌映射

适合高频分页、大页码场景,核心是把每次查询得到的延续令牌和对应页码绑定缓存,后续查询同条件的指定页码时直接取缓存的延续令牌查询,不需要从头遍历。
以下是基于Redis做缓存的实现示例:

import redis
redis_client = redis.Redis(host="localhost", port=6379, db=0)

def get_page_by_num_with_cache(partition_key: str, query: str, page_size: int, target_page: int):
    # 生成唯一缓存键,需把所有影响查询结果的条件都拼接进去
    cache_key = f"cosmos_page:{hash(f'{partition_key}{query}{page_size}')}"
    # 先查缓存有没有目标页码前一页的延续令牌
    continuation_token = redis_client.get(f"{cache_key}:{target_page-1}")
    query_iterable = container.query_items(
        query=query,
        partition_key=partition_key,
        max_item_count=page_size
    )
    # 命中缓存直接用令牌取对应页
    if continuation_token:
        pager = query_iterable.by_page(continuation_token.decode())
        return list(pager.next())
    # 未命中缓存则逐页遍历,同时写入缓存
    pager = query_iterable.by_page()
    current_page = 1
    target_page_items = []
    while current_page <= target_page:
        try:
            current_page_items = list(pager.next())
            if not current_page_items:
                return []
            # 缓存当前页对应的下一页延续令牌,有效期1小时可自行调整
            if pager.continuation_token:
                redis_client.setex(f"{cache_key}:{current_page}", 3600, pager.continuation_token)
            target_page_items = current_page_items
            current_page += 1
        except StopIteration:
            return []
    return target_page_items

注意事项:

  • 数据有新增/删除/更新时,需要清空对应查询条件的缓存,避免页码和数据对应错乱
  • 缓存过期时间可根据业务数据的更新频率灵活调整

内容的提问来源于stack exchange,提问作者SLN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 16:06:01