如何在Prisma中使用微秒精度时间戳字段作为游标?
在Prisma中使用微秒精度DateTime字段实现游标分页
你遇到的核心问题是JavaScript的Date对象仅支持毫秒精度,而Prisma默认会把数据库的Timestamp(6)字段映射为Date,导致微秒部分丢失。下面提供几种实用的解决方案:
方案1:直接查询原始字符串格式的字段
跳过Prisma的Date类型转换,直接从数据库获取带微秒的字符串形式的createdAt,完整保留精度用于游标分页。
示例代码
先保持你的schema定义不变:
model YourModel { id Int @id @default(autoincrement()) createdAt DateTime @unique @default(now()) @db.Timestamp(6) // 其他业务字段... }
查询时使用prisma.raw获取原始字符串:
// 获取分页数据,游标使用上一页最后一条的createdAt字符串 const pageData = await prisma.yourModel.findMany({ select: { id: true, createdAt: prisma.raw("CAST(createdAt AS CHAR)"), // 转换为带微秒的字符串 // 其他需要返回的字段 }, orderBy: { createdAt: "asc" }, cursor: { createdAt: lastPageCursor }, // lastPageCursor是上一页最后一条的createdAt字符串 skip: 1, take: 10, });
这种方式简单直接,完全保留微秒精度,适合需要严格依赖微秒排序的场景。
方案2:扩展Prisma客户端全局处理微秒
如果你不想每次查询都写raw,可以通过Prisma的客户端扩展功能,把createdAt字段的返回值处理为带微秒的字符串。
示例代码
- 在
schema.prisma中启用客户端扩展预览特性:
generator client { provider = "prisma-client-js" previewFeatures = ["clientExtensions"] }
- 初始化Prisma客户端时添加扩展:
import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient().$extends({ result: { yourModel: { createdAt: { needs: { createdAt: true }, compute(model) { // 从Date对象中提取微秒(注:部分数据库驱动会把微秒存在Date的额外属性中,这里以MySQL为例) const date = model.createdAt; const microseconds = (date as any).microseconds || 0; return `${date.toISOString().slice(0, 23)}${microseconds.toString().padStart(3, '0')}`; }, }, }, }, });
之后查询返回的createdAt就是带微秒的字符串,可直接用作游标。
方案3:使用复合游标(简化版)
如果业务上可以接受,没必要纠结微秒的话,建议用createdAt + id作为复合游标。因为id是唯一的,即使createdAt的微秒被截断,也能保证游标唯一性,避免分页出现重复或遗漏。
示例代码
const pageData = await prisma.yourModel.findMany({ orderBy: [ { createdAt: "asc" }, { id: "asc" }, // 用id作为第二排序条件 ], cursor: { createdAt: lastCreatedAtDate, // 这里用Date对象即可 id: lastItemId, }, skip: 1, take: 10, });
这种方式最简单,不需要额外处理精度,大部分分页场景都适用。
内容的提问来源于stack exchange,提问作者Adam A
相关产品推荐
相关产品推荐

