Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sequelize 文档学习(CRUD查询篇) #57

Open
18888628835 opened this issue Jul 17, 2021 · 0 comments
Open

Sequelize 文档学习(CRUD查询篇) #57

18888628835 opened this issue Jul 17, 2021 · 0 comments

Comments

@18888628835
Copy link
Owner

Sequelize 文档学习(CRUD查询篇)

Seq 提供了非常丰富的查询数据的方法,这促使我们需要花费大量精力了解它。

下面开始吧。

简单INSERT查询

下面我将使用 create 方法来创建两条数据,注意它们的区别

(async () => {
  await User.sync({ alter: true });
  // 创建一个新用户 
  const jane: any = await User.create({ firstName: "Jane", lastName: "Doe" });
  console.log("Jane's auto-generated ID:", jane.id);//1
  const jim: any = await User.create(
    { firstName: "Jim", lastName: "Green" },
    { fields: ["firstName"] }
  );
  console.log(jim.lastName);//undefined
})();

create 是使用 Model.build() 构建未保存实例并使用 instance.save() 保存实例的语法糖,它可以使用 save 方法的部分保存功能。上面代码中,使用 Create 方法创建 jim.lastName,打出来依然是 undefined

如果使用 build 和 save 方法,则有一点不同

  const Anne: any = await User.build({ firstName: "Anne", lastName: "Smith" });
  await Anne.save({ fields: ["firstName"] });
  console.log(Anne.lastName); // Smith

上面的代码中,我使用Model.build 方法构建了 lastName 和 firstName,但是并未保存lastName。数据库中自然不会处理 lastName 字段,不过record 实例对象中则依然是存在 lastName 属性的。

简单 SELECT 查询

使用 findAll 方法可以查询整张表

  //读取整张表
  const users: any = await User.findAll();
  console.log(JSON.stringify(users));
$ Executing (default): SELECT `id`, `firstName`, `lastName`, `age`, `createdAt`, `updatedAt` FROM `Users` AS `User`;
[{"id":1,"firstName":"Jane","lastName":"Doe","age":0,"createdAt":"2021-07-17T06:25:50.000Z","updatedAt":"2021-07-17T06:25:50.000Z"},{"id":2,"firstName":"Jim","lastName":null,"age":0,"createdAt":"2021-07-17T06:25:50.000Z","updatedAt":"2021-07-17T06:25:50.000Z"},{"id":3,"firstName":"Anne","lastName":null,"age":0,"createdAt":"2021-07-17T06:25:50.000Z","updatedAt":"2021-07-17T06:25:50.000Z"}]

SELECT查询特定属性

查询特定属性时,可以用attributes属性

  const s = await User.findAll({ attributes: ["firstName"] });
  console.log(JSON.stringify(s));
  //[{"firstName":"Jane"},{"firstName":"Jim"},{"firstName":"Anne"}]

在查询的时候如果希望返回的字段跟数据库的不一致,那可以使用别名,具体用法是这样的

  const d = await User.findAll({
    attributes: ["firstName", ["lastName", "lsName"]],
  });
  console.log(JSON.stringify(d));
  //[{"firstName":"Jane","lsName":"Doe"},{"firstName":"Jim","lsName":null},{"firstName":"Anne","lsName":null}]

使用聚合函数配合 group 分组

  const g = await User.findAll({
    group: ["firstName", "lastName"],
    attributes: [
      "lastName",
      "firstName",
      [Sequelize.fn("COUNT", Sequelize.col("age")), "n_age"],
    ],
  });
  console.log(JSON.stringify(g));
  //[{"lastName":null,"firstName":"Anne","n_age":1},{"lastName":"Doe","firstName":"Jane","n_age":1},{"lastName":null,"firstName":"Jim","n_age":1}]
 SELECT `lastName`, `firstName`, COUNT(`age`) AS `n_age` FROM `Users` AS `User` GROUP BY `firstName`, `lastName`;

还可以排除属性

  const h: any = await User.findAll({
    attributes: {
      exclude: ["age"],
    },
  });
  console.log(JSON.stringify(h));
Executing (default): SELECT `id`, `firstName`, `lastName`, `createdAt`, `updatedAt` FROM `Users` AS `User`;

WHERE

WHERE 语句用于过滤查询,它专门配置了一些语法糖,以下是一些用例

默认相等查询

比如下面我只需要查询 firstName=jim 的数据

  const j: any = await User.findAll({
    where: {
      firstName: "jim",
    },
  });
  console.log(JSON.stringify(j));
  //[{"id":2,"firstName":"Jim","lastName":null,"age":0,"createdAt":"2021-07-17T07:57:06.000Z","updatedAt":"2021-07-17T07:57:06.000Z"}]
$ Executing (default): SELECT `id`, `firstName`, `lastName`, `age`, `createdAt`, `updatedAt` FROM `Users` AS `User` WHERE `User`.`firstName` = 'jim';

上面的代码默认使用相等运算符进行比较,也可以改写成使用 Op.eq 运算符

const { Op } = require("sequelize");
User.findAll({
  where: {
    firstName: {
      [Op.eq]: "jim",
    }
  }
});
// SELECT * FROM post WHERE authorId = 2

基础运算符查询

and 查询语法糖

  const j3 = await User.findAll({
    where: { firstName: "Jane", lastName: "Doe" },
  });
  console.log(JSON.stringify(j3));
  //Executing (default): SELECT `id`, `firstName`, `lastName`, `age`, `createdAt`, `updatedAt` FROM `Users` AS `User` WHERE `User`.`firstName` = 'Jane' AND `User`.`lastName` = 'Doe';

and 查询其他写法

  const j4 = await User.findAll({
    where: { [Op.and]: [{ firstName: "Jane" }, { lastName: "Doe" }] },
  });
  //Executing (default): SELECT `id`, `firstName`, `lastName`, `age`, `createdAt`, `updatedAt` FROM `Users` AS `User` WHERE `User`.`firstName` = 'Jane' AND `User`.`lastName` = 'Doe';

OR查询

  const j5 = await User.findAll({
    where: { [Op.or]: [{ firstName: "Jane" }, { firstName: "jim" }] },
  });
  console.log(JSON.stringify(j5));
//Executing (default): SELECT `id`, `firstName`, `lastName`, `age`, `createdAt`, `updatedAt` FROM `Users` AS `User` WHERE (`User`.`firstName` = 'Jane' OR `User`.`firstName` = 'jim');

Op.in 查询

  const j6 = await User.findAll({
    where: { firstName: ["Jane", "jim"] },
  });
  console.log(JSON.stringify(j6));
//Executing (default): SELECT `id`, `firstName`, `lastName`, `age`, `createdAt`, `updatedAt` FROM `Users` AS `User` WHERE `User`.`firstName` IN ('Jane', 'jim');

两者的语句不太一样,但是查询出来的结果还是相同的

[{"id":1,"firstName":"Jane","lastName":"Doe","age":0,"createdAt":"2021-07-17T08:25:48.000Z","updatedAt":"2021-07-17T08:25:48.000Z"},{"id":2,"firstName":"Jim","lastName":null,"age":0,"createdAt":"2021-07-17T08:25:48.000Z","updatedAt":"2021-07-17T08:25:48.000Z"}]

更多运算符查询

直接看官方的案例吧,用到的时候可以参考

const { Op } = require("sequelize");
Post.findAll({
  where: {
    [Op.and]: [{ a: 5 }, { b: 6 }],            // (a = 5) AND (b = 6)
    [Op.or]: [{ a: 5 }, { b: 6 }],             // (a = 5) OR (b = 6)
    someAttribute: {
      // 基本
      [Op.eq]: 3,                              // = 3
      [Op.ne]: 20,                             // != 20
      [Op.is]: null,                           // IS NULL
      [Op.not]: true,                          // IS NOT TRUE
      [Op.or]: [5, 6],                         // (someAttribute = 5) OR (someAttribute = 6)

      // 使用方言特定的列标识符 (以下示例中使用 PG):
      [Op.col]: 'user.organization_id',        // = "user"."organization_id"

      // 数字比较
      [Op.gt]: 6,                              // > 6
      [Op.gte]: 6,                             // >= 6
      [Op.lt]: 10,                             // < 10
      [Op.lte]: 10,                            // <= 10
      [Op.between]: [6, 10],                   // BETWEEN 6 AND 10
      [Op.notBetween]: [11, 15],               // NOT BETWEEN 11 AND 15

      // 其它操作符

      [Op.all]: sequelize.literal('SELECT 1'), // > ALL (SELECT 1)

      [Op.in]: [1, 2],                         // IN [1, 2]
      [Op.notIn]: [1, 2],                      // NOT IN [1, 2]

      [Op.like]: '%hat',                       // LIKE '%hat'
      [Op.notLike]: '%hat',                    // NOT LIKE '%hat'
      [Op.startsWith]: 'hat',                  // LIKE 'hat%'
      [Op.endsWith]: 'hat',                    // LIKE '%hat'
      [Op.substring]: 'hat',                   // LIKE '%hat%'
      [Op.iLike]: '%hat',                      // ILIKE '%hat' (不区分大小写) (仅 PG)
      [Op.notILike]: '%hat',                   // NOT ILIKE '%hat'  (仅 PG)
      [Op.regexp]: '^[h|a|t]',                 // REGEXP/~ '^[h|a|t]' (仅 MySQL/PG)
      [Op.notRegexp]: '^[h|a|t]',              // NOT REGEXP/!~ '^[h|a|t]' (仅 MySQL/PG)
      [Op.iRegexp]: '^[h|a|t]',                // ~* '^[h|a|t]' (仅 PG)
      [Op.notIRegexp]: '^[h|a|t]',             // !~* '^[h|a|t]' (仅 PG)

      [Op.any]: [2, 3],                        // ANY ARRAY[2, 3]::INTEGER (仅 PG)
      [Op.match]: Sequelize.fn('to_tsquery', 'fat & rat') // 匹配文本搜索字符串 'fat' 和 'rat' (仅 PG)

      // 在 Postgres 中, Op.like/Op.iLike/Op.notLike 可以结合 Op.any 使用:
      [Op.like]: { [Op.any]: ['cat', 'hat'] }  // LIKE ANY ARRAY['cat', 'hat']

      // 还有更多的仅限 postgres 的范围运算符,请参见下文
    }
  }
});

运算符组合

运算符 Op.and, Op.orOp.not 可用于创建任意复杂的嵌套逻辑比较.

使用 Op.andOp.or 示例

const { Op } = require("sequelize");

Foo.findAll({
  where: {
    rank: {
      [Op.or]: {
        [Op.lt]: 1000,
        [Op.eq]: null
      }
    },
    // rank < 1000 OR rank IS NULL

    {
      createdAt: {
        [Op.lt]: new Date(),
        [Op.gt]: new Date(new Date() - 24 * 60 * 60 * 1000)
      }
    },
    // createdAt < [timestamp] AND createdAt > [timestamp]

    {
      [Op.or]: [
        {
          title: {
            [Op.like]: 'Boat%'
          }
        },
        {
          description: {
            [Op.like]: '%boat%'
          }
        }
      ]
    }
    // title LIKE 'Boat%' OR description LIKE '%boat%'
  }
});

使用 Op.not示例

Project.findAll({
  where: {
    name: 'Some Project',
    [Op.not]: [
      { id: [1,2,3] },
      {
        description: {
          [Op.like]: 'Hello%'
        }
      }
    ]
  }
});

生成以下语句

SELECT *
FROM `Projects`
WHERE (
  `Projects`.`name` = 'a project'
  AND NOT (
    `Projects`.`id` IN (1,2,3)
    OR
    `Projects`.`description` LIKE 'Hello%'
  )
)

UPDATE 查询

下面是简单的将 jim 改成 jim2的命令

  const j7 = await User.update(
    { firstName: "jim2" },
    {
      where: {
        firstName: "jim",
      },
    }
  );
  console.log(JSON.stringify(j7));//[1]

DELETE 查询

下面是将所有 lastName 为 null 的数据删除的代码

  // 删除所有名为 "Jane" 的人
  await User.destroy({
    where: {
      lastName: null,
    },
  });

删掉所有内容

  // 截断表格
  await User.destroy({
    truncate: true,
  });

批量创建

可以使用Model.bulkCreate来一次性批量创建,跟create 方法非常相似,但也有一点不同

  await User.bulkCreate([
    { firstName: "qiu", lastName: "yanxi" },
    { firstName: "qiu", lastName: "yanxi" },
    { firstName: "qiu", lastName: "yanxi" },
  ]);

默认情况下,bulkCreate 不会在要创建的每个对象上运行验证(而 create 可以做到). 为了使 bulkCreate 也运行这些验证,必须通过validate: true 参数. 但这会降低性能. 用法示例:

const Foo = sequelize.define('foo', {
  bar: {
    type: DataTypes.TEXT,
    validate: {
      len: [4, 6]
    }
  }
});

// 这不会引发错误,两个实例都将被创建
await Foo.bulkCreate([
  { name: 'abc123' },
  { name: 'name too long' }
]);

// 这将引发错误,不会创建任何内容
await Foo.bulkCreate([
  { name: 'abc123' },
  { name: 'name too long' }
], { validate: true });

如果你直接从用户获取值,那么限制实际插入的列可能会有所帮助. 为了做到这一点,bulkCreate() 接受一个 fields 参数,该参数须为你要定义字段的数组(其余字段将被忽略).

await User.bulkCreate([
  { username: 'foo' },
  { username: 'bar', admin: true }
], { fields: ['username'] });
// foo 和 bar 都不会是管理员.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant