Result of upsert has different binary_id, but this is corrected after the upsert?

So I have the following test:

Post #1 has a title and a body, and is present in the database.
Post #2 has the same title but a different body, and is not yet present in the database.

I have the following upsert logic:

%Post{}
|> Post.changeset(params)
|> Repo.insert(
  conflict_target: [:title],
  on_conflict: [
    set:
      params
      |> Map.to_list()
  ]
)
|> IO.inspect()

I supply this upsert with Post #2, meaning that I expect Post #1 to be updated to ‘become’ Post #2.
When I pipe this Repo.Insert into IO.inspect I notice that the ID is different from the ID in Post #1. However, when I check the database there is only one record, and it’s in the state I expect it to be in, meaning that the upsert was succesful. When did this ID get corrected?

I hope my explanation makes sense, and thank you in advance :slight_smile:

From docs:

Ecto supports the so-called “upsert” command which is an abbreviation for “update or insert”. The idea is that we try to insert a record and in case it conflicts with an existing entry, for example due to a unique index, we can choose how we want the database to act by either raising an error (the default behaviour), ignoring the insert (no error) or by updating the conflicting database entries.

So I think the different ID is the ID from the ‘tried to insert’ record. Default would then raise error, but since you have set it updates the existing one.

Some one please confirm.

in this section of insert/2 doc you can find some information about upsert caveats, including misalignment between the returned struct and database.

I think in your case, if you need the returned to mirror the database, your can use the read_after_writes: true in the schema or the returning: true option in the insert:

Specify read_after_writes: true in your schema for choosing fields that are read from the database after every operation. Or pass returning: true to insert to read all fields back. (Note that it will only read from the database if at least one field is updated).

2 Likes