数据检索/查找器

Finder 方法旨在从数据库查询数据. 他们 返回简单的对象,而是返回模型实例. 因为 finder 方法返回模型实例,你可以按照 实例 的文档中所述,为结果调用任何模型实例成员.

在本文中,我们将探讨 finder 方法可以做什么:

find - 搜索数据库中的一个特定元素

  1. // 搜索已知的ids
  2. Project.findByPk(123).then(project => {
  3. // project 将是 Project的一个实例,并具有在表中存为 id 123 条目的内容.
  4. // 如果没有定义这样的条目,你将获得null
  5. })
  6. // 搜索属性
  7. Project.findOne({ where: {title: 'aProject'} }).then(project => {
  8. // project 将是 Projects 表中 title 为 'aProject' 的第一个条目 || null
  9. })
  10. Project.findOne({
  11. where: {title: 'aProject'},
  12. attributes: ['id', ['name', 'title']]
  13. }).then(project => {
  14. // project 将是 Projects 表中 title 为 'aProject' 的第一个条目 || null
  15. // project.get('title') 将包含 project 的 name
  16. })

findOrCreate - 搜索特定元素或创建它(如果不可用)

方法 findOrCreate 可用于检查数据库中是否已存在某个元素. 如果是这种情况,则该方法将生成相应的实例. 如果元素不存在,将会被创建.

如果是这种情况,则该方法将导致相应的实例. 如果元素不存在,将会被创建.

假设我们有一个空的数据库,一个 User 模型有一个 usernamejob.

where 参数将添加到创建的案例的 defaults.

  1. User
  2. .findOrCreate({where: {username: 'sdepold'}, defaults: {job: 'Technical Lead JavaScript'}})
  3. . then(([user, created]) => {
  4. console.log(user.get({
  5. plain: true
  6. }))
  7. console.log(created)
  8. /*
  9. findOrCreate 返回一个包含已找到或创建的对象的数组,找到或创建的对象和一个布尔值,如果创建一个新对象将为true,否则为false,像这样:
  10. [ {
  11. username: 'sdepold',
  12. job: 'Technical Lead JavaScript',
  13. id: 1,
  14. createdAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET),
  15. updatedAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET)
  16. },
  17. true ]
  18. 在上面的例子中,第三行的数组将分成2部分,并将它们作为参数传递给回调函数,在这种情况下将它们视为 "user" 和 "created" .(所以“user”将是返回数组的索引0的对象,并且 "created" 将等于 "true".)
  19. */
  20. })

代码创建了一个新的实例. 所以当我们已经有一个实例了 …

  1. User.create({ username: 'fnord', job: 'omnomnom' })
  2. .then(() => User.findOrCreate({where: {username: 'fnord'}, defaults: {job: 'something else'}}))
  3. .then(([user, created]) => {
  4. console.log(user.get({
  5. plain: true
  6. }))
  7. console.log(created)
  8. /*
  9. 在这个例子中,findOrCreate 返回一个如下的数组:
  10. [ {
  11. username: 'fnord',
  12. job: 'omnomnom',
  13. id: 2,
  14. createdAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET),
  15. updatedAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET)
  16. },
  17. false
  18. ]
  19. 由findOrCreate返回的数组通过第三行的数组扩展为两部分,并且这些部分将作为2个参数传递给回调函数,在这种情况下将其视为 "user" 和 "created" .(所以“user”将是返回数组的索引0的对象,并且 "created" 将等于 "false".)
  20. */
  21. })

…现有条目将不会更改. 看到第二个用户的 “job”,并且实际上创建操作是假的.

findAndCountAll - 在数据库中搜索多个元素,返回数据和总计数

这是一个方便的方法,它结合了 findAllcount(见下文),当处理与分页相关的查询时,这是有用的,你想用 limitoffset 检索数据,但也需要知道总数与查询匹配的记录数:

处理程序成功将始终接收具有两个属性的对象:

  • count - 一个整数,总数记录匹配where语句和关联的其它过滤器
  • rows - 一个数组对象,记录在limit和offset范围内匹配where语句和关联的其它过滤器,
  1. Project
  2. .findAndCountAll({
  3. where: {
  4. title: {
  5. [Op.like]: 'foo%'
  6. }
  7. },
  8. offset: 10,
  9. limit: 2
  10. })
  11. .then(result => {
  12. console.log(result.count);
  13. console.log(result.rows);
  14. });

它支持 include. 只有标记为 required 的 include 将被添加到计数部分:

假设你想查找附有个人资料的所有用户:

  1. User.findAndCountAll({
  2. include: [
  3. { model: Profile, required: true }
  4. ],
  5. limit: 3
  6. });

因为 Profile 的 include 有 required 设置,这将导致内部连接,并且只有具有 profile 的用户将被计数. 如果我们从 include 中删除required,那么有和没有 profile 的用户都将被计数. 在include中添加一个 where 语句会自动使它成为 required:

  1. User.findAndCountAll({
  2. include: [
  3. { model: Profile, where: { active: true }}
  4. ],
  5. limit: 3
  6. });

上面的查询只会对具有 active profile 的用户进行计数,因为在将 where 语句添加到 include 时,required 被隐式设置为 true.

传递给 findAndCountAll 的 options 对象与 findAll 相同(如下所述).

findAll - 搜索数据库中的多个元素

  1. // 找到多个条目
  2. Project.findAll().then(projects => {
  3. // projects 将是所有 Project 实例的数组
  4. })
  5. // 搜索特定属性 - 使用哈希
  6. Project.findAll({ where: { name: 'A Project' } }).then(projects => {
  7. // projects将是一个具有指定 name 的 Project 实例数组
  8. })
  9. // 在特定范围内进行搜索
  10. Project.findAll({ where: { id: [1,2,3] } }).then(projects => {
  11. // projects将是一系列具有 id 1,2 或 3 的项目
  12. // 这实际上是在做一个 IN 查询
  13. })
  14. Project.findAll({
  15. where: {
  16. id: {
  17. [Op.and]: {a: 5}, // 且 (a = 5)
  18. [Op.or]: [{a: 5}, {a: 6}], // (a = 5 或 a = 6)
  19. [Op.gt]: 6, // id > 6
  20. [Op.gte]: 6, // id >= 6
  21. [Op.lt]: 10, // id < 10
  22. [Op.lte]: 10, // id <= 10
  23. [Op.ne]: 20, // id != 20
  24. [Op.between]: [6, 10], // 在 6 和 10 之间
  25. [Op.notBetween]: [11, 15], // 不在 11 和 15 之间
  26. [Op.in]: [1, 2], // 在 [1, 2] 之中
  27. [Op.notIn]: [1, 2], // 不在 [1, 2] 之中
  28. [Op.like]: '%hat', // 包含 '%hat'
  29. [Op.notLike]: '%hat', // 不包含 '%hat'
  30. [Op.iLike]: '%hat', // 包含 '%hat' (不区分大小写) (仅限 PG)
  31. [Op.notILike]: '%hat', // 不包含 '%hat' (仅限 PG)
  32. [Op.overlap]: [1, 2], // && [1, 2] (PG数组重叠运算符)
  33. [Op.contains]: [1, 2], // @> [1, 2] (PG数组包含运算符)
  34. [Op.contained]: [1, 2], // <@ [1, 2] (PG数组包含于运算符)
  35. [Op.any]: [2,3], // 任何数组[2, 3]::INTEGER (仅限 PG)
  36. },
  37. status: {
  38. [Op.not]: false, // status 不为 FALSE
  39. }
  40. }
  41. })

复合过滤 / OR / NOT 查询

你可以使用多层嵌套的 AND,OR 和 NOT 条件进行一个复合的 where 查询. 为了做到这一点,你可以使用 or , andnot 运算符:

  1. Project.findOne({
  2. where: {
  3. name: 'a project',
  4. [Op.or]: [
  5. { id: [1,2,3] },
  6. { id: { [Op.gt]: 10 } }
  7. ]
  8. }
  9. })
  10. Project.findOne({
  11. where: {
  12. name: 'a project',
  13. id: {
  14. [Op.or]: [
  15. [1,2,3],
  16. { [Op.gt]: 10 }
  17. ]
  18. }
  19. }
  20. })

这两段代码将生成以下内容:

  1. SELECT *
  2. FROM `Projects`
  3. WHERE (
  4. `Projects`.`name` = 'a project'
  5. AND (`Projects`.`id` IN (1,2,3) OR `Projects`.`id` > 10)
  6. )
  7. LIMIT 1;

not 示例:

  1. Project.findOne({
  2. where: {
  3. name: 'a project',
  4. [Op.not]: [
  5. { id: [1,2,3] },
  6. { array: { [Op.contains]: [3,4,5] } }
  7. ]
  8. }
  9. });

将生成:

  1. SELECT *
  2. FROM `Projects`
  3. WHERE (
  4. `Projects`.`name` = 'a project'
  5. AND NOT (`Projects`.`id` IN (1,2,3) OR `Projects`.`array` @> ARRAY[3,4,5]::INTEGER[])
  6. )
  7. LIMIT 1;

用限制,偏移,顺序和分组操作数据集

要获取更多相关数据,可以使用限制,偏移,顺序和分组:

  1. // 限制查询的结果
  2. Project.findAll({ limit: 10 })
  3. // 跳过前10个元素
  4. Project.findAll({ offset: 10 })
  5. // 跳过前10个元素,并获取2个
  6. Project.findAll({ offset: 10, limit: 2 })

分组和排序的语法是相同的,所以下面只用一个单独的例子来解释分组,而其余的则是排序. 你下面看到的所有内容也可以对分组进行

  1. Project.findAll({order: [['title', 'DESC']]})
  2. // 生成 ORDER BY title DESC
  3. Project.findAll({group: 'name'})
  4. // 生成 GROUP BY name

请注意,在上述两个示例中,提供的字符串逐字插入到查询中,所以不会转义列名称. 当你向 order / group 提供字符串时,将始终如此. 如果要转义列名,你应该提供一个参数数组,即使你只想通过单个列进行 order / group

  1. something.findOne({
  2. order: [
  3. // 将返回 `name`
  4. ['name'],
  5. // 将返回 `username` DESC
  6. ['username', 'DESC'],
  7. // 将返回 max(`age`)
  8. sequelize.fn('max', sequelize.col('age')),
  9. // 将返回 max(`age`) DESC
  10. [sequelize.fn('max', sequelize.col('age')), 'DESC'],
  11. // 将返回 otherfunction(`col1`, 12, 'lalala') DESC
  12. [sequelize.fn('otherfunction', sequelize.col('col1'), 12, 'lalala'), 'DESC'],
  13. // 将返回 otherfunction(awesomefunction(`col`)) DESC,这个嵌套是可以无限的!
  14. [sequelize.fn('otherfunction', sequelize.fn('awesomefunction', sequelize.col('col'))), 'DESC']
  15. ]
  16. })

回顾一下,order / group数组的元素可以是以下内容:

  • String - 将被引用
  • Array - 第一个元素将被引用,第二个将被逐字地追加
  • Object -
    • raw 将被添加逐字引用
    • 如果未设置 raw,一切都被忽略,查询将失败
  • Sequelize.fn 和 Sequelize.col 返回函数和引用的列名

原始查询

有时候,你可能会期待一个你想要显示的大量数据集,而无需操作. 对于你选择的每一行,Sequelize 创建一个具有更新,删除和获取关联等功能的实例.如果你有数千行,则可能需要一些时间. 如果你只需要原始数据,并且不想更新任何内容,你可以这样做来获取原始数据.

  1. // 你期望从数据库的一个巨大的数据集,
  2. // 并且不想花时间为每个条目构建DAO?
  3. // 你可以传递一个额外的查询参数来取代原始数据:
  4. Project.findAll({ where: { ... }, raw: true })

count - 计算数据库中元素的出现次数

还有一种数据库对象计数的方法:

  1. Project.count().then(c => {
  2. console.log("There are " + c + " projects!")
  3. })
  4. Project.count({ where: {'id': {[Op.gt]: 25}} }).then(c => {
  5. console.log("There are " + c + " projects with an id greater than 25.")
  6. })

max - 获取特定表中特定属性的最大值

这里是获取属性的最大值的方法:

  1. /*
  2. 我们假设3个具有属性年龄的对象.
  3. 第一个是10岁,
  4. 第二个是5岁,
  5. 第三个是40岁.
  6. */
  7. Project.max('age').then(max => {
  8. // 将返回 40
  9. })
  10. Project.max('age', { where: { age: { [Op.lt]: 20 } } }).then(max => {
  11. // 将会是 10
  12. })

min - 获取特定表中特定属性的最小值

这里是获取属性的最小值的方法:

  1. /*
  2. 我们假设3个具有属性年龄的对象.
  3. 第一个是10岁,
  4. 第二个是5岁,
  5. 第三个是40岁.
  6. */
  7. Project.min('age').then(min => {
  8. // 将返回 5
  9. })
  10. Project.min('age', { where: { age: { [Op.gt]: 5 } } }).then(min => {
  11. // 将会是 10
  12. })

sum - 特定属性的值求和

为了计算表的特定列的总和,可以使用“sum”方法.

  1. /*
  2. 我们假设3个具有属性年龄的对象.
  3. 第一个是10岁,
  4. 第二个是5岁,
  5. 第三个是40岁.
  6. */
  7. Project.sum('age').then(sum => {
  8. // 将返回 55
  9. })
  10. Project.sum('age', { where: { age: { [Op.gt]: 5 } } }).then(sum => {
  11. // 将会是 50
  12. })