Rails中的Acvtice Record使得我们不用写SQL语句就可以查询数据库中的数据。
当使用Rails中的方法查询数据时,过程大体是这样的:
- 将查询选项转为sql语句
- 触发sql语句在数据库中查询
- 将查询结果实例化(变成对应的模型对象)
1– 查询单个对象
(1)find方法
find方法用于查询指定主键的对象;Author.find(1)
(2) find_by方法
find_by 方法会查询到符合条件的第一条记录Author.find_by(:name => "鲁迅")
也可以写成Author.find_by name: "鲁迅"
(3)take方法
take方法会查询到一条记录,往往是数据表中的第一条记录。Author.take
2– 查询多个对象
我们常常使用each方法,用来检索数据表中的记录。它的原理是会让Active Record 捞出整个数据表的数据,然后对每条记录创建模型对象,并把整个模型对象以数组形式保存在内存中。如果数据量很多的话,这样明显是行不通的。Rails有两种方法可以解决这个问题:
(1)find_each
工作原理:find_each方法每次检索一批记录,然后把每条记录实例化成模型对象传入块。默认每次检索1000条记录。1
2
3Player.find_each do |player|
player.name
end
a. 使用batch_size 来指定每次检索的记录总数1
2
3Player.find_each(batch_size: 5000) do |player|
player.name
end
b. 使用start
实现从起始点进行ID检索 ,比这个ID小的都不会取回。并且这个ID必须是主键。平常情况下较少用这个方法。1
2
3
4# 检索id从10开始的作者姓名
Player.find_each(start: 10) do |player|
player.name
end
c.使用finish
实现从起始点进行ID检索,比这个ID大的都不取回。与start
类似。1
2
3
4# 检索id为10000到20000的作者姓名
Player.find_each(start: 10000, finish: 20000) do |player|
player.name
end
(2)find_in_batches
工作原理:find_in_batches 方法每次检索一批记录,然后把每批记录实例化成模型数组传入块。用法和find_each
类似。
3.条件查询
(1)数组条件中的占位符
a. ?1
2
3$ Player.where("age >= ?", params[:age])
或者
$ Player.where("player.age >= ?", params[:age])
b. 字符
如果条件中有很多变量,那么以下做法会更易于代码的阅读。1
$ Player.where("age >= :age AND saler >= :wage_level_", { age: params[:age], wage_level: params[:wage_level]})
(2)使用not
反向查询
查询年龄在30岁以上的玩家1
2
3$ Player.where("diamond > ?", 30)
也可以写成
$ Player.where.not(" diamond <= ?", 30)
4. 查询特定字段
使用find、find_by、where方法时会返回table的全部字段,若想返回指定的字段可以使用select
,比如查询年龄大于20 的玩家名字。
(1) select方法1
2
3
4
5Player.select(:name).where("age >= ?", 30)
查询名字和id
Player.select(:userid, :name).where("age >= ?", 30)
&
Player.select("userid, name").where("age >= ?", 30)
(2)pluck方法
pluck 方法与select方法不同,select返回是一组对象模型,pluck方法是返回字段数组,因此在数据量很大的情况下使用pluck会好很多。1
2
3
4
5
6Player.select(:nickname, :userid).map{ |u| [u.userid, u.nickname]}
相当于
Player.pluck(:nickname, :userid)
PS:map 的另一种写法
Player.select(:userid).map(&:userid)
pluck方法会触发即时查询,个人理解为立即查询,所以当其他查询在pluck之前时,会执行成功;在pluck之后时,会查询失败。例如:1
2
3Player.pluck(:userid).limit(5) #=> undefined method `limit
Player.limit(5).pluck(:userid) #=> [1], [2], [3], [4], [5]
(3)ids方法
ids方法会获得模型的主键,rails中模型主键默认为id,返回的是数组。1
2
3
4
5
6
7
8
9
10
11class Player < ApplicationRecord
self.primary_key = "userid"
end
Player.ids
相当于
Player.pluck(:userid)
或
Player.select(:id).map(&:userid)
或
Player.select(:id).map{ |u| u.userid}
5.关联查询
(1) joins 方法
示例代码:1
2
3
4
5
6
7class Player < ApplicationRecord
has_many :groups, class_name: "GroupMsg", foreign_key: "userid"
end
class GroupMsg < ApplicationRecord
belongs_to :owner, class_name: "Player", foreign_key: "userid"
end
1 | $ GroupMsg.joins(:owner) |
这条语句的意思为所有属于某个用户的圈子作为一个GroupMsg对象返回。1
2
3$ GroupMsg.joins(:owner).where(:userid => 2)
查询结果相当于
$ Player.find_by(userid: 2).groups
1 | $ Player.joins(:groups) |
这条语句的意思为查询所有创建了圈子的用户作为Player对象返回(可以简单理解为查询创建过圈子的用户)。如果一个用户创建了很多圈子,那么也会被重复列出。
(2)includes方法
includes可以解决N+1queries问题,因为它可以及早加载关联。1
Player.includes(:groups)
这条命令会取出所有的用户和所有的关联圈子。
对应的SQL语句为1
2
3#=> 假设只有五个用户
select * from players
select * from group_msgs where group_msgs.userid in (1,2,3,4,5)
1 | GroupMsg.includes(:owner) |
这个命令会捞出所有的圈子和相关联的用户。
对应的SQL语句为1
2select * from group_msg
select * from players where player.userid = [2,3,4]