Hello! I build a crawler and using Ecto as a database.
The crawler scrapes some data from the doctor-hospitals site.
One doctor can work in many hospitals, and one hospital can have many doctors.
I use many-to-many associations to connect them.
I will try to explain how crawler works:
- Go to the Doctor’s page. Grab all doctor’s info and its hospitals.
- Put these hospitals’ links to the queue.
- Crawled data go to Ecto Changeset. Which build the associations via put_assoc, add to hospital table:hospital_profile, which contains just the links and no other data yet.
- After the hospital link is visited(from point 2), the crawler should enrich data by fill the field.
%Doctor{}
|> cast(params, fields)
|> validate_required(:doctor_profile)
|> put_assoc(:hospitals, hospitals_to_map(params.hospitals))
|> upsert_doctors()
def upsert_doctors(changeset) do
changeset
|> Repo.insert(on_conflict: :replace_all_except_primary_key, conflict_target: :doctor_profile)
end
Below is my debugging process.
- Add the Doctor fields with associated Hospitals - Success! The references to “hospitals_doctors” table added.
- Enrich data for the Hospitals - Sucess! (for this I using usperts)
- Add a new Doctor which related from one of the Hospitals which already has added(points above) - Error!
** (Ecto.ConstraintError) constraint error when attempting to insert struct:
* hospitals_index (unique_constraint)
If you would like to stop this constraint violation from raising an
exception and instead add it as an error to your changeset, please
call `unique_constraint/3` on your changeset with the constraint
`:name` as an option.
The changeset has not defined any constraint.
So If a doctor has many hospitals then I will get many ids in hospitals_doctors table. However if I want to add a new doctor which also works in one of the hospitals where work the first one, I will meat the error. Somehow can I fix it ? What I am doing wrong?