ruby on rails查询

2018-05-07  本文已影响0人  Lucien_d70a

find 方法

User.find(id)  => 直接主键(id)查询
User.find(id,id2)  => 查询多个

take 方法

User.take(number)  => 返回 number 条数据
User.take  => 返回一条数据 并无视排序
User.take(2)  => 返回2条数据

first 方法

Client.first(number)  => 返回前 number 条数据
User.first  => 返回第一条数据

PS:first! 方法的行为和 first 方法类似,区别在于如果没有找到匹配的记录,first! 方法会抛出 ActiveRecord::RecordNotFound 异常。

last 方法

User.last(number)  => 返回后 number 条数据
User.last  => 返回最后一条数据

find_by 方法

User.find_by nickname: 'cwhh'  => 找到 nickname 是 cwhh 的数据

PS:find_by! 方法的行为和 find_by 方法类似,区别在于如果没有找到匹配的记录,find_by! 方法会抛出 ActiveRecord::RecordNotFound 异常。

find_each 方法

User.find_each do |user|
 p user
end
=>  User 里面所有 user 数据
User.find_each(batch_size: 5000) do |user|
 p user
end
=> 检索 5000 条 打印 5000个 user 数据
User.find_each(start: 主键) do |user|
  p user
end
=> 打印出从主键开始 到最后的 user 数据
User.find_each(start: 开始的主键, finish: 结束的主键) do |user|
 p user
end
=> 打印从 start 开始,finish结束的所有 user 数据

find_in_batches方法

User.find_in_batches do |user|
  p user
end
=> 打印出 User 的所有user 的一个组合

PS: 和 find_each 类似,但是它是一次过将数据的组合传入块

条件查询

# 最简单一个例子
User.where("nickname = 'cwhh'")
=> 会查处所有 nickname为 cwhh 的用户

PS:上面的例子及其不安全,很容易受到 SQL 注入攻击的风险,要像下面这样写。

# 推荐写法
User.where("nickname = ?",'cwhh')
=> 会查出所有 nickname为 cwhh 的用户

# 多条件查询
User.where("nickname= ? AND status = ?", params[:name], false)
=> 会查处所有 nickname 为传入 参数对应 并且 状态 为 false 的所有用户

# 如果条件中有很多变量,那么上面这种写法的可读性更高。
Client.where("created_at >= :start_date AND created_at <= :end_date", {start_date: params[:start_date], end_date: params[:end_date]})
=> 查询 创建时间 大于等于传入开始时间,并且小于传入结束时间的 所有数据。
# 如果查询的是个数组
Course.where("'#{params[:id]}' = ANY (teachers)")
=> 查出 传入老师id对应的所有课程。
User.where(nickname: 'cwhh')  => 查出所有 nickname 是 cwhh 的数据
User.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
=> 查出 创建时间 是 现在时间减去一天,到现在傍晚的 所有数据
Client.where.not(nickname: 'cwhh')  => 查询所有 nickname 不是 cwhh 的所有数据

排序

User.order(:created_at)
# 或
User.order("created_at")
=> 按创建时间排序 输出所有 User 数据
User.order(created_at: :desc)
# 或
User.order(created_at: :asc)
# 或
User.order("created_at DESC")
# 或
User.order("created_at ASC")
=> 输出创建时间 升序 或者 降序的所有数据。
User.order(orders_count: :asc, created_at: :desc)
=> 输出订单数量降序,创建时间升序的所有数据

选择特定字段

Client.select("viewable_by, locked")
=> 输出 client 所有数据的 viewable_by 字段 和 locked 字段。

# 输出数据无重复
Client.select(:name).distinct
=> 输出 Client 所有数据里的 name 字段,并且不带重复
User.select{ |user| user.realname  }
=> 输出 realname 有值的数据
User.select{ |user| user.realname == nil }
=> 输出 所有 realname 没有值的数据

限量和偏移量

User.limit(5)
=> 打印5条user数据

User.limit(5).offset(30)
=> 打印5条user数据 从第31条开始

条件覆盖

User.where.not('nickname = ?','nil').limit(2).unscope(:limit)
=> 找到nickname不是空的user数据,unscope(:limit) 把limit限制给删除了

User.where.not('nickname=? AND realname=?','cwhh','123123').unscope(where: :realname)
=> 还可以把where的某条件删除

空关系

User.none
=> 返回一个空 Relation 对象,而且不执行查询

联结表

class Category < ApplicationRecord
  has_many :articles
end
 => 一个创造者拥有多篇文章

class Article < ApplicationRecord
  belongs_to :category
  has_many :comments
  has_many :tags
end
=> 一篇文章 只有一个创造者
=> 一篇文章 拥有多个评论
=> 一篇文章 拥有多个标签
 
class Comment < ApplicationRecord
  belongs_to :article
  has_one :guest
end
=> 一个评论 只有一对应一篇文章
=> 并且一个评论只对应一个客人
 
class Guest < ApplicationRecord
  belongs_to :comment
end
=> 一个客人对应一个评论
 
class Tag < ApplicationRecord
  belongs_to :article
end
=> 一个标签对应一篇文章
Category.joins(:articles)
=> 拥有文章的作者都打印出来
=> 如果这个作者有多篇文章,那么这个作者将会出现多次。

# 如果不想重复,可以
Category.joins(:articles).distinct
Article.joins(:category, :comments)
=> 打印出属于某个作者至少有一条评论的Article数据打印出来
=> 注意,依然会重复。
Article.joins(comments: :guest)
=> 打印出,拥有客人评论的文章数据
Category.joins(articles: [{ comments: :guest }, :tags])
=> 把拥有评论,拥有标签的文章创建者打印出来

及早关联

clients = Client.limit(10)
 
clients.each do |client|
  puts client.address.postcode
end

# 这里查询 存在查询过多的问题 每条 client 都是去找他对应的address 和 postcode
#一共要找 1+10次address+10次postcode

# 作出改动
clients = Client.includes(:address).limit(10)
 
clients.each do |client|
  puts client.address.postcode
end
=> 这里一早把拥有地址的client 都找出来 然后再去找postcode,所以只执行了2次查询
Article.includes(:category, :comments)
=> 上面的代码会加载所有文章、所有关联的分类和每篇文章的所有评论。
Category.includes(articles: [{ comments: :guest }, :tags]).find(1)
=> 上面的代码会查找 ID 为 1 的分类,并及早加载所有关联的文章、这些文章关联的标签和评论,以及这些评论关联的访客。
User.includes(:user_grounp).where(:user_grounp,  {name: :teacher})
=> 提早关联有只有teacher小组里的的user用户数据 
User.includes(:user_groups).where('user_groups.name=?','teacher').references(:user_groups)

作用域

#写在model里的
class User < ApplicationRecord
  scope :sex, -> { where(sex: '男') }
end
#这两种方法达到的效果相同
class User < ApplicationRecord
  def self.sex
    where(sex: '男')
  end
end
class User < ApplicationRecord
  scope :sex,               -> { where(sex:  '男') }
  scope :sex_and_age, -> { sex.where("age > 18") }
end
user = User.first
user.sex
class User < ApplicationRecord
  scope :created_before, ->(time) { where("created_at < ?", time) }
end

# 调用都是一样的
user = User.first
user.created_before(Time.now)

#当作用域需要接受参数时,推荐改用类方法。使用类方法时,这些方法仍然可以在关联对象上访问:
class Article < ApplicationRecord
  def self.created_before(time)
    where("created_at < ?", time)
  end
end

#调用一样的
user.user_groups.created_before(time)
class Article < ApplicationRecord
  scope :created_before, ->(time) { where("created_at < ?", time) if time.present? }
end

class Article < ApplicationRecord
  def self.created_before(time)
    where("created_at < ?", time) if time.present?
  end
end
class Client < ApplicationRecord
  default_scope { where("removed_at IS NULL") }
end

class Client < ApplicationRecord
  def self.default_scope
    # 应该返回一个 ActiveRecord::Relation 对象
  end
end

默认作用域在创建记录时同样起作用,但在更新记录时不起作用。例如:

合并作用域

class User < ApplicationRecord
  scope :active, -> { where state: 'active' }
  scope :inactive, -> { where state: 'inactive' }
end
 
User.active.inactive
# 混用where 方法 
User.active.where(state: 'finished')

class User < ApplicationRecord
  default_scope { where state: 'pending' }
  scope :active, -> { where state: 'active' }
  scope :inactive, -> { where state: 'inactive' }
end
 
User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'
 
User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'active'
 
User.where(state: 'inactive')
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'inactive'

有一点需要特别注意,default_scope 总是在所有 scope 和 where 之前起作用。
在上面的代码中我们可以看到,在 scope 条件和 where 条件中都合并了 default_scope 条件。

enum 宏

enum status: {activation: 1, not_activation: 2}
User.create(name:'cwh',age:'18',status: 'activation')
User.find_by_name('cwh')
=> 这时候存到数据库时候 status 就是 1
=> 输出的时候 status 就是 activation

find_or_create_by 方法

这个方法 如果找到 就返回这个数据,没有找到就 创建一条这样的数据

find_or_initialize_by 方法

此方法和find_or_create_by差不错,只不过不是创建时候是new,不是create,要手动保存

使用 SQL 语句进行查找

Client.find_by_sql("SELECT * FROM clients
  INNER JOIN orders ON clients.id = orders.client_id
  ORDER BY clients.created_at desc")

pluck方法

User.pluck(:nickname)
=> 返回的是所有名字的一个组合的一个数组

检查对象是否存在

User.exists?  => true
User.exists?(id: [1,2,3])  => 只要有一条对应记录存在就会返回 true
User.exists?(nickname: 'cwhh')  => true
User.exists?(nickname: '1231231231')  => false

计算

User.count => 200

上一篇 下一篇

猜你喜欢

热点阅读