使用Rails查询返回单个字段

时间:2012-03-03 02:39:02

标签: mysql ruby-on-rails activerecord hash

我遇到的问题应该很容易,但我不知道我做错了什么。我只是尝试执行一个返回单个字段的查询,而不是Rails 3中的完整记录。

模型方法

def self.find_user_username(user_id)
  user_name = User.select("user_name").where(user_id)
  return user_name
end

我正盯着Rails指南(http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields) 它只是说(其中viewable_by,locked = fields):

Client.select("viewable_by, locked")

我试过翻转选择,就像这样:

User.select("user_name").where(user_id) - AND - 
User.where(user_id).select("user_name")
但是没有工作。事实上,我甚至尝试过:

user_name = User.select("yoda").where(user_id)

我没有收到错误。当我查看视图时,我在哪里:

Friend.find_user_username(friend.user_id)

我只是不断获取哈希:ActiveRecord :: Relation:0x2f4942f0

7 个答案:

答案 0 :(得分:22)

User.where(:id => user_id).pluck(:user_name).first

应该做你想做的事。

pluck“接受列名作为参数,并返回指定列的值数组以及相应的数据类型”

答案 1 :(得分:1)

您需要添加.first以强制查询返回记录,因为where仅返回activerecord关系。

1.9.3p0 :048 > user = User.select('first_name').where('id = 1').first
  User Load (0.6ms)  SELECT first_name FROM `users` WHERE (id = 1) LIMIT 1
+------------+
| first_name |
+------------+
| Johnny     |
+------------+
1 row in set

1.9.3p0 :049 > user.first_name
=> "Johnny" 

答案 2 :(得分:1)

您的问题不是select,而是where。您现在的状况基本上是WHERE #{user_id}。如果您在Rails控制台上执行此操作,您会看到如下内容:

1.9.2p290 :003 > puts User.select('user_name').where(1).to_sql
SELECT user_name FROM "users" WHERE (1)

您需要将条件作为哈希值传递给where,并按照其他人的建议获取第一条记录:

User.select('user_name').where(:id => user_id).first

答案 3 :(得分:1)

很多人提到.pluck。它确实有一个警告,它返回用于找到记录的列的数组。

如果列是唯一的,例如id,那么这不是问题,数据库将使用或不使用limit(1)向Active Record发送相同的内容,即1记录1列。使用它是没有用的,并且最肯定的是它将被数据库查询优化器丢弃。

但是,如果列不是唯一的,那么实际上这可能是一个更大的问题。 AR执行数据库查询后,将调用first,并返回[0]从数据库中获得的结果。 limit,之前被调用,并作为查询的一部分发送到数据库。

请考虑以下表格和设置:

> Log
=> Log(id: integer, user_id, integer, event_type: integer, timestamp: datetime)

> user_newest_logs = Log.where(user_id: 1).order(timestamp: :desc)

现在,让我们获取user_id = 1的最后一个事件日期时间:

1)这是最好的方法

> user_newest_logs.limit(1).pluck(:timestamp).first
SELECT timestamp FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC LIMIT 1
=> Fri, 09 Aug 2019 23:00:00 UTC +00:00

2)都从数据库中检索相同的数据

> user_newest_logs.first
SELECT * FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC LIMIT 1
=> #<Log:0x00111111>
 id: 920821839,
 user_id: 1,
 event_type: 1,
 timestamp: Fri, 09 Aug 2019 23:00:00 UTC +00:00

> user_newest_logs.first.timestamp
SELECT * FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC LIMIT 1
=> Fri, 09 Aug 2019 23:00:00 UTC +00:00

3)都从数据库中检索相同的数据

> user_newest_logs.pluck(:timestamp)
SELECT timestamp FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC
=> [Fri, 09 Aug 2019 23:00:00 UTC +00:00,
Fri, 09 Aug 2019 22:00:00 UTC +00:00,
Fri, 09 Aug 2019 21:00:00 UTC +00:00,
Fri, 09 Aug 2019 20:00:00 UTC +00:00,
...
]

> user_newest_logs.pluck(:timestamp).first
SELECT timestamp FROM logs WHERE logs.user_id = 1 ORDER BY logs.timestamp DESC
=> Fri, 09 Aug 2019 23:00:00 UTC +00:00

> user_newest_logs.pluck(:timestamp).count    # NOT PRETTY HUH?!
=> 1523

因此,如果您这样做,pluck(:column).first实际上可能比仅仅find_by.column更糟糕。

答案 4 :(得分:0)

看起来虽然没有返回每个字段,但查询确实返回了一个对象而不是特定字段的值。您可以将return user_name的返回值更改为return user_name.user_name

def self.find_user_username(user_id)
  user_name = User.select("user_name").where(user_id)
  return user_name
end

或者您可能会看到User.user_name.where(user_id).first是否能满足您的需求。

答案 5 :(得分:0)

顺便说一句,如果问题是关于ActiveRecord :: Relation它是由where和select返回的对象的类,正如你在阅读的Rails指南中所说的那样。 它被优化为在几个方法之间链接,并且在实际访问关联的元素时获得模型对象(因此在幕后SQL查询只运行一次)。这意味着你得到了Relation对象,因为你只需返回它。

在这种情况下,最好的解决方案可能就是使用find并访问user_name属性

def self.find_user_username(user_id)
  User.find(user_id).user_name
end

查询将从数据库获取所有其他属性,但您只返回用户名。

答案 6 :(得分:0)

有一种名为'pluck'的方法,请参考http://apidock.com/rails/ActiveRecord/Calculations/pluck