Prisma 游标分页

Flying
2024-04-10 / 0 评论 / 31 阅读 / 正在检测是否收录...

Prisma ORM 是一个 Node.js 和T ypeScript 的 ORM,具有直观的数据模型、自动迁移、类型安全和自动补全功能。Prisma ORM一大亮点就是支持游标分页。游标分页使用 cursor 和 take 在给定游标之前或之后返回一组有限的结果,因此相对于传统的偏移分页具有更高的性能。

游标标记你在结果集中的位置,必须是唯一且连续的列 - 例如 ID 或时间戳。

prisma.svg

✔ 游标分页的优点

游标分页具有扩展性。底层 SQL 不使用 OFFSET,而是查询所有 ID 大于游标值的 Post 记录。

✘ 游标分页的缺点

你必须按游标排序,而游标必须是唯一且连续的列。
你无法仅使用游标跳转到特定页面。例如,你无法准确预测哪个游标代表第 400 页(每页 20 条记录)的起始位置,而无需先请求第 1 - 399 页。

游标分页的使用场景

  • 无限滚动 - 例如,按日期/时间降序排序博客文章,并一次请求 10 篇博客文章。
  • 分批遍历整个结果集 - 例如,作为长时间运行的数据导出的一部分。

示例

这里是使用 Prisma 实现游标分页的示例代码。

Prisma 模式 (示例)

假设你有以下 User 模型:

model User {
  id    Int    @id @default(autoincrement())
  name  String
  email String @unique
  // 其他字段...
  createdAt DateTime @default(now())
}

游标分页查询

要实现游标分页,你需要在 Prisma 中使用 cursortakeskip 参数。

const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();

async function getUsers(cursor = null, pageSize = 10) {
  let queryOptions = {
    take: pageSize + 1, // 多获取一个项来检查是否有下一页
    orderBy: {
      id: 'asc', // 确保顺序一致
    },
  };

  if (cursor) {
    queryOptions = {
      ...queryOptions,
      cursor: {
        id: cursor,
      },
      skip: 1, // 跳过游标本身
    };
  }

  const users = await prisma.user.findMany(queryOptions);

  const hasNextPage = users.length > pageSize;
  if (hasNextPage) {
    users.pop(); // 如果多获取了一个项,移除它
  }

  return {
    users: users,
    hasNextPage: hasNextPage,
    nextCursor: hasNextPage ? users[users.length - 1].id : null,
  };
}

// 示例使用
getUsers(null, 10).then(result => {
  console.log(result);
}).catch(error => {
  console.error(error);
}).finally(() => {
  prisma.$disconnect();
});

解释

  1. 初始查询设置:

    • 设置查询以获取 pageSize + 1 项。多获取一个项有助于确定是否有下一页。
    • 通过 id 排序以确保顺序一致。
    let queryOptions = {
      take: pageSize + 1,
      orderBy: {
        id: 'asc',
      },
    };
  2. 处理游标:

    • 如果提供了游标,更新查询以从游标之后开始。
    • 使用 skip: 1 跳过游标本身。
    if (cursor) {
      queryOptions = {
        ...queryOptions,
        cursor: {
          id: cursor,
        },
        skip: 1,
      };
    }
  3. 获取数据并确定 hasNextPage

    • 从数据库中获取用户。
    • 通过检查结果的长度是否大于 pageSize 来确定是否有下一页。
    • 如果有下一页,移除多获取的项以返回正确数量的项。
    const users = await prisma.user.findMany(queryOptions);
    
    const hasNextPage = users.length > pageSize;
    if (hasNextPage) {
      users.pop();
    }
  4. 返回结果:

    • 返回用户数据、一个指示是否有下一页的标志以及下一页的游标。
    return {
      users: users,
      hasNextPage: hasNextPage,
      nextCursor: hasNextPage ? users[users.length - 1].id : null,
    };

示例使用

示例用法获取第一页的用户。你可以调整 cursor 参数来获取后续的页面。

getUsers(null, 10).then(result => {
  console.log(result);
}).catch(error => {
  console.error(error);
}).finally(() => {
  prisma.$disconnect();
});

通过这种方法,你可以使用 Prisma 实现高效的游标分页。每个查询都从指定的游标开始获取固定数量的项,这对于大数据集来说非常理想,因为偏移分页在处理大数据量时可能效率不高。

链接

1

评论 (0)

取消