情况:
我有用户模型。 db中的属性“meta_data”表示“text”类型字段。
在模型中,它按自定义类进行了序列化。 (serialize :meta_data, CustomJsonSerializer.new
)
这意味着,当我有一个用户实例时,我可以像使用Hash一样使用meta_data
。
User.first.meta_data['username']
问题:
我需要编写一个搜索功能,它将按给定的字符串搜索用户。我可以通过rails ex中的手动构建搜索查询来实现。 User.where("email LIKE '%#{string}%'")...
但是meta_data怎么样?我也应该通过LIKE语句搜索这个字段吗?如果我这样做,它将降低找到记录的相关性。
例如:
我有2个用户。其中一个有用户名“patrick”,另一个是“sergio”
db中的元数据将如下所示:1){username:patrick}
2){username:sergio}
我想找塞尔吉奥,我输入一个搜索字符串“ser”=>但我有2个结果,而不是一个。这个meta_data字符串“{uSERname:Patrick}”也有“ser”,所以它使这个记录无关紧要。
你知道如何解决它吗?
答案 0 :(得分:0)
这确实是序列化数据的问题。理论上,序列化可能是一种非常难以搜索的算法。它可以进行霍夫曼编码或其他压缩,并将序列化存储为二进制。您依赖于序列化使用JSON的假设,并且您的字符串仍然可以作为序列化中的子字符串找到。
那么你遇到的问题是另一个问题。序列化中的其他数据可能会弄乱您的结果。
通常,如果您序列化数据,则可以选择不可搜索。
因此,解决方案是添加一个以您控制的方式填充的其他字段。有一个值字段并存储可以搜索的管道(|)分隔值。因此,如果数据是{firstname:“Patrick”,姓氏:“Stern”},则您的meta_values字段可能是“Patrick | Stern”。
另外,不要将where方法与输入值扩展为#{}的字符串一起使用。这使它容易受到SQL攻击。而是使用:
where("meta_values is like :pattern", pattern: "%#{string}%")
我知道这可能看起来不太相似,但ActiveRecord会以这种方式进行消毒。如果有人在字符串中有一个分号,那么ActiveRecord将在搜索条件中转义分号。