# SequelizeQueryBuilder 使用

SequelizeQueryBuilder 使用文档

SequelizeQueryBuilder 是一个用于构建 Sequelize 查询的辅助类。它提供了一系列方法来构建查询条件、排序、分组、限制和选择字段等操作。以下是 SequelizeQueryBuilder 类的详细说明和使用示例。

# 例子

   let builder = new sequelizeQueryBuilder()
    let queryObj = builder
      .select('author_id', 'video.aweme_id', 'video.title', 'video.cover', 'video.create_time', 'video.content_url',
        'video.duration', 'video.digg_count', 'video.comment_count', 'video.forward_count', 'video.order_count') // 如果是查询连表里的字段,需要在字段前面写别名, 不写别名是查询当前表字段, 特殊查询使用raw方法
      .where('platform_id', _.toInteger(query.platform_id))
      .where('author_id', _.toInteger(query.author_id))
      .when(query.product_id, queryBuilder => {
        queryBuilder.where('product_id', query.product_id)
      })
      .where('type', CONST_ACTIVITY.JOIN_DETAIL_TYPE_VIDEO)
      .join({
        fromModel: this.compassModel.PlatformJoinDetail,
        fromField: 'join_id',
        toModel: this.compassModel.AuthorVideo,
        toField: 'aweme_id',
        as: 'video',
        whereClosure: queryBuilder => {
          queryBuilder.where('author_id', _.toInteger(query.author_id))
        }// 连表的额外条件
      })//连表
      .when(query.order_key, queryBuilder => {
        queryBuilder.orderBy(builder.raw('video.' + query.order_key), query.order_value ?? 'DESC')
      })// 给连表的字段排序
      .build()

    queryObj.isPagination = true
    this.pagination({params: query, origin_data: queryObj})
    let data = await this.compassModel.PlatformJoinDetail.findAndCountAll(queryObj)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    let pageQueryBuilder = new sequelizeQueryBuilder()
    let queryObj = pageQueryBuilder
      .select('type', 'service_rate', 'commission_rate', 'exclusive_duration', 'commission_effect_end_time',
        'id', 'product_id', 'activity_id', 'promotion_url', 'status', 'institution_account_id')
      .where('admin_id', 'eq', query.admin_id)
      .when(query?.query_type == 'product_id' && query?.q, (queryBuilder) => {
        queryBuilder.where('product_id',query.q)
      })
      .when(query?.query_type == 'product_name' && query?.q, (queryBuilder) => {
        queryBuilder.join({
          fromModel: this.xpinModel.XpinInstitutionActivityGoods,
          fromField: 'product_id',
          toModel: this.compassModel.Product,
          toField: 'product_id',
          as: 'product'
        }).join({
          fromModel: this.xpinModel.XpinInstitutionActivityGoods,
          fromField: 'id',
          toModel: this.xpinModel.XpinInstitutionActivityGoodsExtension,
          toField: 'id',
          as: 'ext'
        })
      })
      .when(query?.query_type == 'product_name' && query?.q, (queryBuilder) => {
        query.q = `%${query.q}%`
        queryBuilder.whereRaw(`(product.title like :q or ext.title like :q)`)
      })
      .when(query.shop_name, (pageQueryBuilder) => {
        pageQueryBuilder.where('shop_name', 'like', '%'+query.shop_name+'%')
      })
      .when(query.status, (pageQueryBuilder) => {
        pageQueryBuilder.where('status', 'eq', parseInt(query.status))
      })
      .when(query.is_new, (pageQueryBuilder) =>{
        pageQueryBuilder.where('is_new', 'eq', parseInt(query.is_new))
      })
      .when(query.activity_id, (pageQueryBuilder) =>{
        pageQueryBuilder.where('activity_id', 'eq', query.activity_id)
      })
      .when(query.commission_effect_end_time, (pageQueryBuilder) =>{
        pageQueryBuilder.whereBetween('commission_effect_end_time',
          this.helper.getExpireTimestamp({
            expire: query.commission_effect_end_time,
            is_all: query.is_all_expire ? true : false
          }))
      })
      .when(query.type, (pageQueryBuilder) =>{
        pageQueryBuilder.where('type', 'eq', query.type)
      })
      .when(query.exclusive_duration !== "" && query.exclusive_duration !== undefined, (pageQueryBuilder) =>{
        if (query.exclusive_duration == 1){
          pageQueryBuilder.where('exclusive_duration', '>', 0)
        }else {
          pageQueryBuilder.where('exclusive_duration', 0)
        }
      })
      .when(query.plan_status, (pageQueryBuilder) =>{
        switch (parseInt(query.plan_status)){
          case 1: // 合作中
            pageQueryBuilder.where('audit_status', 'eq', CONST_INST_ACTIVITY_GOODS.AUDIT_STATUS_PASS)
            break
          case 2: // 合作已终止
            pageQueryBuilder.where('audit_status', 'eq', CONST_INST_ACTIVITY_GOODS.AUDIT_STATUS_STOP)
            break
          case 3: //合作已过期
            pageQueryBuilder.where('audit_status', 'eq', CONST_INST_ACTIVITY_GOODS.AUDIT_STATUS_EXPIRE)
            break
        }
      })
      .when(!_.isEmpty(query.publish_status), (pageQueryBuilder) =>{ // 通过外接传入发布状态过滤数据
        pageQueryBuilder.whereIn('publish_status', query.publish_status.map(i => parseInt(i)))
      })
      .when(query.order_key && query.order_value, queryBuilder => {
        queryBuilder.orderBy(query.order_key, query.order_value == 'ascending' ? 'asc' : 'desc')
      })
      .bind(query)
      .orderBy('published_at', 'desc')
      .paginate({params: query}
    // 分页查询
    let data = await this.xpinModel.XpinInstitutionActivityGoods.findAndCountAll(queryObj)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

# 构造函数

const builder = new SequelizeQueryBuilder();
1

使用 new 关键字创建一个新的 SequelizeQueryBuilder 实例。

# 查询条件

# where(...args)

添加一个查询条件,根据指定的字段、操作符和值进行匹配。

  • 如果参数个数为 1,则表示使用回调函数的方式构建复杂的查询条件。
  • 如果参数个数为 2,则表示添加一个基本的等值查询条件。
  • 如果参数个数为 3,则表示添加一个指定操作符的查询条件。
  • 查询的值也可以是原生sql。

示例:

builder.where('name', 'John');
builder.where('age', '>', 18);
builder.where((subQueryBuilder) => {
  subQueryBuilder.where('age', '>', 18).where('name', 'John');
});
bilder.where('nickname', '=', builder.raw('name')
1
2
3
4
5
6

# orWhere(callback)

添加一个使用 OR 连接的复杂查询条件,可以通过回调函数的方式构建复杂的嵌套条件。

提示:orWhere里第一层的查询生成出来后,全部使用 or 连接,sql:( xxx or xxx ),如果需要嵌套 and 查询, 需要自己使用 where 闭包

示例:

builder.orWhere((subQueryBuilder) => {
  subQueryBuilder.where('age', '>', 18).where('name', 'John');
});
1
2
3

# when(condition, callback)

添加一个满足前置条件的查询条件,通过回调函数的方式构建条件。

示例:

builder.when(!_.isEmpty(query),(subQueryBuilder) => {
  subQueryBuilder.where('age', '>', 18).where('name', 'John');
});
1
2
3

# whereIn(field, values)

添加一个查询条件,检查指定字段的值是否在给定的值数组中。

示例:

builder.whereIn('id', [1, 2, 3]);
1

# whereNotIn(field, values)

添加一个查询条件,检查指定字段的值不在给定的值数组中。

示例:

builder.whereNotIn('id', [1, 2, 3]);
1

# whereBetween(field, values)

添加一个查询条件,检查指定字段的值是否在给定的范围内。

示例:

builder.whereBetween('age', [18, 30]);
1

# whereNotBetween(field, values)

添加一个查询条件,检查指定字段的值是否不在给定的范围内。

示例:

builder.whereNotBetween('age', [0, 18]);
1

# whereBetweenTimeStamps(field, values)

添加一个查询条件,检查指定字段的值是否在给定的时间戳(已适配秒级/毫秒级)范围内, 结束时间会自动加86400-1秒。

示例:

builder.whereBetweenTimeStamps('created_at', [1704211200, 1704211200]);
1

# whereNull(field)

添加一个查询条件,检查指定字段的值是否为 null。

示例:

builder.whereNull('email');
1

# whereNotNull(field)

添加一个查询条件,检查指定字段的值是否不为 null。

示例:

builder.whereNotNull('email');
1

# whereDate(field, date)

添加一个查询条件,检查指定字段的日期是否与给定的日期匹配。

示例:

builder.whereDate('createdAt', '2022-01-01');
1

# whereMonth(field, month)

添加一个查询条件,检查指定字段的月份是否与给定的月份匹配。

示例:

builder.whereMonth('createdAt', 3);
1

# whereYear(field, year)

添加一个查询条件,检查指定字段的年份是否与给定的年份匹配。

示例:

builder.whereYear('createdAt', 2022);
1

# whereTime(field, time)

添加一个查询条件,检查指定字段的时间是否与给定的时间匹配。

示例:

builder.whereTime('createdAt', '09:00:00');
1

# whereRaw(condition)

添加一个原始查询条件,使用原始的 SQL 条件语句。

示例:

builder.whereRaw('LENGTH(name) > 5');
1

# 排序和分组

# orderBy(field, direction)

指定结果集的排序方式。可以指定字段和排序方向('ASC' 或 'DESC')。

示例:

builder.orderBy('createdAt', 'DESC');
builder.orderBy(builder.raw('balance+point*2'), 'DESC');
1
2

# groupBy(field)

指定结果集的分组字段。

示例:

builder.groupBy('category').groupBy(builder.raw("max(id)"));
1

# 聚合函数和限制

# having(...args)

添加一个聚合函数的条件,根据指定的字段、操作符和值进行匹配。

  • 如果参数个数为 1,则表示使用回调函数的方式构建复杂的查询条件。
  • 如果参数个数为 2,则表示添加一个基本的等值查询条件。
  • 如果参数个数为 3,则表示添加一个指定操作符的查询条件。
  • 查询的值也可以是原生sql。

示例:

builder.having('name', 'John');
builder.having('age', '>', 18);
builder.having((subQueryBuilder) => {
  subQueryBuilder.having('age', '>', 18).having('name', 'John');
});
bilder.having('nickname', '=', builder.raw('name')
1
2
3
4
5
6

# orHaving(callback)

添加一个使用 OR 连接的复杂查询条件,可以通过回调函数的方式构建复杂的嵌套条件。

提示:orHaving里第一层的查询生成出来后,全部使用 or 连接,sql:( xxx or xxx ),如果需要嵌套 and 查询, 需要自己使用 having 闭包

示例:

builder.orHaving((subQueryBuilder) => {
  subQueryBuilder.having('age', '>', 18).having('name', 'John');
});
1
2
3

# havingRaw(condition)

添加一个聚合函数的条件,使用原始的 SQL 条件语句。

示例:

builder.havingRaw('LENGTH(name) > 5');
1

# limit(value)

指定查询结果的最大返回数量。

示例:

builder.limit(10);
1

# offset(value)

指定查询结果的偏移量,用于分页查询。

示例:

builder.offset(20);
1

# paginate({ params, maxLimit = 200, defaultLimit = 20 })

为查询构建器设置 limit 和 offset,实现分页查询,同时也会构建并返回最终的查询对象,也就是内部会调用build方法。

参数

  • maxLimit - 最大限制,默认为200。超过这个值时使用这个值

  • defaultLimit- 默认限制,默认为20。如果没传limit参数则使用这个值

实现:

  1. 获取limit参数的值,如果没有则使用defaultLimit
  2. 检查limit值是否超过maxLimit,如果超过则使用maxLimit
  3. 计算offset值:
    • 如果有offset参数,则直接使用
    • 如果有page参数,则取(page - 1) * limit
    • 否则默认为0
  4. limitValueoffsetValue设为函数的属性

示例:

builder.paginate({ params: query });
1

# 结果集选择

# select(...fields)

指定查询结果中要选择的字段。

查询主表不需要带别名(除非是raw查询), 查询连表需要带别名

示例:

// 基本查询
builder.select('name', 'age');

// 连表后,获取连表内的字段,以及使用原始语句,假设主表model是User,连了profile表,且别名也是profile
// 查询内容是, 姓名,年级,个性签名,身份证,手机号(地区+手机号)
builder.select('name', 'age', 'profile.bio', builder.raw('profile.idcard as idcard,concat(User.area_code,User.phone) as phone'))
1
2
3
4
5
6

# selectRaw(value)

指定查询结果中要执行的原始sql。

示例:

// 基本查询
builder.selectRaw('count(1) as cnt');
1
2

# 参数绑定和事务

# bind(values)

绑定查询参数,用于预防 SQL 注入攻击。

提示:不支持多次调用。

示例:

builder.bind({name:'John'});
1

# bindTransaction(transaction)

绑定事务对象,用于在SQL操作中使用事务。

示例:

builder.bindTransaction(transaction);
1

# 连表

# join({options})

  • fromModel - 源模型
  • fromField - 源模型的外键
  • toModel - 目标模型
  • toField - 目标模型的外键
  • as - 别名
  • whereClosure - 一个回调执行子查询构建器来设置where条件 跟where参数二选一
  • where - 一个where条件(优先级高于whereClosure) 跟whereClosure参数二选一

连表查询

连表后如果需要在外面做字段查询或者条件检索,需要带上别名

示例:

builder.join({
  fromModel: User,
  fromField: 'id',
  toModel: Post,
  toField: 'userId',
  as: 'posts',
  whereClosure: (subQueryBuilder) => {
      subQueryBuilder.where('title', 'like', '%hello%');
  },
  where: new sequelizeQueryBuilder().where('title', 'like', '%hello%').build().where
})
1
2
3
4
5
6
7
8
9
10
11

# leftJoin({options})

执行左连接。参数同 join() ,只是执行左连接而不是内连接。

示例:

builder.leftJoin({
  fromModel: User,
  fromField: 'id',
  toModel: Post,
  toField: 'userId',
  as: 'posts' 
})
1
2
3
4
5
6
7

# 构建查询对象

# build()

构建并返回最终的查询对象。

示例:

const query = builder.build();
console.log(query);
1
2