Before deciding on doing that can I recommend reading this? https://tray2.se/posts/database-design
how to add an array in a database
i would like to insert related posts in a column of my post table called 'correlated_posts'. in the store method of controller i have this and i've done the casts in the model protected $casts = [ 'correlated_posts' => 'array', ]; and in database the column is type string
i receive always null result, does someone know why ?
$post->author = $request->input('author');
$post->article = $request->input('post_html');
$post->summary = $request->input('summary');
if(!empty($request->correlated_posts)){
$correlated_posts= $request->input('correlated_posts');
$post->correlated_posts = $correlated_posts;
}
$correlated_posts is like this
array:3 [▼
0 => "1"
1 => "2"
2 => "4"
] ```
understood, but i didn't want to do a pivot table
@davidebo, it seems like a good idea now. But 99% of the time it's not. You loose more than you gain. The work you are avoiding now will cascade into extra work when you want to interact with that data that is bound up in a columns.
@davidebo so you are absolutely sure you will never ever need to query that data? If you ever need to find out which posts a post is correlated to, then what?
Anyways please format your code by adding ``` on the line before and after it. After that I will take a look at it
Where do you get null? In the database? Or dd()?
@Sinnbeck in database
well, here the user when create a new post have to choose at maximum 3 correlated posts for that post, if he choose 1 the others 2 are random and if he choose 2 the other is random, maybe is better with pivot,
@davidebo I would go with pivot at least. That way you can add a column to indicate which are chosen by the user :)
@Sinnbeck and then can i choose a random post and merge with the other selected ?
@Sinnbeck Is there any benefit of using a pivot table over having a seperate model & migration for correlated_posts?
It would seem there is a lot of advantages with eloquent relationships in having the correlated_posts data stored in a seperate migration so the data is not nested inside a json column in the table.
@Sinnbeck so you are suggensting to create a pivot table between the posts and the user, for example a post_user table where there are these column : id, post_id, correlated_post and the user_id ?
@davidebo you can in theory call it what you want. You just need to specify it in the relationship then. But I would imagine you just need post_id, user_id and user_added? No need for id and no need for two posts columns?
Or is it a related relationship between two posts? If so, yours is fine 👍 (no need for id though)
@Sinnbeck the user will be only one here, but when create the post have to choose 1-3 posts, from his choice
@davidebo ok so it's related posts for the post they are creating? Then yes your columns should be fine :) but no need for a user_id in theory as the main post already has a user_id I assume. So post_id and related post_id
@Sinnbeck yes are related posts for the post they are creating, but if the pivot connect two tables, for example posts and users, in the pivot doesn't need to exists user_id ? even if in posts table i have already the user_id
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained('users');
@davidebo You could consider keeping the user_id table & making it nullable, so that you can use it for logic that tells if the post was user added & also the id of the user that added the post. As you need at least a Boolean for checking if it’s user added, then you could store the user_id too?
@davidebo sorry if it wasn't clear but exactly. No need for user_id on the pivot. You can add it if you want, but it isn't needed
@Sinnbeck ok thank you
As people here mentioned, you it's better to add pivot table. But for the 1% use case I will write how to add array to your database.
First the column should be JSON or Text, it might also be String if the array is always short.
Secondly, in your Laravel model you should case your column to JSON
class Post extends Model
{
protected $casts = [
'correlated_posts' => 'array',
];
}
https://laravel.com/docs/9.x/eloquent-mutators#array-and-json-casting
Definitely recommend going the normalized route to save yourself headaches down the road. However if you're really certain this is what you want to do... Spatie's schemaless attributes are a good way of handling this sort of thing. https://github.com/spatie/laravel-schemaless-attributes
I would only ever use the array approach if I was 100% certain I would never ever need to query by it. Your case seems very likely to require a query.
Like so many other here are suggesting, use a pivot for this, it makes it much easier to do all the crud operations you will need. It is also much faster when it comes to filtering on those posts, since they can be indexed. An json column can't be, without simulating a virtual table for each of the "columns" in the array.
@Tray2 and how should be a manyToMany relation with just a post table and the correlated posts as pivot ? i mean, the user can choose maximum 3 posts of his choice, so every post should have 3 related posts
@davidebo Why limit it to three?
You can handle the limitation with a Custom validation rule.
https://laravel.com/docs/9.x/validation#custom-validation-rules
@Tray2 yes ok, but I do not understand how should be the other table for relation, i have a post table like this, and the one for correlated posts should have an id, the post_id and the related posts for every post_id ?
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title',128)->index('idx_title')->unique();
$table->foreignId('user_id')->constrained('users');
$table->string('author');
$table->text('article');
$table->text('summary')->nullable();
$table->string('post_thumb',128)->nullable();
$table->string('meta_title')->nullable();
$table->string('meta_description')->nullable();
$table->string('slug')->unique();
@Tray2 I’m interested in pivot tables, can you help me understand why you would use them over creating a seperate migration & model for related_posts (with user_id & post_id), then use eloquent to set up the relationships?
@CamKem that's what a pivot table is. So let's say you need to connect users with posts, you would make a table named post_user. Pivot is for when both parts had many. So a user has many posts and a post has many users
@Sinnbeck Thanks for explaining, makes sense.
I do not understand how should be the other table for relation
Have you read the docs for relationships?
https://laravel.com/docs/9.x/eloquent-relationships#many-to-many
users
id - integer
name - string
…
posts
id - integer
name - string
…
post_user
user_id - integer
post_id - integer
@webrobert yes, i didn't know which tables connect, but now is clear thanks, i will connect posts table with users table and in the pivot i will have the post_id and the post_correlated_id
@davidebo Your pivot should contain post_id and corelated_post_id.
Let's look at you posts table.
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title',128)->index('idx_title')->unique();
$table->foreignId('user_id')->constrained('users');
$table->string('author');
$table->text('article');
$table->text('summary')->nullable();
$table->string('post_thumb',128)->nullable();
$table->string('meta_title')->nullable();
$table->string('meta_description')->nullable();
$table->string('slug')->unique();
There isn't really any need to limit the size of the title to 128 characters, and adding a unique index is really bad, use a normal index instead, since the posts titles uniqueness should not be forced. Why do you have the author in the table, isn't the user_id the author? There is no need to store it twice.
@Tray2 yes you are right, for the author well maybe wil be inserted another name, for the pivot connection i've done like this
class Post extends Model{
public function correlatedPosts()
{
return $this->belongsToMany(Post::class, 'correlated_posts', 'post_id', 'correlated_post_id' )->withTimestamps();
}
}
class CorrelatedPost extends Model{
protected $table = "correlated_posts";
public function post()
{
return $this->belongsToMany(Post::class, 'correlated_posts', 'correlated_post_id', 'post_id')->withTimestamps();
}
}
class CreateCorrelatedPostsTable extends Migration
public function up()
{
Schema::create('correlated_posts', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id');
$table->foreign('post_id')->on('posts')->references('id')->onDelete('cascade');
$table->string('correlated_post_id');
$table->timestamps();
});
}
}
class PostController extends Controller
{
public function store(Post $post, PostRequest $request, Tag $tag){
...
$res = $post->save();
if($request->has('correlated_posts')){
$post->correlatedPosts()->syncWithPivotValues($request->input('correlated_posts'),['post_id' => $post->id ]);
}
}
}
Please or to participate in this conversation.