【问题标题】:How to filter a models field by multiple values (OR'd)如何按多个值过滤模型字段(OR'd)
【发布时间】:2019-07-21 17:40:26
【问题描述】:

我有一个模型说Book,它具有以下作用域函数:

scope :author, lambda { |author|
    return where(nil) unless author.present?
    joins(:author).where('author.id' => author)
  }

这可以过滤只有一个作者值的书籍。我想要做的是,我从一个 JavaScript 文件中传递了一个数组,它是一个作者列表,例如:["harry", "doyle", "alex", "parrish"],我希望能够找到所有拥有这些作者的所有书籍(所以一个 OR 查询这里)。请注意,每本书可以有多个作者。

我尝试了以下功能,但它只是给了我所有的书,而不是像我上面所说的那样正确过滤。

scope :authors_multiple, lambda { |authors|
  @results = Book
  authors.each do |auth|
    @results = @results.author(auth)
  end
  return @results
}

模型作者(摘录):

class Author < ApplicationRecord
  has_and_belongs_to_many :books, uniq: true
  ....

模型书(摘录):

class Book < ApplicationRecord
  has_and_belongs_to_many :authors, uniq: true
  ....

请您帮助我了解我做错了什么或正确的方法。提前致谢。

【问题讨论】:

  • 你能添加你的关系和架构吗?书有单数关系author。您如何为一本书存储多个作者?

标签: javascript ruby-on-rails ruby input-filtering


【解决方案1】:
authors = ["harry", "doyle", "alex", "parrish"]  
Book.where(author: authors)

authors = ["harry", "doyle", "alex", "parrish"]  
auths = Author.where(name: authors)
Book.where(author: auths)

这假设一个作者有很多书。 您可以在此处了解有关模型关联的更多信息:https://guides.rubyonrails.org/association_basics.html

【讨论】:

  • SQLite3::SQLException: no such column: books.author: SELECT "books".* FROM "books" WHERE "books"."title" = ? AND "books"."year" = ? AND "books"."author" IN ('harry', 'doyle', 'owen', 'hall', 'shelby', 'whyte', 'alex', 'parrish') ORDER BY "books"."published_at" DESC
  • 您能提供您的 structure.sql 文件的副本吗?听起来您没有名为“作者”的列。
【解决方案2】:

首先,您需要获取您的 Author 记录。这如何完成取决于您的架构和数据,但它类似于:

author_names = ["harry", "doyle", "alex", "parrish"]

然后是以下之一:

authors = Author.where(name: author_names)
authors = Author.where("name ILIKE ANY ( array[?] )", author_names.map { |name| "%#{name}%" })

让我们得到我们需要的作者ActiveRecord::Relation 的东西。一旦我们有了作者,我们就可以将其与我们的书籍合并以获得我们想要的所有书籍:

books = Book.joins(:authors).merge(authors)

请注意,连接是在复数作者s上。 Rails 将知道通过连接表(默认为 authors_books)连接到 authors 表。

【讨论】:

  • 嘿,我知道我们可以使用Author.find_by(name: auth).try(:id) 将字符串作者转换为实际作者
  • Author.where(name: author_names) 这将采用数组,就像 find_by 使用单个名称一样。使用where 将阻止记录加载,并将它们留在合并操作所需的ActiveRecord::Relation 中。如果列出的名称正是数据库中的名称,您可以使用Book.joins(:authors).merge(Author.where(name: author_names))
【解决方案3】:

你会得到一组作者姓名,对吧?

scope :by_author, lambda { |names|
  # if you have a chance to get blank values you need to reject them
  names.reject!(&:blank?) if names.is_a? Array

  joins(:authors).where(authors: { name: names }).distinct if names.present?
}

它应该与数组或字符串参数一起正常工作

Book.by_author(["harry", "doyle"])
Book.by_author("harry")

【讨论】:

    【解决方案4】:

    试试下面的代码:

    authors = ["harry", "doyle", "alex", "parrish"]    
    Book.joins(:authors).where(:authors => {:name => authors})
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 1970-01-01
      • 1970-01-01
      • 2021-12-30
      • 1970-01-01
      • 2023-03-16
      • 2013-10-20
      相关资源
      最近更新 更多