在社交类应用的开发中,用户之间的好友关系是非常典型的需求,这种关系在Prisma中可以通过自引用多对多关系来建模,而获取某个用户所有朋友的用户信息,就需要用到Prisma的深度关联查询能力。

自引用多对多关系的定义
首先我们需要在Prisma schema中定义用户模型以及自引用的多对多关系,Prisma会自动生成中间表来管理这种关系。下面是一个标准的用户模型定义示例:
// 定义用户模型
model User {
id Int @id @default(autoincrement())
name String
email String @unique
// 自引用多对多关系,friends表示当前用户的好友列表
friends User[] @relation("UserFriends")
// 反向关系,表示当前用户被哪些用户加为好友
friendOf User[] @relation("UserFriends")
}
上面的schema中,我们在User模型里定义了两个数组类型的字段friends和friendOf,都关联到User模型本身,使用同一个关系名UserFriends,Prisma会自动创建一个名为UserFriends的中间表,存储用户之间的好友关联关系。
基础深度关联查询实现
当我们需要获取某个用户的所有朋友的用户信息时,可以使用Prisma Client的findUnique方法结合include选项进行深度关联查询。假设我们要获取id为1的用户的所有朋友信息,代码如下:
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// 获取id为1的用户的所有朋友信息
async function getFriendsInfo() {
const userWithFriends = await prisma.user.findUnique({
where: {
id: 1
},
// 使用include进行关联查询,获取friends关联的所有用户信息
include: {
friends: true
}
})
return userWithFriends
}
// 调用函数并输出结果
getFriendsInfo().then(result => {
console.log(result)
})
上面的代码中,我们通过include: { friends: true }指定在查询用户时,同时关联查询friends字段对应的所有用户数据,返回的结果中friends字段就是一个数组,包含了该用户所有朋友的用户信息,包括id、name、email等字段。
自定义关联查询的返回字段
如果我们不需要返回朋友的所有字段,只想获取朋友的id和name,可以在include的friends字段中使用select来指定需要返回的字段,减少不必要的数据传输:
async function getFriendsBasicInfo() {
const userWithFriends = await prisma.user.findUnique({
where: {
id: 1
},
include: {
friends: {
// 只选择需要返回的字段
select: {
id: true,
name: true
}
}
}
})
return userWithFriends
}
多层深度关联查询
如果我们需要获取朋友的朋友的相关信息,还可以继续进行更深度的关联查询,只需要在friends的include中继续嵌套关联即可:
async function getFriendsOfFriends() {
const userWithFriends = await prisma.user.findUnique({
where: {
id: 1
},
include: {
friends: {
include: {
// 继续关联查询朋友的好友
friends: {
select: {
id: true,
name: true
}
}
}
}
}
})
return userWithFriends
}
查询注意事项
- 自引用多对多关系中,中间表是双向的,添加好友时需要在两个用户的关系中都添加记录,否则查询可能出现遗漏。
- 深度关联查询的层级越多,查询性能开销越大,建议根据实际需求控制关联查询的层级,避免不必要的性能损耗。
- 如果好友数量较多,可以结合
take和skip参数实现分页查询,避免一次性返回过多数据。
Prisma的深度关联查询语法非常灵活,只要理清模型之间的关联关系,就可以通过嵌套的include或select实现各种复杂的关联数据获取需求。