Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

colinlongworth's avatar

firstOrCreate causes duplicate entry exception in PostgreSQL

I have a loop that uploads a CSV to my database. The email of a student is unique, and duplicates are not permitted. The outline of the logic is:


foreach ($csv->data as $row) {

//Other logic
 $student = Student::firstOrCreate(
                        [
                            'email' => $data['email']
                        ],
                        [
                            'first_name' => $data['first_name'],
                            'last_name' => $data['last_name']
                        ]);
                        
                        //More Logic
}

However, this causes an exception in PostgreSQL.

duplicate key value violates unique constraint "students_email_unique"

If I alter my logic to try get the first row another way, and avoid duplicates:


$student = Student::where('email', $data['email'])->firstOr(function () use ($data) {

                    return Student::firstOrCreate(
                        [
                            'email' => $data['email']
                        ],
                        [
                            'first_name' => $data['first_name'],
                            'last_name' => $data['last_name']
                        ]);
                });

The exception still occurs, which is even weirder.

It seems from reading online that PostgreSQL can cause this due to auto increment differences, but I'm trying to figure out how I can fix this as migrating from PostgreSQL is not an option.

0 likes
4 replies
tykus's avatar

It could be something to do with case-sensitivity maybe; how is the unique index defined?

colinlongworth's avatar

@tykus Hmm, good point. The Student model has a mutator:

    public function setEmailAttribute($value)
    {
        $this->attributes['email'] = strtolower($value);
    }

Which I assume would handle this case?

tykus's avatar
tykus
Best Answer
Level 104

@colinlongworth but the search part of firstOrCreate does not go through the mutator. try this:

 $student = Student::firstOrCreate([
    'email' => strtolower($data['email']),
], [
    'first_name' => $data['first_name'],
    'last_name' => $data['last_name']
]);
colinlongworth's avatar

@tykus Ok, good to know about the mutators!

I think this may have solved it. I'll revert back but for now the issue has cleared. Thank you.

Please or to participate in this conversation.