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

nameless__'s avatar

Seed lots of Data into DB

Hello, I'm currently got stuck with the following: I'm trying to implement a catgeory system to my app. Therefore, I need about 100-200 categories with some "parent categories". So I want to create two tables: Category, Subcategory. The category table holds the parent categories, the subcategories are the subcategory of those, pointing to the primary key of the parent category. Here's what I mean with the category thing: Parent Category: Clothing Subcategory: Woman Shoes Subcategory: Men's Shirts Subcategory: Jeans Parent Category: Handys Subcategory: Smartphones Subcategory: PDA's Subcategory: Smartwatches and so on.

The database would then have the two tables, categories would hold (for this example) two entries

id name

0 Clothing

1 Handy

and subcategory would look like:

id name parent

0 Woman Shoes 0

1 Men's Shirts 0

2 Jeans 0

3 Smartphones 1

4 PDA's 1

5 Smartwatches 1

I hope you got what I mean. Now, of course I create a migration for those two tables, and of course, I create a model for those two tables. But whats the best way to seed this data into the tables. As I said it are like 100-200 categories (not just those two mentioned). So something like that:

DB::table('category')->insert([ 'name' => 'Clothing', ]);

times 100 wouldn't make sence I guess. Especially, because the subcategory refers to the id of the category. So if I once insert a category between two others, then every category afterwards has another primary key (after new seeding), so everything would be messed up. So how can I do that? Any ideas?

0 likes
14 replies
willvincent's avatar

Why would you insert a category "between two others" in a way that changes it's ID?

If you are worried about controlling the order of categories, just include a weight field. signed integer, lower values appearing first on the list. Default them to 0.

Then when you select your categories from the DB, just include an orderBy('weight', 'asc')

Also, do you really need to have categories and sub categories in separate tables? Categories could just reference the same table for their children, by making the 'parent' column nullable, if null it's a top level category, if not null it's a descendent. This would also let you have things more than one level deep.

nameless__'s avatar

Yeah, might not make sence, but still the seeding is not making sence like making 200 entries of insert like I wrote right?

And ofcourse, your right, this could work, too and I would have two tables, but one. But would the "children" then still just hold the id of the parent element in the "parent" column, right?

But still the question is open: How do I then seed the data? Whats the best way to enter all these in the db? And how can I (while seeding) refer to the id of the parent element if the table isn't even filled with them yet?

willvincent's avatar

well if you're going to use 'insert' you could do it in fewer calls, since that's able to insert multiple rows at a time.

You'll want to populate the parents first, then for each parent, populate it's children.

So like:

DB::table('categories')->insert($arrayOfParents);

Then select all from categories, loop through each result, and insert its children.. If you have all your data as a multi-dimensional array you could use the array keys as the parent category names, which would make it easier to map the children to the proper parents later..

$data = [
  'Clothing' => [
    'Women\'s Shoes',
    'Men\'s Shirts',
  ],
  'Handy' => [
    'Smartphone',
    'PDA'
  ],
];

Then your initial insert would be like this:

DB::table('categories')->insert(array_keys($data));
raphaelcoder's avatar

The Eloquent way


 $categories = array(['name' => 'Clothing'], ['name' => 'Handy']);
        $sub_categories = array(
            'Clothing' => ['name' => ' Woman Shoes '], ['name' => 'Men\'s Shirts'],
            'Handy' => ['name' => ' Smartphones '], ['name' => 'Smartwatches ']
        );


        foreach($categories as $category)
        {
            $category = Category::create($category);
            foreach ($sub_categories as $sub_category)
            {
                $active = $sub_category[$category->name];
                $active['parent_id'] = $categories->id;
                SubCategory::create($sub_category);
            }
        }
nameless__'s avatar

Still not completely sure about that... $arrayOfParents would just look like that?

$arrayOfParents = [
'Clothing', 'Handy'];

But how can I (for the children) refer to those? Sorry, I'm really stuck with that I think...

nameless__'s avatar

@raphaelcoder looks good, I'll try that one. But one question: What $active in your case? Ofcourse, this is the referrer to the parent key, but is this also the name, that the column in the db has to be called?

raphaelcoder's avatar

$active is to hold value of the current subcategory to be inserted.

 SubCategory::create($active);
willvincent's avatar

would almost certainly be easier with eloquent, vs misc. query builder.

nameless__'s avatar

Yeah, looks easier. But I'm right that the way described works with 2 tables again?

nameless__'s avatar

@raphaelcoder And whats the right last line now? SubCategory::create($active);

or

SubCategory::create($sub_category);?

nameless__'s avatar

@raphaelcoder I now tried the code, using this up function:

public function run()
    {
        $categories = array(['name' => 'Clothing'], ['name' => 'Handy']);
        $sub_categories = array(
            'Clothing' => ['name' => ' Woman Shoes '], ['name' => 'Men\'s Shirts'],
            'Handy' => ['name' => ' Smartphones '], ['name' => 'Smartwatches ']
        );


        foreach($categories as $category)
        {
            $category = Category::create($category);
            foreach ($sub_categories as $sub_category)
            {
                $active = $sub_category[$category->name];
                $active['parent_id'] = $categories->id;
                Subcategory::create($active);
            }
        }
    }

But now, php artisan db:seed delivers this error:

Undefined index: Clothing

Whats the problem?

nameless__'s avatar

@raphaelcoder seems like the $sub_category[$category->name] is the problem I guess, to the string as index is not possible?

I also tried this now:

foreach($categories as $category)
        {
            $category = Category::create($category);
            foreach ($sub_categories as $sub_category)
            {
                $subcategory = new Subcategory();
                $subcategory->name = $sub_category['name'];
                $subcategory->parent_id = $category['id'];
                $subcategory->save();
            }
        }

But that way, the elemtents of handy are insirted for parent Clothing as well as the other way round, so I have all subcategory entries for every parent...

nameless__'s avatar

Got it working now (just for those who mind, using this code):

$data = [
            'Clothing' => ['Woman Shoes', 'Men\'s Shirts'],
            'Handy' => ['Smartphones', 'Smartwatches ']
        ];

        foreach ($data as $category => $subCategories)
        {
            $id = Category::create(['name' => $category])->id;

            foreach ($subCategories as $subCategory) {
                Subcategory::create([
                    'parent_id' => $id,
                    'name' => $subCategory
                ]);
            }
        }

Please or to participate in this conversation.