首页 > 解决方案 > 如何使用片段作为更新变更集属性的一部分?

问题描述

我正在尝试使用新属性和与现有列交互的数据库调用来更新现有模型。类似于UPDATE companies SET a = 1, b = jsonb_set(b, '{key}', CURRENT_TIMESTAMP(), true)SQL 中的东西。

我将如何使用 Ecto 和 Fragments 实现这一目标?

这是我的尝试,但它失败了,因为它fragment是一个宏:

enhanced =
  %{ attrs | b: fragment(
    "jsonb_set(b, ?, CURRENT_TIMESTAMP(), true)",
    "{#{Atom.to_string(key)}}"
  )}
result =
  company
  |> Company.changeset(enhanced)
  |> Repo.update()

标签: elixirphoenix-frameworkecto

解决方案


通过使用片段宏Ecto.Query.update是要走的路。为此,我们需要将更新作为查询表达式的一部分。

{count, results} =
  Company
  |> where([c], <some_condition>)
  |> select([e], e) ## Optional: this will return our changes
  |> update(set: [
        string_field: "value",
        map_field: fragment(~S<jsonb_set("map_field"::jsonb, '{key_name_here}', 'value_here')>)
      ]
  |> Repo.update_all([])

用于避免在我们的片段中~S<…&gt;转义引号。"

通过用 a 替换字符串中的变量并将它们?添加为固定^参数,将变量添加到片段中。

fragment(~S<jsonb_set("map_field"::jsonb, '{?}', 'value_here')>, ^key)

推荐阅读