Active Record Query Interface 数据查询接口(界面) 看到第8节。
- http://guides.rubyonrails.org/active_record_querying.html
✅How to find records using a variety of methods and conditions.
✅How to specify the order, retrieved attributes,grouping, and other properties of the found records.
✅ How to use eager loading(预先积极加载) to reduce the number of database queries needed for data retrieval.
✅ How to use dynamic finder methods.
✅ How to use method chaining to use multiple Active Record methods together.
✅ How to check for the existence of particular records
✅ How to perform to do sth useful or difficult various calculations on Active Record models.
✅ How to run EXPLAIN on relations.(如何在关联上跑explain命令)
Active Record will perform queries on the database for you and is compatible(兼容) with most database systems, including MySQL,SQLite ,etc..
1 .Retrieving Objects from the Database
The methods are: find ,where,select,group,20多种。
Finder methods that return a collection, such as where and group, return an instance of ActiveRecord::Relation.
Methods that find a single entity, such as find and first, return a single instance of the model.
The primary operatin of Model.find(options) can be summarized as:
- 根据options转化成SQL语句,激发查询语句并从数据库返回结果
- 从数据库返回的模型的每行结果实例化为相关的Ruby对象
- Run after_find and then after_initialize callbacks, if any.
1.1Retrieving single objects
1.11 find
通过指定primary key来检索object。可以同时检索多个primary key ,并返回一个数组,数组内包含所以匹配的记录。例子:
client = Client.find([1,10]) //或者写Client.find(1,10)
#=> [#<Client id: 1, first_name: "Lifo">, #<Client id: 10, first_name: "Ryan">]
等同于:
SELECT * FROM clients WHERE(clients.id IN (1,10))
如果primary key没有匹配的记录,find method会抛出ActiveRecord::RecordNotFound异常
1.12 take(数字)
The take method retrieves a record without any implicit ordering .例子:
参数是几,就返回几条记录。
client = Client.take
# => #<Client id: 1, first_name: "Lifo">
|
等同于:
SELECT * FROM clients LIMIT 1
|
如果没有检索到哪怕一条数据就会返回 nil.
1.13 first
find the first record ordered by primary key(default).
如果没有检索到哪怕一条数据就会返回 nil.
可以传入数字参数,根据数字,返回对应的记录数量。
Product.first(2) 等同于
可以和order连用。
first! ,if no matching record is found, it will rasie ActiveRecord::RecordNotFound
1.14 last
用法和first一样,sql语句是按照 DESC 降序排列。
1.15 find_by
finds the first record matching some conditions.例子:
Client.find_by first_name: 'XXX'
等同于
Client.where(first_name: 'xxx').take //take是取where找到的第一个数据。
1.2 Retrieving Multiple Objects in Batches
分批取回大量对象,多次检索,每次检索的记录数量有限制。默认1000条。
当dadabase非常大的时候,User.all.each 。。end 会占用超大内存,和时间。所以Rails提供了2个method:
find_each和find_in_batches,1000条以上记录,用这个比较好。batch processing 批处理
1.2.1 find_each 方法
User.find_each(可选参数) do |user|
NewsMailer.weekly(user).deliver_now
end
|
有3个options for find_each:
- :batch_size: 指定每次检索返回多少条数据.
- :start and :finish 根据primary id,确定开始和结束。
find_in_batches()方法,和find_each方法的区别
find_in_batches()每次返回的是一个数组,里面是模型对象的集合。
find_each()每次返回的是独立数量的模型对象,没有用数组括起来。
2 conditions --where()
不要用pure string,容易被injection exploits.注射攻击剥削。
㊗️:find和find_by method在ruby和rails 中已经自动可以规避这个问题。
攻击方法:在where的查询中添加一些string(有多种方法),来绕过登陆验证,获取数据 。
⚠️ :where, find_by_sql, connection.execute()等条件片段的查询,需要手动避免注入。 好的方法就是只用数组,或hash.
Returns a new relation, which is the result of filtering the current relation according to the conditions in the arguments
2.2 Array Conditions
Clinet.where("orders_count = ?", params[:orders])
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
placeholder, 可以在条件字符串中指定keys,之后附加相关的keys/values对儿。
Client.where("created_at >= :start_date AND created_at < :end_date", {start_date: params[:start_date], end_date: params[:end_date]})
2.3 Hash Condititons 具体看api
可以用Equality Conditions,Range Conditions, Subset Conditions.
Client.where(locked: true)
-> select * from clients where(clients.locked = 1)
Client.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
->SELECT
*
FROM
clients
WHERE
(clients.created_at
BETWEEN
'2008-12-21 00:00:00'
AND
'2008-12-22 00:00:00'
)
Client.where(orders_count: [1,3,5])
-> SELECT
*
FROM
clients
WHERE
(clients.orders_count
IN
(1,3,5))
在 belongs_to relationship, an association key can be used to specify the model if an ActiveRecord object is used as the value.
for example:
author = Author.find(1); // author 被定义为一个关联的对象
Post.where(author_id: author) //也可以写成:where(author: author) 但前者容易理解。
NOT
Client.where.not(locked: true)
-> select * from clients where(clients.locked != 1)
OR
Client.where(locked: true).or(Client.where(orders_count: [1,3,5]))
->select * from clients where(clients.locked = 1 or clients.orders_count in (1,3,5))
3 Ordering
Client.order(created_at:
:desc
)
相当于MySQL:
SELECT * from client ORDER BY created_at ASC;
Client.order("orders_count ASC").order("created_at DESC")
-> select * from clients order by orders_count asc, created_at desc
4 Selecting Specific Fields
select用于从结果集中选择字段的子集,就是只捞出column "vewable_by"和“locked”的值,其他列不捞出。
Client.select( "viewable_by, locked" )
|
等同于
SELECT viewable_by, locked FROM clients
|
5 Limit and Offset
You can use limit to specify the number of records to be retrieved,
Client.limit(5) 等同于 SELECT * FROM clients LIMIT 5
如果使用offset
Client.limit(
5
).offset(
30
)将返回5条记录,从31st开始。
⚠️ :用offset必须先用limit
6
Group
To apply a Group by clause to the SQL fired by the finder, you can use the group method.
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")
->
select date(created_at) as ordered_date, sum(price) as total_price FROM orders GROUP BY date(created_at)
7 Having方法
用having进行group by的条件限制。例子:
Order.select( "date(created_at) as ordered_date, sum(price) as total_price" ).
group( "date(created_at)" ).having( "sum(price) > ?" , 100 )
|
等同于:
SELECT
date
(created_at)
as
ordered_date,
sum
(price)
as
total_price
FROM
orders
GROUP
BY
date
(created_at)
HAVING
sum
(price) > 100
This returns the data and total price for each order object, grouped by the day they were created and where the price is more than $100.
上面的语句返回每个order对象的日期和总价,查询结果按照日期分组并排序(合并?),并且总价需要大于100.
8 Overriding Conditions 覆盖条件(对条件进行限制)
8.1 unscope
移除指定的条件。
Article.where(
'id > 10'
).limit(
20
).order(
'id asc'
).unscope(
:order
)等同于:
SELECT * FROM articles WHERE id > 10 LIMIT 20
|
8.2 only
指定用哪个查询条件。 和unscope正相反。
8.3 reorder :
The reorder method overrides the default scope order.当建立了一个一对多关联并指定排列的顺序后,想要在查询某个一对多的对象的实例上从新排序(不使用在model中申明的):可以用reorder.
class Article < ApplicationRecord
has_many :comments , -> {order( 'posted_at DESC' ) }
end
Article.find( 10 ).comments.reorder( 'name' )
|
SQL语句会被执行executed:
SELECT * FROM articles WHERE id = 10
SELECT * FROM comments WHERE article_id = 10 ORDER BY name
|
8.4 reverse_order 配合reorder或者order,升序变降序。
9 Null Relation
Article.none # returns an empty Relation and fires no queries.返回nil, []
|
10 Readonly Objects
当一个对象被设置为只读,他的属性不能被修改。
client = Client.readonly.first
client.visits += 1
client.save #这时会报错❌,raise ActiveRecord::ReadOnlyRecord exception
11 Locking Records for Update
积极锁,和消极锁。 防止在数据库更新时,出现混乱情况。
(没仔细看。)
积极锁允许多个用户同时更新同一条记录,并假定产生数据冲突的可能性最小。其原来是检查读取记录后看是否有其他进程尝试更新记录,如果有就抛出异常。
为了使用乐观锁,表格有一个整数型字段lock_version。每次记录更新,会同步增加这个字段的值。 如果更新请求中字段的值比当前数据库的字段的值小,更新请求失败,抛出异常。
抛出异常后,需要救援异常并处理冲突,或回滚或合并或使用其他逻辑来解决冲突。
12 Joining Tables 联结表
连个方法:
- joins: 对应SQL的 INNER JOIN ...ON
- left_outer_joins: 对应LEFT OUTER JOIN
1 使用字符串 SQL 片段
Author.joins("INNER JOIN posts ON posts.author_id = authors.id")
->
SELECT authors.* FROM authors INNER JOIN posts ON posts.author_id = authors.id
2 使用 Array/Hash of Named Associations使用具名关联数组或散列
如果连个model已经建立了关联:
Category.joins(:articels)
-》
select categories.* from categories inner join articles on articles.category_id = categories.id
会返回一个包含category 对象的数组,如过有多个article和一个category关联,则返回的这个数组中会出现多次这个category对象。
可以附加destinct方法 ,这样重复的category对象不会出现了。
3. 多个关联的联结
category has_many :articles
articles has_many :comments
Article.joins(:category, :comments)
->
select articles.* from articles
inner join categories on articles.category_id = categories.id
inner join comments on comments.artice_id = articles.id
解释:把属于某个目录并至少有一条评论的文章作为一个Article对象返回。
同样,拥有多个评论的一篇文章会在Article对象的数组中出现多次。
4单层嵌套关联的联结⚠️ 没细看
Article.joins(comments: :guest)
5 为joining table 指明条件
可以使用array, string条件 作为关联数据表的条件。
散列需要特殊的语法:
time_range = (Time.now。midnight - 1.day)..Time.now.midnight
Client.joins(:orders).where("orders.created_at" => time_range)
或者
Client.joins(:orders).where(orders: {created_at: time_range})
select clients.* from clients
inner join orders on clients.order_id = orders.id
where orders.created_at between "XXX时间" and "xxx时间"
解释:查找昨天创建过订单的所有客户,在生成的SQL中使用了between..and..
13 Eager Loading Associations
一种查找机制:目的是减少查询数据库的次数。
client has_one :address
clients = Client.limit(10)
clients.each do |c|
puts c.address.postcode
end
先查询10条clients记录,然后每条记录执行关联查询,一个调用了数据库11次。
为了提高效能:使用includes()方法。
clients = Client.includes(:address).limit(10)
这行代码执行了2次数据库。
1. select * from clients limit 10
2. select addresses.* from addresses where(addresses.client_id IN (1,2,3,..10))
14 Scopes
把常用的查询定义为方法,可以在关联对象或模型上作为方法调用。
总会返回一个ActiveRecord::Relation object
scope :published, -> {where(published: ture)}
完全等同于类方法:
def self.publish
where(published: true)
end
在作用域中可以链接其他scope。
如:
Article.published #作为类方法使用
category.articles.published #在关联对象上调用。
14.1 传递参数。
scope :created_before, ->(time) {where("created_at < ?", time)}
14.2 可以在{}内使用 if.
谨慎使用,如果if 的结果是false,会返回nil,并导致NoMethodError❌
14.3 默认作用域
default_scope:
在模型的任意查询中会自动附加上默认作用域、
default_scope {where("removed_at IS NULL")}
⚠️更新记录时,不会加上这个方法。
⚠️default_scope方法总在自定义的scope和where方法前起作用
14.4 合并作用域
两个scope连接起来,相当于使用了AND来合并作用域。
14.5 unscoped方法:删除所有的作用域。
Client.unscoped.all只执行常规查询 -》 select * from clients
Client.where(published:false).unscoped.all
不会执行where条件查询,把where当成了scope.
15 Dynamic Finders
find_by_*()方法。其实就是find_by(key/value)
16 enum
给一个类型是integer的列,指定一组值作为选项。
create_table :conversations do |t|t.column :status, :integer, default: 0
end
class Conversation < ActiveRecord::Base
enum status: { active: 0, archived: 1 }
end
17. Understanding the chain方法链连接多个ActiveRecord方法。
Person
.select('people.id, people.nam')
.joins(:comments)
.where('comments.created_at > ?', 1.week.ago)
等同
SELECT people.id, people.name
FROM people
INNER JOIN comments ON comments.people_id = people.id
WHERE comments.created_at > "2015-01-01"
19 可以使用完全的SQL:
find_by_sql() ,返回对象的数组。
sellect_all(),和find_by_sql()是近亲,区别是返回的是散列构成的数组,每行散列表示一条记录,没有被实例化。
pluck(),返回查询字段的值的数组。
Client.where(active: true) .pluck(:id)
-> select id from clients where active =1 #=> [1, 2, 3]
pluck()方法相当于使用select().map{|x| x.attr}
Client.select(:id, :name).map{|c| [c.id, c.name]}
-> Client.pluck(:id, :name)
⚠️,pluck()返回的是数组,所以不能放在查询方法链的中间,只能放置在最后。
20 ids方法
获得关联的所有ID, 数据表的primary_key
collection_singular_ids 这是has_many中的选项。返回关联对象的id的数组。\
@book_ids = @author.book_ids
21 exists?()方法,看是否存在记录。
也可以拥有关联记录collections.exists?()
也可以用于表的查询: 返回true/false,可以接受多个参数,
Client.exists?(1) #id等1的客户是否存在。
any? 是否存在一条记录
many? 是否存在2条(含)以上的记录。
21 calculation
Client.count
-> select count(*) as count_all from clients 算有多少条记录
Client.where(first_nam: "Tom").count
-> select count(*) as count_all from clients where(first_name = 'Tom')
算名字是Tom 的记录的数量。
Client.count(:age),返回有age字段的记录的数量
Client.average("orders_count") , 返回字段的平均值
Client.minimum("age")
Client.maximum("age")
Client.sum("orders_count")
转载于:https://www.cnblogs.com/chentianwei/p/8051664.html
Active Record Query Interface 数据查询接口(界面) 看到第8节。相关推荐
- boot spring 接口接收数据_在 Spring Boot 中使用 Dataway 配置数据查询接口
Dataway介绍 Dataway 是基于 DataQL 服务聚合能力,为应用提供的一个接口配置工具.使得使用者无需开发任何代码就配置一个满足需求的接口. 整个接口配置.测试.冒烟.发布.一站式都通过 ...
- Hystrix面试 - 基于 request cache 请求缓存技术优化批量商品数据查询接口
Hystrix面试 - 基于 request cache 请求缓存技术优化批量商品数据查询接口 Hystrix command 执行时 8 大步骤第三步,就是检查 Request cache 是否有缓 ...
- SpringBoot集成Hasor-Dataway数据查询接口
目录 一.前言 1.Hasor Core Core 容器框架 设计思想 特性 2.Hasor Web Web 框架 3.Hasor DB JDBC 框架 特性 4.Hasor DataQL DataQ ...
- vue获取商品数据接口_基于 request cache 请求缓存技术优化批量商品数据查询接口...
Hystrix command 执行时 8 大步骤第三步,就是检查 Request cache 是否有缓存. 首先,有一个概念,叫做 Request Context 请求上下文,一般来说,在一个 we ...
- hystrix基于request cache请求缓存技术优化批量数据查询接口
1.创建command,2种command类型 2.执行command,4种执行方式 3.查找是否开启了request cache,是否有请求缓存,如果有缓存,直接取用缓存,返回结果 首先,有一个概念 ...
- 数据查询接口Springboot
需求: 1.使用微博数据提供数据查询接口,通过微博编号查询微博,将热门数据缓存到redis中 基于Spring的网页端口查询,MVC分层构架 数据库数据 1001 [#蛇头将孩子扔过美墨边境墙# ...
- 通过Spring boot编写数据查询接口-----练习题
准备:在mysql中准备两张表 ,student表存学生信息的,score表存学生的各科成绩 studnet表 score表 例题: 一.通过班级名称查询班级人数(要求加入缓存,这里缓存用的数据库是r ...
- Active Record
class Data extends CI_Controller {function index(){echo 'Hwllo DBer';}//多结果标准查询(对象形式)function select ...
- Android开源库--ActiveAndroid(active record模式的ORM数据库框架)
Github地址:https://github.com/pardom/ActiveAndroid 前言 我一般在Android开发中,几乎用不到SQLlite,因为一些小数据就直接使用Preferen ...
最新文章
- 第四周作业 wcPro
- STM32使用非8M晶振时如何修改代码
- python 泛型_Python插件 - 如何创建C#泛型List
- gulp自动添加版本号
- 构造数列中的常见变形总结【中阶和高阶辅导】
- linux stm32 ide,一文教你如何在ubuntu上快速搭建STM32 CubeIDE环境(图文超详细+文末有附件)...
- spring将service添加事务管理,在applicationContext.xml文件中的设置
- js创建对象时,属性加引号与不加引号的区别(转)
- 10 年三线小城 IT 开发的感悟
- 简述static关键字、void与void *(void指针)、函数指针
- 微信小程序不行了?连接应用场景面临挑战
- 【Android驱动】屏和TP谁先休眠的问题
- Word排版——毕业论文专业排版3——编号+多级列表
- 第三名是最危险的名次
- 在线问诊配药的背后,看这家“数字化医院”如何守护数据流动安全
- JS - 11 - 原型、继承 -
- Java开发社招面试总结!docker镜像导出img格式文件
- Vue动态绑定class
- 3DMax基础:渲染的小技巧(做好笔记!)
- ubuntu mate在树莓派2上的安装
热门文章
- php 微盘系统教程,新版微盘API接口调用方法
- rtsp,rtp,gb28181直接转化为html5播放(二)
- vs2015 vs2017 编译zlib库
- c语言银行家算法模拟程序,C语言实现 操作系统 银行家算法
- 获取时间CLOCK_MONOTONIC学习——顺记第一次与开源项目交互
- android 悬浮组件,Android 悬浮组件
- linux5.5 里dns,linux red hat 5.5 dns 问题求解
- redis清理缓存_大话Redis问题
- 【kafka】Unexpected handshake request with client mechanism GSSAPI, enabled mechanisms are
- 95-40-014-生产者-KafkaProducer