1. 程式人生 > >sequelize-----關聯查詢與批量查詢

sequelize-----關聯查詢與批量查詢

之前的文章說了sequelize對於事物的處理,包括說自動提交的事務以及手動提交回滾的事物。而對於java來說事務相對來說用起來簡單一些,個人是這樣認為的。

這次來說一下關聯查詢與批量查詢:

都知道,關聯關係主要有三種:一對一,一對多,多對多,我記得javayou一個批量的方法就是addbatch進行批量的操作,言歸正傳sequelize對於一對一的處理你可以用find相關的方法比如說:findByid,findOne,包括說findAll,而一對多來說有hasMany、多對一是有belongsTo,對於多對多有belongsToMany,我想對於這種名字來說是很好理解的,接下來我們類介紹一下這幾種方法:

1 findOne:

我們來看一下原始碼:

/**
   * Search for a single instance. This applies LIMIT 1, so the listener will always be called with a single instance.
   *
   * __Alias__: _find_
   *
   * @param  {Object}                    [options] A hash of options to describe the scope of the search
   * @param  {Transaction}               [options.transaction] Transaction to run query under
   * @param  {String}                    [options.searchPath=DEFAULT] An optional parameter to specify the schema search_path (Postgres only)
   *
   * @see {@link Model.findAll}           for an explanation of options
   * @return {Promise<Model>}
   */
  static findOne(options) {
    if (options !== undefined && !_.isPlainObject(options)) {
      throw new Error('The argument passed to findOne must be an options object, use findById if you wish to pass a single primary key value');
    }
    options = Utils.cloneDeep(options);

    if (options.limit === undefined) {
      const uniqueSingleColumns = _.chain(this.uniqueKeys).values().filter(c => c.fields.length === 1).map('column').value();

      // Don't add limit if querying directly on the pk or a unique column
      if (!options.where || !_.some(options.where, (value, key) =>
        (key === this.primaryKeyAttribute || _.includes(uniqueSingleColumns, key)) &&
          (Utils.isPrimitive(value) || Buffer.isBuffer(value))
      )) {
        options.limit = 1;
      }
    }

    // Bypass a possible overloaded findAll.
    return this.findAll(_.defaults(options, {
      plain: true,
      rejectOnEmpty: false
    }));
  }

其實通過上面的原始碼我們可以看到的就是,其實findOne底層用到的就是findAll只不過加了限制的limit 1 這樣返回的就是一個找到的物件,而且我們可以看到的就是它的返回值是當前找到的一個一部model:當然你在查詢的時候需要通過where去新增查詢的條件,它不像是findById一樣直接填入引數就預設去用id查詢,他是需要查詢條件的;

2.findAll

原始碼太長大家可以自己去看,這裡我只是拿出一部分來了解一下:它對於demo的列舉還是比較詳細的,大家可以自己去看;

這裡找到的結果可以用與where並列的limit,offerset,order等來進行排序和分頁;其中對於[and],[or]來說可以對條件之間的關係進行約束;

/**
   * Search for multiple instances.
   *
   * __Simple search using AND and =__
   * ```js
   * Model.findAll({
   *   where: {
   *     attr1: 42,
   *     attr2: 'cake'
   *   }
   * })
   * ```
   * ```sql
   * WHERE attr1 = 42 AND attr2 = 'cake'
   *```
   *
   * __Using greater than, less than etc.__
   * ```js
   * const {gt, lte, ne, in: opIn} = Sequelize.Op;
   * Model.findAll({
   *   where: {
   *     attr1: {
   *       [gt]: 50
   *     },
   *     attr2: {
   *       [lte]: 45
   *     },
   *     attr3: {
   *       [opIn]: [1,2,3]
   *     },
   *     attr4: {
   *       [ne]: 5
   *     }
   *   }
   * })
   * ```
   * ```sql
   * WHERE attr1 > 50 AND attr2 <= 45 AND attr3 IN (1,2,3) AND attr4 != 5
   * ```
   * See {@link Operators} for possible operators
   *
   * __Queries using OR__
   * ```js
   * const {or, and, gt, lt} = Sequelize.Op;
   * Model.findAll({
   *   where: {
   *     name: 'a project',
   *     [or]: [
   *       {id: [1, 2, 3]},
   *       {
   *         [and]: [
   *           {id: {[gt]: 10}},
   *           {id: {[lt]: 100}}
   *         ]
   *       }
   *     ]
   *   }
   * });
   * ```
   * ```sql
   * WHERE `Model`.`name` = 'a project' AND (`Model`.`id` IN (1, 2, 3) OR (`Model`.`id` > 10 AND `Model`.`id` < 100));
   * ```
   *
   * The promise is resolved with an array of Model instances if the query succeeds.
   *
   * __Alias__: _all_
   *
   * @param  {Object}                                                    [options] A hash of options to describe the scope of the search
   * @param  {Object}                                                    [options.where] A hash of attributes to describe your search. See above for examples.
   * @param  {Array<String>|Object}                                      [options.attributes] A list of the attributes that you want to select, or an object with `include` and `exclude` keys. To rename an attribute, you can pass an array, with two elements - the first is the name of the attribute in the DB (or some kind of expression such as `Sequelize.literal`, `Sequelize.fn` and so on), and the second is the name you want the attribute to have in the returned instance
   * @param  {Array<String>}                                             [options.attributes.include] Select all the attributes of the model, plus some additional ones. Useful for aggregations, e.g. `{ attributes: { include: [[sequelize.fn('COUNT', sequelize.col('id')), 'total']] }`
   * @param  {Array<String>}                                             [options.attributes.exclude] Select all the attributes of the model, except some few. Useful for security purposes e.g. `{ attributes: { exclude: ['password'] } }`
   * @param  {Boolean}                                                   [options.paranoid=true] If true, only non-deleted records will be returned. If false, both deleted and non-deleted records will be returned. Only applies if `options.paranoid` is true for the model.
   * @param  {Array<Object|Model|String>}                                [options.include] A list of associations to eagerly load using a left join. Supported is either `{ include: [ Model1, Model2, ...]}` or `{ include: [{ model: Model1, as: 'Alias' }]}` or `{ include: ['Alias']}`. If your association are set up with an `as` (eg. `X.hasMany(Y, { as: 'Z }`, you need to specify Z in the as attribute when eager loading Y).
   * @param  {Model}                                                     [options.include[].model] The model you want to eagerly load
   * @param  {String}                                                    [options.include[].as] The alias of the relation, in case the model you want to eagerly load is aliased. For `hasOne` / `belongsTo`, this should be the singular name, and for `hasMany`, it should be the plural
   * @param  {Association}                                               [options.include[].association] The association you want to eagerly load. (This can be used instead of providing a model/as pair)
   * @param  {Object}                                                    [options.include[].where] Where clauses to apply to the child models. Note that this converts the eager load to an inner join, unless you explicitly set `required: false`
   * @param  {Boolean}                                                   [options.include[].or=false] Whether to bind the ON and WHERE clause together by OR instead of AND.
   * @param  {Object}                                                    [options.include[].on] Supply your own ON condition for the join.
   * @param  {Array<String>}                                             [options.include[].attributes] A list of attributes to select from the child model
   * @param  {Boolean}                                                   [options.include[].required] If true, converts to an inner join, which means that the parent model will only be loaded if it has any matching children. True if `include.where` is set, false otherwise.
   * @param  {Boolean}                                                   [options.include[].separate] If true, runs a separate query to fetch the associated instances, only supported for hasMany associations
   * @param  {Number}                                                    [options.include[].limit] Limit the joined rows, only supported with include.separate=true
   * @param  {Object}                                                    [options.include[].through.where] Filter on the join model for belongsToMany relations
   * @param  {Array}                                                     [options.include[].through.attributes] A list of attributes to select from the join model for belongsToMany relations
   * @param  {Array<Object|Model|String>}                                [options.include[].include] Load further nested related models
   * @param  {Array|Sequelize.fn|Sequelize.col|Sequelize.literal}        [options.order] Specifies an ordering. Using an array, you can provide several columns / functions to order by. Each element can be further wrapped in a two-element array. The first element is the column / function to order by, the second is the direction. For example: `order: [['name', 'DESC']]`. In this way the column will be escaped, but the direction will not.
   * @param  {Number}                                                    [options.limit]
   * @param  {Number}                                                    [options.offset]
   * @param  {Transaction}                                               [options.transaction] Transaction to run query under
   * @param  {String|Object}                                             [options.lock] Lock the selected rows. Possible options are transaction.LOCK.UPDATE and transaction.LOCK.SHARE. Postgres also supports transaction.LOCK.KEY_SHARE, transaction.LOCK.NO_KEY_UPDATE and specific model locks with joins. See [transaction.LOCK for an example](transaction#lock)
   * @param  {Boolean}                                                   [options.raw] Return raw result. See sequelize.query for more information.
   * @param  {Function}                                                  [options.logging=false] A function that gets executed while running the query to log the sql.
   * @param  {Boolean}                                                   [options.benchmark=false] Pass query execution time in milliseconds as second argument to logging function (options.logging).
   * @param  {Object}                                                    [options.having]
   * @param  {String}                                                    [options.searchPath=DEFAULT] An optional parameter to specify the schema search_path (Postgres only)
   * @param  {Boolean|Error}                                             [options.rejectOnEmpty=false] Throws an error when no records found
   *
   * @link   {@link Sequelize.query}
   * @return {Promise<Array<Model>>}
   */

3 批量查詢

 

批量查詢我這裡用到的是一種條件的方法,要是大家有更好的方法可以分享一下:

首先我們需要sequelize的Op來使用這些條件:關於這些條件大家可以去官方文件檢視有很對類似與java的條件拼接的查詢,像in、notin等等;一下就是我們需要的Op的匯入,後面我們來使用一下:

import Seqeuelize from 'sequelize';

const Op = Seqeuelize.Op;

比如說我們去查詢多個商品這樣一種批量查詢:下面直接給出了例子的程式碼:

//很簡單我們只需要在查詢的條件上面將多個條件組成一個數組,在進行查詢的將這種條件以in的方式去並列查詢,意思就是將在這個陣列當中的商品全部查詢出來:
let goods = await GoodsModel.findAll({
		where: {
			id: {[Op.in]: goodsIds}
		}
	});

4 關聯查詢

在這裡我們以belongsTo為例子來展示,比如說訂單和商品的關係,大家都知道是多對多,這個時候應該去關聯第三張表去查詢,但是如果我們不是以訂單對商品的角度來看,而是以訂單對第三張表,以第三張表取對應商品這樣兩種角度來看的話前者就是一對多,而後者雖然是一個記錄對應一個商品,但是這多條記錄可能對應的就是一個訂單,所以歸結起來就是多對一關係,

好了我們直接以關聯表對商品來展示,其他的都是一樣的道理,好了直接來上程式碼:

//這裡加的外來鍵,值在查詢的時候由方法建立的的一個臨時的外來鍵,他不會建立在表當中的
let orderGoods = await OrderGooodsModel.findAll({
			where: {
				order_id: order1[i].id
			}, include: [
				{
	association: OrderGooodsModel.belongsTo(GoodsModel, {foreignKey: 'goods_id'}),
				},
			],
		});
//下面我們可以看一下它的原始碼:應該可以很清楚的看見遠與目標的作用
/**
   * Creates an association between this (the source) and the provided target. The foreign key is added on the source.
   *
   * @param {Model}           target
   * @param {object}          [options]
   * @param {boolean}         [options.hooks=false] Set to true to run before-/afterDestroy hooks when an associated model is deleted because of a cascade. For example if `User.hasOne(Profile, {onDelete: 'cascade', hooks:true})`, the before-/afterDestroy hooks for profile will be called when a user is deleted. Otherwise the profile will be deleted without invoking any hooks
   * @param {string}          [options.as] The alias of this model, in singular form. See also the `name` option passed to `sequelize.define`. If you create multiple associations between the same tables, you should provide an alias to be able to distinguish between them. If you provide an alias when creating the association, you should provide the same alias when eager loading and when getting associated models. Defaults to the singularized name of target
   * @param {string|object}   [options.foreignKey] The name of the foreign key in the source table or an object representing the type definition for the foreign column (see `Sequelize.define` for syntax). When using an object, you can add a `name` property to set the name of the column. Defaults to the name of target + primary key of target
   * @param {string}          [options.targetKey] The name of the field to use as the key for the association in the target table. Defaults to the primary key of the target table
   * @param {string}          [options.onDelete='SET&nbsp;NULL|NO&nbsp;ACTION'] SET NULL if foreignKey allows nulls, NO ACTION if otherwise
   * @param {string}          [options.onUpdate='CASCADE']
   * @param {boolean}         [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
   * @returns {BelongsTo}
   * @example
   * Profile.belongsTo(User) // This will add userId to the profile table
   */
  static belongsTo(target, options) {} // eslint-disable-line

y以上就是今天的對於幾個方法的簡單介紹以及使用,後期會去學習其他的來和大家分享,歡迎大家訪問;