如何为特殊情况编写ActiveRecord查询

时间:2022-09-26 15:33:09

I am using Ruby on Rails 5.1, and I have an Entry model that has a word attribute. There can be multiple Entries with the same word, as their uniqueness is based on word plus another field. In the controller, I am creating a dropdown selector @unique_entries that should only include the first instance of an Entry.word.

我正在使用Ruby on Rails 5.1,我有一个具有word属性的Entry模型。可以有多个具有相同单词的条目,因为它们的唯一性基于单词加上另一个字段。在控制器中,我正在创建一个下拉选择器@unique_entries,它应该只包含Entry.word的第一个实例。

I have attempted to do this from multiple angles, but just can't seem to get it right.

我试图从多个角度来做这件事,但似乎无法做到这一点。

The last thing I tried was something like this pseudocode (sorry, I deleted the actual code after it failed):

我尝试的最后一件事是像这样的伪代码(对不起,我在失败后删除了实际的代码):

all_entries = Entry.all.order(word: :asc)
unique_entries = []
all_entries.each do |entry|
  if unique_entries.include?(entry.word)
    use the index to delete this record from all_entries
  else
    unique_entries << entry.word
  end
end

In my head at least, this should loop through the all_entries collection, checking to see if each entry.word is in unique_entries, which starts out as an empty array. If not, the entry.word gets added to unique_entries. If so, it removes the entry from the ActiveRecord collection all_entries, because that means one already exists. This approach failed hard, removing contents from a sample array inconsistently.

至少在我的脑海中,这应该循环遍历all_entries集合,检查每个entry.word是否在unique_entries中,最开始是一个空数组。如果不是,则entry.word被添加到unique_entries。如果是这样,它将从ActiveRecord集合all_entries中删除该条目,因为这意味着一个已经存在。这种方法很难,不一致地从样本数组中删除内容。

I realize this is a slow way to go, and will only be fine while I have a small number of records, so I am open to suggestions of other ways to approach this. I am still relatively new to RoR development and haven't had to deal with very complex ActiveRecord queries yet, so please don't step on my neck for not having already done what would have been "obvious" to you. Thanks.

我意识到这是一个缓慢的方法,只有在我有少量记录的情况下才会这样,所以我愿意接受其他方法的建议。我仍然是相对较新的RoR开发,并且还没有处理过非常复杂的ActiveRecord查询,所以请不要踩到我的脖子上,因为我还没有完成对你来说“显而易见”的事情。谢谢。

2 个解决方案

#1


2  

You can let the database do the work by using distinct and pluck together:

你可以让数据库通过使用distinct和pluck来完成工作:

Entry.distinct.pluck(:word)

And if you want the database to do the sorting:

如果您希望数据库进行排序:

Entry.distinct.order(:word).pluck(:word)

The last one should end up using SQL like this:

最后一个应该最终使用这样的SQL:

select distinct word from entries order by word

#2


1  

Try:

尝试:

@unique_entries = Entry.pluck(:word).uniq

Or:

要么:

@unique_entries = Entry.all.order(word: :asc).pluck(:word).uniq

To have it sorted.

让它排序。

To be a bit more descriptive, consider:

为了更具描述性,请考虑:

@unique_entry_words = Entry.all.order(word: :asc).pluck(:word).uniq

(since the array is, well, a set of unique entry words, not unique entries)

(因为数组是一组唯一的输入词,而不是唯一的条目)

Of course, mu is too short is correct and this would be better as:

当然,亩太短是正确的,这会更好:

Entry.distinct.order(:word).pluck(:word)

If, OTOH, you're trying to get an array comprised of the first instance of each Entry for a given word (not sure if that's what you're after, but that comment about 'use the index to delete...' suggests it might be), you could try something like:

如果,OTOH,你试图获得一个由给定单词的每个条目的第一个实例组成的数组(不确定这是你所追求的,但关于'使用索引删除...'的评论建议它可能是),你可以尝试类似的东西:

Entry.all.order(:word).group_by(&:word).map{|k,v| v.first}

#1


2  

You can let the database do the work by using distinct and pluck together:

你可以让数据库通过使用distinct和pluck来完成工作:

Entry.distinct.pluck(:word)

And if you want the database to do the sorting:

如果您希望数据库进行排序:

Entry.distinct.order(:word).pluck(:word)

The last one should end up using SQL like this:

最后一个应该最终使用这样的SQL:

select distinct word from entries order by word

#2


1  

Try:

尝试:

@unique_entries = Entry.pluck(:word).uniq

Or:

要么:

@unique_entries = Entry.all.order(word: :asc).pluck(:word).uniq

To have it sorted.

让它排序。

To be a bit more descriptive, consider:

为了更具描述性,请考虑:

@unique_entry_words = Entry.all.order(word: :asc).pluck(:word).uniq

(since the array is, well, a set of unique entry words, not unique entries)

(因为数组是一组唯一的输入词,而不是唯一的条目)

Of course, mu is too short is correct and this would be better as:

当然,亩太短是正确的,这会更好:

Entry.distinct.order(:word).pluck(:word)

If, OTOH, you're trying to get an array comprised of the first instance of each Entry for a given word (not sure if that's what you're after, but that comment about 'use the index to delete...' suggests it might be), you could try something like:

如果,OTOH,你试图获得一个由给定单词的每个条目的第一个实例组成的数组(不确定这是你所追求的,但关于'使用索引删除...'的评论建议它可能是),你可以尝试类似的东西:

Entry.all.order(:word).group_by(&:word).map{|k,v| v.first}