我偶然发现了在我的模型like so中使用数组限制我的表和关联的想法。
我正在开发一个任务分配应用程序,用户将在本质上构造一个句子来执行操作。我使用关键字来帮助构建句子的边界。
示例包括(括号中的关键字):
所以这是我的迁移:
class CreateKeywords < ActiveRecord::Migration[5.1]
def change
create_table :keywords do |t|
t.string :name, null: false
t.text :pre, array: true, default: []
t.text :post, array: true, default: []
t.string :method, null: false, default: "read" # a CRUD indicator
end
end
end
keyword.post
表示关键字
keyword.pre
表示关键字
我的种子数据如下所示:
Keyword.create([
{ name: "i will", post: ["task"] },
{ name: "ask", post: ["user"] },
{ name: "assign", post: ["user", "task"] },
{ name: "find a", post: ["user", "task"] },
{ name: "make a new", post: ["user", "task"], method: "create" },
{ name: "finalize", post: ["task"] },
{ name: "archive", post: ["user", "task"], method: "delete" },
{ name: "update", post: ["user", "task"], method: "update" },
{ name: "for", post: ["user", "task"], pre: ["user", "task"] },
{ name: "to", post: ["user", "task"], pre: ["user", "task"] },
{ name: "and repeat", pre: ["task"] },
{ name: "before", pre: ["task"] },
{ name: "after", pre: ["task"] },
{ name: "on", pre: ["task"] }
])
现在我想做的事情如下:
key = Keyword.third
Keyword.where(pre: key.post)
但这会返回完全匹配,我想做类似的事情:
&#34;返回key.post
&#34;
Keyword.pre
的任何值的所有关键字
我在这些方面没有运气:
Keyword.where(pre.include? key.post)
我可以遍历所有关键字并使用AND:
results = []
Keyword.all.each do |k|
comb = k.pre & key.post
if comb.present?
results << k
end
end
results.map { |k| k.name }
但这感觉不好。
我对SQL所需的SQL有点深入了解。
任何指针?
答案 0 :(得分:1)
您想了解两件事:
array['a', 'b', 'c']
而不是更常见的'{a,b,c}'
语法。数组构造函数语法很方便,因为当ActiveRecord将数组视为占位符的值时,它会将数组扩展为逗号分隔列表,该列表与x in (?)
和x && array[?]
同样适用。
要运营商使用,您需要:
可以在
中找到key.post
Keyword.pre
的任何值的所有关键字
这是另一种表示key.post
和Keyword.pre
重叠的方式,其运算符为&&
。如果您需要稍微不同的逻辑,还有子集(<@
)和超集(@>
)运算符。
把它们放在一起:
Keyword.where('pre && array[?]', key.post)
或:
Keyword.where('pre && array[:post]', post: key.post)
lacostenycoder,在评论中,关注空数组是正确的。填充占位符时,ActiveRecord会将空数组扩展为单个null
,这样您最终可能会像以下那样执行SQL:
pre && array[null]
并且PostgreSQL无法确定array[null]
的类型。你可以加一个演员:
Keyword.where('pre && array[:post]::text[]', post: key.post)
# --------------------------------^^^^^^^^ tell PostgreSQL that this is an array of text
但是,由于pre && array[null]::text[]
永远不会成真,如果key.post.empty?
,你可以跳过整个事情。
空数组不会与任何其他数组(甚至不是另一个空数组)重叠,因此您不必担心ActiveRecord将使用它们的空数组。同样地,对于pre is null
,null && any_array
将永远不会成立(它实际上将评估为null
),因此不会与此类事物重叠。
答案 1 :(得分:0)
这实际上比你想象的容易得多:
Keyword.where("pre && post")
# testing vs your seed data plus a few I added returns:
#Keyword Load (1.0ms) SELECT "keywords".* FROM "keywords" WHERE (pre && post)
#[<Keyword:0x007fc03c0438b0 id: 9, name: "for", pre: ["user", "task"], post: ["user", "task"], method: "read">,
#<Keyword:0x007fc03c0435b8 id: 10, name: "to", pre: ["user", "task"], post: ["user", "task"], method: "read">,
#<Keyword:0x007fc03c043248 id: 15, name: "foo", pre: ["bar", "baz"], post: ["baz", "boo"], method: "read">,
#<Keyword:0x007fc03c042f28 id: 16, name: "rock", pre: ["anthem"], post: ["ballad", "anthem"], method: "read">,
#<Keyword:0x007fc03c042cf8 id: 17, name: "disco", pre: ["mood"], post: ["ballad", "anthem", "mood"], method: "read">]