Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

174
Vistas
¿Ecto insert_or_update creando múltiples inserciones?

Mi código está dando como resultado una rara inserción doble o triple en la base de datos y no sé por qué. Es muy difícil de reproducir, pero puedo mirar las marcas de tiempo para ver que el tiempo creado es básicamente el mismo cuando sucede. Creo que solo ocurre cuando CardMeta no se encuentra.

Me imagino que necesito agregar una clave única o envolverla en una transacción.

 def get_or_create_meta(user, card) do case Repo.all(from c in CardMeta, where: c.user_id == ^user.id, where: c.card_id == ^card.id) do [] -> %CardMeta{} metas -> hd metas end end def bury(user, card) do get_or_create_meta(user, card) |> Repo.preload([:card, :user]) |> CardMeta.changeset(%{last_seen: DateTime.utc_now(), user_id: user.id, card_id: card.id, learning: false, known: false, prev_interval: 0}) |> Repo.insert_or_update end

Editar: agregar fuente de conjunto de cambios

 def changeset(struct, params \\ %{}) do struct |> cast(params, [:last_seen, :difficulty, :prev_interval, :due, :known, :learning, :user_id, :card_id]) |> assoc_constraint(:user) |> assoc_constraint(:card) end

Llamando a enterrar desde el controlador

 def update(conn, %{"currentCardId" => card_id, "command" => command}) do # perform some update on card card = Repo.get!(Card,card_id) user = Guardian.Plug.current_resource(conn) case command do "fail" -> SpacedRepetition.fail(user, card) "learn" -> SpacedRepetition.learn(user, card) _ -> SpacedRepetition.bury(user, card) end sendNextCard(conn, user) end

Editar:

Noté que el campo last_seen tiene una diferencia de microsegundos entre filas duplicadas, mientras que el campo create_at no tiene esa resolución. Por lo tanto, sospecho que la llamada insert_or_update está bien, pero el controlador se dispara dos veces antes de que se actualice la base de datos. Esto podría ser algo del lado del cliente, en lo que no quiero pensar. Así que solo voy a agregar una clave única.

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Como alternativa a la respuesta de @aliCna, si no desea cambiar la clave principal en CardMeta , puede poner una restricción de índice única en la base de datos con una migración:

 defmodule YourApp.Repo.Migrations.AddCardMetaUniqueIndex do use Ecto.Migration def change do create unique_index( :card_meta, [:card_id, :user_id], name: :card_meta_unique_index) end end

Que luego puede manejar en su conjunto de cambios para producir buenos errores si ocurren conflictos:

 def changeset(struct, params \\ %{}) do struct |> cast(params, [:last_seen, :difficulty, :prev_interval, :due, :known, :learning, :user_id, :card_id]) |> assoc_constraint(:user) |> assoc_constraint(:card) |> unique_constraint(:user_id, name: :card_meta_unique_index) end
over 4 years ago · Santiago Trujillo Denunciar

0

Creo que puede resolver esto agregando una clave principal compuesta en user_id y card_id

 defmodule Anything.CardMeta do use Anything.Web, :model @primary_key false schema "card_meta" do field :user_id, :integer, primary_key: true field :card_id, :integer, primary_key: true . . . timestamps() end end

Si esto no resuelve su problema, agregue su modelo de datos aquí.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda