Udders
Udders

Reputation: 6976

Eloquent querying 1:n relationship

I have 2 tables in my database, a notifications table and a notifications_user table.

A notification can have many notification users. And a result in my notification model I have the following relationship,

public function user()
{
    return $this->belongsToMany('User')->withPivot('is_read');
}

What I am wanting to achieve is to get all notifications that are unread (or is_read = 0), the is_read column is in the notification user table though and I cannot work out how to run a query on it becuase of that.

Current I have this,

$unread = Notification::has('user')->with('user')->get();

Now this pulls the relationship into the results, but takes no account of the is_read value.

Is there a way to select all the data from a table based on a value in its 1:n relationship.

Upvotes: 1

Views: 139

Answers (3)

Sieabah
Sieabah

Reputation: 964

So while it may make sense to have the relation that notifications have many users it really doesn't make sense from an ownership. Notifications are one-time things while users persist in a way. So try to think of users as the base object and notifications as the abundant resource.

The goal here is to get the users notifications so out of this you have to choose whether to duplicate notifications for each user or have one notification for many users. In one case where it's universal notifications (admin panel maybe) and the other is notifications that are personal to the user. If you're doing the latter you don't really need a pivot table and just a notifications table.

User -> hasOne -> Notification

Notification -> belongsTo -> User

This enables you to really customize the notifications per-user than relying on maybe another table for read notifications you can just mark it as "read" in the row.

If however you need universal notifications the structure just implements a third table called a pivot as you know. (I noticed you have the class names pluralized which is not recommended)

User -> Notification_User -> Notification

For ease you also could just soft-delete the notification_user row or notification themselves. You can simply just say ->withTrashed()->limit(x) to get previous notifications.

This really simplifies the work done by the DB and your code. The personal notifications allows you to order by creation/update and deal with read in two ways, soft-deletion and IsRead variables.

Your code becomes as simple as this.

Auth::user()->notifications()

Your User class has the following (assuming standard naming schemes)

public function notifications()
{
    //You're free to append other requirements here
    return $this->hasMany('App\Notification','id','user_id');
}

The Notification class has the inverse

public function user()
{
    //You're free to append other requirements here
    return $this->belongsTo('App\User','user_id','id');
}

If for some reason you require to know all unread notifications universally just query the Notification table.

Notification::where('isRead','null')->get();

Alternatively you can lazy load the users for each notification or group by users in this case for whatever purpose you need.

Upvotes: 0

Namoshek
Namoshek

Reputation: 6544

You can use the wherePivot and orWherePivot functions provided by laravel for relations. Link

Upvotes: 0

Ray
Ray

Reputation: 3060

You can query on the relationship by doing something like:

$unread = Notification::has('user')->with('user')->where('is_read','!=', 0)->get();

Check the docs: http://laravel.com/docs/5.1/eloquent-relationships#querying-relations

Upvotes: 1

Related Questions