• 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) 等同于 

SELECT  "products".* FROM "products" ORDER BY "products"."id" ASC LIMIT ?  [["LIMIT", 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 联结表

连个方法:

  1. joins: 对应SQL的 INNER JOIN ...ON
  2. 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")


Active Record Query Interface 数据查询接口(界面) 看到第8节。的更多相关文章

  1. 阶段5 3.微服务项目【学成在线】_day09 课程预览 Eureka Feign_10-课程详情页面静态化-课程详情模型数据查询接口

    根据课程详情页面写一个获取数据模型的接口 目录的数据来自于课程计划表 右侧是课程的图片 需要写一个接口 获取课程相关的所有信息. 所以就需要一个模型类,里面包含了基本信息.图片信息.等各种详情页面的信 ...

  2. Active Record 数据库模式-增删改查操作

    选择数据 下面的函数帮助你构建 SQL SELECT语句. 备注:如果你正在使用 PHP5,你可以在复杂情况下使用链式语法.本页面底部有具体描述. $this->db->get(); 运行 ...

  3. Android开源库--ActiveAndroid(active record模式的ORM数据库框架)

    Github地址:https://github.com/pardom/ActiveAndroid 前言 我一般在Android开发中,几乎用不到SQLlite,因为一些小数据就直接使用Preferen ...

  4. Dynamics CRM 2015/2016 Web API:新的数据查询方式

    今天我们来看看Web API的数据查询功能,尽管之前介绍CRUD的文章里面提到过怎么去Read数据,可是并没有详细的去深究那些细节,今天我们就来详细看看吧.事实上呢,Web API的数据查询接口也是基 ...

  5. hibernate框架学习第五天:数据查询、投影等

    复习day1环境搭建CRUD操作DB6个核心的APIday2TO PO DO 及其状态切换OID 自然主键 代理主键(uuid)一级缓存 Session绑定 load/get关系1对1 1对多(重点) ...

  6. 架构模式数据源模式之:表数据入口(Table Data Gateway)、行数据入口(Row Data Gateway)、活动记录(Active Record)

    一:表数据入口(Table Data Gateway) 表数据入口提供了用于访问单个表或者视图(也包含了联表查询)的所有SQL,通常一个表一个类.其它代码通过它来实现对数据库的交互.基于这个特点,表数 ...

  7. 2017.2.21 activiti实战--第十三章--流量数据查询与跟踪(一)查询接口介绍及运行时数据查询

    学习资料:<Activiti实战> 第十三章 流量数据查询与跟踪 本章讲解运行时与历史数据的查询方法.主要包含三种:标准查询,Native查询,CustomSql查询. 13.1 Quer ...

  8. Yii Active Record 查询结果转化成数组

    使用Yii 的Active Record 来获取查询结果的时候,返回的结果集是一个对象类型的,有时候为了数据处理的方便希望能够转成数组返回.比如下面的方法: // 查找满足指定条件的结果中的第一行 $ ...

  9. Yii2 三层设计模式:SQL Command、Query builder、Active Record(ORM)

    用Yii2也有一段时间了,发现Yii2 Framework对Database的操作有非常良好的结构和弹性. 接下来介绍三种数据库操作方式. SQL Command Level: // Get DB c ...

随机推荐

  1. PHP洗牌、猴子选大王两个小算法

    <一>洗牌算法 /** *洗牌算法washCard *@param $cardNum *@return array */ function washCard($cardNum) { $ca ...

  2. 梳理vue双向绑定的实现原理

    Vue 采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后 ...

  3. Excel控制AutoCad进行坐标标注

    做过工程测绘,平面设计,使用过Autocad制图的朋友们,都经常要在CAD上标注点或者线的坐标,CAD自身的标注功能,并不能同时标注X和Y坐标,,要同时标注X和Y坐标,可以使用南方CASS软件,或者一 ...

  4. Centos7 创建内部的yum源

  5. 2018-2019-20175205 实验三敏捷开发与XP实践《Java开发环境的熟悉》实验报告

    2018-2019-20175205 实验三敏捷开发与XP实践<Java开发环境的熟悉>实验报告 实验要求 没有Linux基础的同学建议先学习<Linux基础入门(新版)>&l ...

  6. 2018-2019-2 网络对抗技术 20165305 Exp4 恶意代码分析

    Exp4 恶意代码分析 1.实践目标 1.1是监控你自己系统的运行状态,看有没有可疑的程序在运行. 1.2是分析一个恶意软件,就分析Exp2或Exp3中生成后门软件:分析工具尽量使用原生指令或sysi ...

  7. RESTClient 使用

    Wisdom RESTClient 一款自动化测试REST API的工具,它可以自动化测试RESTful API并生成精美的测试报告,同时基于测试过的历史API,可以生成精美的RESTful API文 ...

  8. 论文笔记【三】A Deep Dive into Word Sense Disambiguation with LSTM

    深入理解LSTM词义消歧 Minh Le,Marten Postma,Jacopo Urbani和Piek Vossen 阿姆斯特丹自由大学语言,文学和传播系 阿姆斯特丹自由大学计算机科学系 摘要 基 ...

  9. datasnap 的HTTP 调用返回JSON

    datasnap 相关设置,就不细说了,直接上函数 uses System.JSON function TServerMethods.Updatehello: Tjsonobject; var tem ...

  10. 防止sql注入(简单)

    (1)mysql_real_escape_string -- 转义 SQL 语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集 使用方法如下: $sql = "select count ...