如果对象仅存在于两个数组之一中,则删除记录



我有两个数组来表示用户表中的记录。

@server = [{ id: 1, name: "john" }, { id: 2, name: "Sarah" }, { id: 3, name: "George" }]
@client = [{ id: 1, name: "john" }, { id: 2, name: "Sarah" }]

我想运行一个函数来检查一个数组与另一个数组并删除 George 的记录,因为它们不再存在于@client

目前,我有这种相当长的方法,它有效但绝对不是最佳的。

@server.each do |item|
if @client.select{ |obj| obj[:id] == item.id }.length < 1
User.find(item.id).delete
end
end

解决此问题的最佳方法是什么?

你本质上是要求找到所有常见元素,这很容易用Array#&做到:

a = %w[ john sarah george ]
b = %w[ sarah john ringo ]
a & b
# => ["john", "sarah"]

这将找到两个集合的并集,或者换句话说,删除两个集合中不存在的条目。

要找出需要删除的那些,您还可以使用Array#-将它们减去:

to_delete = a - b

我可以想到两种不同的方法来做到这一点。

1)使用Array#-方法获取差异,并这样直接从数据库中删除这些条目;

ids_to_delete = (server - client).map { |entry| entry[:id] }
User.where(id: ids_to_delete).delete_all

2)第二种方法是让数据库引擎为您完成这项工作;

server_ids = server.map { |entry| entry[:id] }
client_ids = client.map { |entry| entry[:id] }
User.where(id: server_ids).where.not(id: client_ids).delete_all

我宁愿选择第一个选项,因为第二个查询最终可能会向数据库发送一个大查询,并且仅通过单元测试测试第一个解决方案会简单得多。

我将首先将两个集合映射到它们的 id:

server_user_ids = @server.map { |user| user[:id] }
client_user_ids = @client.map { |user| user[:id] }

然后,您可以使用以下方法删除所有用户:

User.where(id: server_user_ids - client_user_ids).delete_all

请注意,deletedelete_all都不会触发回调。如果要触发回调,请改用destroydestroy_all


如果@server@client可以容纳大型集合,我建议改用集合。它们的查找时间更快,但可读性会降低一点。

server_user_ids = @server.map { |user| user[:id] }.to_set
client_user_ids = @client.map { |user| user[:id] }.to_set
User.where(id: server_user_ids - client_user_ids).delete_all

我不确定where是否适用于集合。如果没有,请将上述更改为[*server_user_ids - client_user_ids],这会将结果集分散到数组中。还可以对生成的集调用to_a(server_user_ids - client_user_ids).to_a

相关内容

  • 没有找到相关文章

最新更新