我正在努力完成智能插入,我将其定义为:
我看到repo.insert有将查询作为:on_conflict选项传递的选项。我决定编写最简约的源代码来满足我的需求。
update_query =
from s in User,
where: s.id == ^id,
where: s.updated_at < ^updated_at,
update: ^[set: Map.to_list(data)]
%User{}
|> Ecto.Changeset.change(data)
|> @repo.insert(conflict_target: :id, on_conflict: update_query)只有在插入发生时,此代码才能工作。在冲突中,它会导致(Ecto.StaleEntryError) attempted to insert a stale struct:错误。我可以从where: s.id == ^id, where: s.updated_at < ^updated_at中删除update_query并删除此错误,但是这样就会丢失所需的updated_at检查。所需的postgres代码如下所示
INSERT INTO mytable (id, entry) VALUES (42, '2021-05-29 12:00:00')
ON CONFLICT (id)
DO UPDATE SET entry = EXCLUDED.entry, ......
WHERE mytable.entry < EXCLUDED.entry;发布于 2021-06-29 17:58:43
我认为这样做可能更容易:
def smart_upsert(%{id: id, updated_at: updated_at} = data) do
query =
from u in User,
where: u.id == ^id,
where: u.updated_at < ^updated_at
User
|> Repo.get_by(query)
|> case do
nil ->
%User{}
existing_user ->
existing_user
end
|> User.changeset(data)
|> Repo.insert_or_update()
end诚然,这需要两个数据库操作。
https://stackoverflow.com/questions/68182807
复制相似问题