0

I want to import a csv file into database where name should always unique means if any duplicate title found it should avoid the row and go to the next row. How do I implement using Laravel Controller?

Here's the controller for importing csv/xl I've used :

 public function importExcel()
    {
        if(Input::hasFile('import_file')){
            $path = Input::file('import_file')->getRealPath();
            $data = Excel::load($path, function($reader) {
            })->get();
            if(!empty($data) && $data->count()){
                foreach ($data as $key => $value) {
                    $insert[] = ['title' => $value->title, 'description' => $value->description];
                }
                if(!empty($insert)){
                    DB::table('items')->insert($insert);
                  //  dd('Insert Record successfully.');
                }
            }
        }
        return back();    
    }
3
  • why do you want to make it complicated? Mysql has built in tools for dealing with CSV - load data in file Commented Aug 10, 2016 at 5:39
  • I'm not clear to your answer, please can you elaborate more? Commented Aug 10, 2016 at 6:00
  • read up on mysql's LOAD DATA INFILE. It's a matter of using the right tool for the job Commented Aug 10, 2016 at 6:22

3 Answers 3

2

Some improvement on Matt Borja's answer. This will also check earlier data from table.

public function importExcel()
{
    // Get current data from items table
    $titles = Item::lists('title')->toArray();

    if(Input::hasFile('import_file')){
        $path = Input::file('import_file')->getRealPath();
        $data = Excel::load($path, function($reader) {
        })->get();

        if(!empty($data) && $data->count()){
            $insert = array();

            foreach ($data as $key => $value) {
                // Skip title previously added using in_array
                if (in_array($value->title, $titles))
                    continue;

                $insert[] = ['title' => $value->title, 'description' => $value->description];

                // Add new title to array
                $titles[] = $value->title;
            }

            if(!empty($insert)){
                DB::table('items')->insert($insert);
              //  dd('Insert Record successfully.');
            }
        }
    }
    return back();    
}
Sign up to request clarification or add additional context in comments.

3 Comments

I have changed to your code But got the following Error: FatalThrowableError in ItemController.php line 89: Cannot access protected property Maatwebsite\Excel\Collections\RowCollection::$title It's in the line if (in_array($value->title, $titles))
That error is for $value->title part which was in your original code actually. That is for your code which can't access title value from excel file.
Checked the code locally, it's working fine. Didn't get any error like that.
2

Before inserting the data into database you can apply array_unique() function on your array variable $insert[]. It will return you the unique array.

Or make the column in the table unique so that it cannot accept duplicate value.

1 Comment

If I put the column key unique, i will see unique key constrain error while importing data, whereas I used array() unique But it's showing the array to string conversion Error!
0

I typically maintain an index of previously added items, skipping the current iteration (re-adding) if I've indexed it already.

In your example, it would be something along the lines of this:

 public function importExcel()
    {
        // Index titles
        $titles = [];

        if(Input::hasFile('import_file')){
            $path = Input::file('import_file')->getRealPath();
            $data = Excel::load($path, function($reader) {
            })->get();

            if(!empty($data) && $data->count()){
                foreach ($data as $key => $value) {

                    // Skip title previously added using array_key_exists or in_array
                    if (array_key_exists($value->title, $titles))
                        continue;

                    $insert[] = ['title' => $value->title, 'description' => $value->description];

                    // Index added title
                    $titles[$value->title] = true; // or array_push
                }

                if(!empty($insert)){
                    DB::table('items')->insert($insert);
                  //  dd('Insert Record successfully.');
                }
            }
        }
        return back();    
    }

2 Comments

I have changed it to your code but it still keeps the duplicate value in database!
Well it's not meant to clean it up if they were previously imported. I would do some "print" debugging at this point to verify that the $insert[] array doesn't contain any duplicate titles. I would also initialize $insert as an empty array somewhere at the beginning of this method to ensure it's not picking up any global vars, etc. If you're looking to clean up your previously imported duplicate records, though, a good start might be to audit those records: SELECT title, COUNT(*) AS total FROM items GROUP BY title ORDER BY total DESC

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.