Featured image of post Prisma 知识点归纳(二)增删改查以及关系查询汇总 1W3字大章 2023

Prisma 知识点归纳(二)增删改查以及关系查询汇总 1W3字大章 2023

本文含有: Prisma 增删改查, 聚合和分组和汇总, 关系查询, connect, disconnect, 更新或创建, 关联过滤器, 过滤条件, 运算符

该文档的基础是建立在学过关系型数据库的基础上,并且以下内容是根据 API 文档进行参考编写的(没办法,概念那太零散了)。

https://prisma.yoga/getting-started

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["orderByRelation"]
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

model ExtendedProfile {
  id        Int    @id @default(autoincrement())
  biography String
  user      User   @relation(fields: [userId], references: [id])
  userId    Int    @unique
}

model User {
  id           Int              @id @default(autoincrement())
  name         String?
  email        String           @unique
  profileViews Int              @default(0)
  role         Role             @default(USER)
  coinflips    Boolean?
  posts        Post[]
  profile      ExtendedProfile?
}

model Post {
  id         Int        @id @default(autoincrement())
  title      String
  published  Boolean    @default(true)
  author     User       @relation(fields: [authorId], references: [id])
  authorId   Int
  comments   Json?
  views      Int        @default(0)
  likes      Int        @default(0)
  categories Category[]
}

model Category {
  id    Int    @id @default(autoincrement())
  name  String @unique
  posts Post[]
}

enum Role {
  USER
  ADMIN
}
npx prisma db push

npx prisma generate

基本使用

查询选项

  • 选项
    • orderBy:排序
      • asc:升序
      • desc:降序
    • distinct:去重
    • include:定义了 Prisma 客户端返回的结果中包含哪些关系。
// orderBy
const users = await prisma.user.findMany({
  orderBy: {
    email: "asc",
  },
  /*
  orderBy: [
    {
      role: 'desc',
    },
    {
      name: 'desc',
    },
  ],*/
});

// distinct
const distinctCities = await prisma.user.findMany({
  select: {
    city: true,
    country: true,
  },
  distinct: ["city"],
});

// 返回所有 User 记录按 email 排序
// 对于每个 User 记录,返回按 title 排序的所有嵌套 Post 记录的 title 字段
const usersWithPosts = await prisma.user.findMany({
  orderBy: {
    email: "asc",
  },
  include: {
    posts: {
      select: {
        title: true,
      },
      orderBy: {
        title: "asc",
      },
    },
  },
});
/* 
[
{
  "id": 2,
  "email": "alice@prisma.io",
  "name": "Alice",
  "posts": [
    {
      "title": "Watch the talks from Prisma Day 2019"
    }
  ]
},
{
  "id": 3,
  "email": "ariadne@prisma.io",
  "name": "Ariadne",
  "posts": [
    {
      "title": "How to connect to a SQLite database"
    },
    {
      "title": "My first day at Prisma"
    }
  ]
},
]
*/

创建

  • create:创建记录
    • 选项:data
    • 返回对象选项:select、include
  • createMany:创建多个记录
    • 选项:data、skipDuplicates
      • skipDuplicates:boolean,在插入唯一字段时在冲突中什么都不做。(默认 false)
const user = await prisma.user.create({
  data: { email: "alice@prisma.io" },
});
const createMany = await prisma.user.createMany({
  data: [
    { name: "Bob", email: "bob@prisma.io" },
    { name: "Bobo", email: "bob@prisma.io" }, // 唯一键重复!
    { name: "Yewande", email: "yewande@prisma.io" },
    { name: "Angelique", email: "angelique@prisma.io" },
  ],
  skipDuplicates: true, // 跳过 'Bobo'
});

查询

  • 1、findUnique:唯一条件来获取单个数据库记录

    • ID
    • 唯一(unique) 属性
    • 选项:where
    • 返回对象选项:select、include
  • 2、findFirst:返回第一个匹配您的条件的记录。

    • 选项:distinct、where、cursor、orderBy、skip、take
    • 返回对象选项:select、include
  • 3、findMany:返回列表

    • 选项:distinct、where、cursor、orderBy、skip、take
    • 返回对象选项:select、include
  • 查询特定字段

// select email,name from user
const getUser: object | null = await prisma.user.findUnique({
  where: {
    id: 1,
  },
  select: {
    email: true,
    name: true,
  },
});
  • 联合查询
// SELECT u.name,p.title FROM prisma.`User` AS u LEFT JOIN prisma.Post AS p
// ON u.id = p.authorId
const users = await prisma.user.findMany({
  select: {
    name: true,
    posts: {
      select: {
        title: true,
      },
    },
  },
});

2023-02-20-Prisma_find_many

  • 分页查询
    • skip:跳过前三个,然后返回 4 个
    • take:返回特定数量
// 分页查询
// 跳过前三个 1 2 3; 返回 4 5 6 7
const results = await prisma.post.findMany({
  skip: 3,
  take: 4,
});

更新

  • update:更新记录
    • 选项:data、where
    • 返回对象选项:select、include
  • updateMany:更新多个记录
    • 选项:data、where
  • upsert:更新或创建记录
    • 选项:create、update、where
    • 返回对象选项:select、include
// update
const user = await prisma.user.update({
  where: { id: 1 },
  data: { email: "alice@prisma.io" },
});

// updateMany
const users = await prisma.user.createMany({
  data: [
    { name: "Sonali", email: "sonali@prisma.io" },
    { name: "Alex", email: "alex@prisma.io" },
  ],
});

// 查找电子邮件地址更新 User 记录,或者如果该 User 记录不存在,则创建该记录:
const upsertUser = await prisma.user.upsert({
  where: {
    email: "viola@prisma.io",
  },
  update: {
    name: "Viola the Magnificent",
  },
  create: {
    email: "viola@prisma.io",
    name: "Viola the Magnificent",
  },
});

删除

  • delete:删除记录(只能应用于 ID 或 unique属性)
    • 选项:where
    • 返回对象选项:select、include
  • delteMany:删除多个记录
    • 选项:where
// 以下查询会删除特定用户记录并使用 select 返回被删除用户的 name 和 email:
const deleteUser = await prisma.user.delete({
  where: {
    email: "elsa@prisma.io",
  },
  select: {
    email: true,
    name: true,
  },
});

count

  • count():统计数量
    • 选项:distinct、where、cursor、orderBy、select、skip、take
const c = await prisma.user.count({
  select: {
    _all: true, // 统计记录的总数
    city: true, // 统计非 null city字段的总数
    name: true, // 统计非 null name字段的总数
  },
});

关系查询

  • 关系嵌套查询
// 1. 返回 user用户对应自己的 posts 表信息.
const getUser = await prisma.user.findUnique({
  where: {
    id: 19,
  },
  include: {
    posts: true,
  },
});

// 2. 深嵌套
// 返回 user + posts + categories
const user = await prisma.user.findMany({
  include: {
    posts: {
      include: {
        categories: true,
      },
    },
  },
});
  • 查询特定字段
// 返回 user.name, posts.title
const getUser = await prisma.user.findUnique({
  where: {
    id: 19,
  },
  select: {
    name: true,
    posts: {
      select: {
        title: true,
      },
    },
  },
});
  • 关系嵌套写入
    • 创建 User 用户时同时创建 Post,并自动传递作者 ID。
async function main() {
  let user: Prisma.UserCreateInput;

  user = {
    email: "elsa@prisma.io",
    name: "Elsa Prisma",
    posts: {
      create: {
        title: "Include this post!",
      },
    },
    include: {
      posts: true, // 返回对象包含 posts 对象
    },
  };

  // 将 'user' 对象传递到查询中
  const createUser = await prisma.user.create({ data: user });
}

connect 连接记录

  • 连接记录什么意思呢?
    • 表和表的关联,例如 user 表的用户 ID 字段与 Post 表的作者 ID 字段相互连接。
    • 简单点说就是, Post.authorId === User.id
model User {
  id           Int              @id @default(autoincrement())
  posts        Post[]
}

model Post {
  id         Int        @id @default(autoincrement())
  author     User       @relation(fields: [authorId], references: [id])
  authorId   Int
}
  • 连接现有记录 connect
    • 例:创建一个新用户,并把 Post 中的 id 为 8 9 10 的 作者 ID 更改为他。
const user = await prisma.user.create({
  data: {
    email: "vlad@prisma.io",
    posts: {
      connect: [{ id: 8 }, { id: 9 }, { id: 10 }],
    },
  },
  include: {
    posts: true, // 包括返回对象中的所有帖子
  },
});
  • 连接现有记录 connect
    • 将现有帖子(id:11)连接到现有用户(id:9
    • 添加一个新的相关帖子(title: "My new post title"
const getUser = await prisma.user.update({
  where: {
    id: 9,
  },
  data: {
    posts: {
      connect: {
        id: 11,
      },
      create: {
        title: "My new post title",
      },
    },
  },
});
  • 连接或创建 connectOrCreate
    • 当不清楚记录是否存在时,就用这个。
// 存在 "viola@prisma.io" 则使用,否则就创建新的
const createPost = await prisma.post.create({
  data: {
    title: "How to make croissants",
    author: {
      connectOrCreate: {
        where: {
          email: "viola@prisma.io",
        },
        create: {
          email: "viola@prisma.io",
          name: "Viola",
        },
      },
    },
  },
  include: {
    author: true,
  },
});

disconnect 断开连接

  • 断开连接什么意思?

    • 中断父记录和相关记录之间的连接,但不会删除任一记录。
    • 仅在关系是可选的情况下可用。
  • 断开连接 disconnect

// 1.
const updatePost = await prisma.user.update({
  where: {
    id: 16,
  },
  data: {
    posts: {
      disconnect: [{ id: 12 }, { id: 19 }],
    },
  },
  select: {
    posts: true,
  },
});

// 2. 当为一条记录的时候, 使用 true
// 例如 profile?
const user = await prisma.user.update({
  where: { email: "bob  @prisma.io" },
  data: {
    profile: {
      disconnect: true,
    },
  },
});
  • 断开所有连接 set:[]
const updateUser = await prisma.user.update({
  where: {
    id: 16,
  },
  data: {
    posts: {
      set: [],
    },
  },
  include: {
    posts: true,
  },
});
  • 删除所有记录
  • 删除特定相关记录
// 删除所有
const update = await prisma.user.update({
  where: {
    id: 11,
  },
  data: {
    posts: {
      deleteMany: {},
    },
  },
});

// 删除所有 "published: false" 的 Post
const update = await prisma.user.update({
  where: {
    id: 11,
  },
  data: {
    posts: {
      deleteMany: {
        published: false,
      },
    },
  },
});

// 特定用户
const update = await prisma.user.update({
  where: {
    id: 6,
  },
  data: {
    posts: {
      deleteMany: [{ id: 7 }],
    },
  },
});

更新或创建

  • update
// 将关联用户ID为6的所有, Post 的 published 值变为 false
const update = await prisma.user.update({
  where: {
    id: 6,
  },
  data: {
    posts: {
      updateMany: {
        where: {
          published: true,
        },
        data: {
          published: false,
        },
      },
    },
  },
});
  • upset
// 更新或创建 PostID 为 6 的所关联的 用户信息
const update = await prisma.post.update({
  where: {
    id: 6,
  },
  data: {
    author: {
      upsert: {
        create: {
          email: "bob@prisma.io",
          name: "Bob the New User",
        },
        update: {
          email: "bob@prisma.io",
          name: "Bob the existing user",
        },
      },
    },
  },
});
  • createMany
const user = await prisma.user.update({
  where: {
    id: 9,
  },
  data: {
    posts: {
      createMany: {
        data: [{ title: "My first post" }, { title: "My second post" }],
      },
    },
  },
});

关联过滤器

  • some:至少有一个
  • none:否定(取反)
  • every:一个都没有

操作符:gt、lt、gte、lte(大于、小于、大于等于、小于等于)

// 返回没有文章的用户
const usersWithZeroPosts = await prisma.user.findMany({
  where: {
    posts: {
      none: {},
    },
  },
});

// 返回至少有一篇文章的用户
const usersWithSomePosts = await prisma.user.findMany({
  where: {
    posts: {
      some: {},
    },
  },
});

// 返回 `views`不超过100, `likes`小于等于 50 的
const users = await prisma.user.findMany({
  where: {
    posts: {
      none: {
        views: {
          gt: 100,
        },
      },
      every: {
        likes: {
          lte: 50,
        },
      },
    },
  },
});
  • is
  • isNot
// 名字不是"Bob", 年龄大于 40
const users = await prisma.post.findMany({
  where: {
    author: {
      isNot: {
        name: "Bob",
      },
      is: {
        age: {
          gt: 40,
        },
      },
    },
  },
});

过滤条件

  • 不区分大小写
    • mode: 'insensitive'
    • 仅支持 PostgreSQL 和 MongoDB 连接器
const users = await prisma.user.findMany({
  where: {
    email: {
      endsWith: "prisma.io",
      mode: "insensitive", // Default value: default
    },
  },
});
  • not
  • in:[]notIn:[]
  • gt、lt、gte、lte、ne(大于、小于、大于等于、小于等于、不等于)
  • contains:模糊查询
  • startsWith:匹配开头
  • endsWith:匹配结尾
const result = await prisma.user.findMany({
  where: {
    name: { not: "Eleanor" },
    id: { in: [22, 91, 14, 2, 5] },
    id: { notIn: [22, 91, 14, 2, 5] },
  },
});

const result = await prisma.post.count({
  where: {
    content: {
      contains: "databases",
    },
  },
});

运算符

  • AND:所有条件必须返回 true
  • NOT:所有条件必须返回 false
  • OR:至少一个条件必须返回 true
// email 以 "prisma.io" 或 "gmail.com" 结尾,但不以 "hotmail.com" 结尾
const result = await prisma.user.findMany({
  where: {
    OR: [
      {
        email: {
          endsWith: "prisma.io",
        },
      },
      { email: { endsWith: "gmail.com" } },
    ],
    NOT: {
      email: {
        endsWith: "hotmail.com",
      },
    },
  },
  select: {
    email: true,
  },
});

聚合、分组和汇总

  • 聚合 aggregate
// 求年龄平均值
const aggregations = await prisma.user.aggregate({
  _avg: {
    age: true,
  },
});

// 与过滤结合起来
const aggregations = await prisma.user.aggregate({
  _avg: {
    age: true,
  },
  where: {
    email: {
      contains: "prisma.io",
    },
  },
  orderBy: {
    age: "asc",
  },
  take: 10,
});

console.log("Average age:" + aggregations._avg.age);
  • 分组
// 返回每个国家的个人资料浏览总数
const groupUsers = await prisma.user.groupBy({
  by: ["country"],
  _sum: {
    profileViews: true,
  },
});
/*
;[
  { country: 'Germany', _sum: { profileViews: 126 } },
  { country: 'Sweden', _sum: { profileViews: 0 } },
]
*/

原始数据库访问

MongoDB 不支持

const email = "emelie@prisma.io";

const result =
  await prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}`;

const result = await prisma.$queryRaw(
  Prisma.sql`SELECT * FROM User WHERE email = ${email}`
);
Licensed under CC BY-NC-SA 4.0
本博客已稳定运行
发表了53篇文章 · 总计28.17k字
使用 Hugo 构建
主题 StackJimmy 设计