如何在Prisma中获取列表首元素优化Next.js API性能
问题
在Next.js项目中,通过API路由使用Prisma获取设备列表时,每个设备的brand属性携带大量图片数据,导致JSON payload过大,影响应用性能。需要优化查询逻辑,仅返回每个brand的第一张图片,以此减小payload体积、提升用户体验。
相关Prisma模型(简化)
model Equipment { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") title String @db.VarChar(255) // 省略其他属性 brand Brand? @relation(fields: [brandId], references: [id], onDelete: Cascade) brandId Int? @map("brand_id") images EquipmentImage[] @@map("equipments") }
当前查询代码
const equipments = await prisma.equipment.findMany({ where: { published: true, category: { ...(slug && { slug: slug as string, }), }, }, include: { subcategory: { select: { id: true, slug: true, category: { select: { slug: true, }, }, }, }, images: true, brand: { select: { id: true, images: true, // 需要修改的部分 }, }, }, });
问题表现
返回的设备数据中,brand.images包含多张图片,示例片段如下:
{ "id": 66, "title": "SY16C", "brand": { "id": 1, "images": [ { "id": 16, "fileName": "SANY-4tu5s2li.png", /* 其他图片字段 */ }, { "id": 29, "fileName": "SANY-nwffhrfd.jpeg", /* 其他图片字段 */ }, // 更多图片数据 ] } }
解决方案
提供两种实用实现方案,按需选择:
方案1:通过Prisma查询直接限制图片数量
利用Prisma关联查询的take参数,直接从数据库层面只获取brand的第一张图片,配合orderBy可确保取到特定排序的图片(比如最早创建的)。
修改后的查询代码:
const equipments = await prisma.equipment.findMany({ where: { published: true, category: { ...(slug && { slug: slug as string, }), }, }, include: { subcategory: { select: { id: true, slug: true, category: { select: { slug: true, }, }, }, }, images: true, brand: { select: { id: true, images: { take: 1, // 仅获取第一张图片 orderBy: { createdAt: 'asc' } // 可选:按创建时间升序,保证取到固定的首张图片 }, }, }, }, });
此方案返回的brand.images是仅含单张图片的数组,若需单个对象而非数组,可结合方案2的后处理逻辑。
方案2:查询后处理数据结构
如果需要调整返回的数据结构(比如将图片数组转为单个对象),可在查询完成后遍历设备列表,修改brand字段:
// 原查询逻辑不变,先获取完整数据 const equipments = await prisma.equipment.findMany({ where: { published: true, category: { ...(slug && { slug: slug as string, }), }, }, include: { subcategory: { select: { id: true, slug: true, category: { select: { slug: true, }, }, }, }, images: true, brand: { select: { id: true, images: true, }, }, }, }); // 处理数据,仅保留brand的第一张图片并调整结构 const processedEquipments = equipments.map(equipment => { if (!equipment.brand) return equipment; return { ...equipment, brand: { ...equipment.brand, image: equipment.brand.images[0] || null, // 将数组转为单个image对象 images: undefined // 移除原图片数组 } }; });
这种方式适合需要前端直接使用单个图片对象的场景,减少前端额外处理步骤。
内容的提问来源于stack exchange,提问作者Aghilesdza
相关产品推荐
相关产品推荐

