简体   繁体   中英

Laravel Eloquent hasMany\hasOne limit parents to children with records

Using Laravel Eloquent and a hasOne()\\hasMany() relationship, is it possible to limit the "parent" table to only retrieve results if a "child\\foreign" relationship exists?

FOOS

+----+------------+
| id |     etc    |
+----+------------+
|  1 |     one    |
|  2 |     two    |
|  3 |     three  |
|  4 |     four   |
+----+------------+

BARS

+----+-----+--------+
| id | val | foo_id |
+----+-----+--------+
| 11 | 101 |      1 |
| 12 | 102 |      2 |
| 13 | 203 |      3 |
| 14 | 204 |      4 |
+----+-----+--------+

in Foo class (model)

public function highBars(){
    return $this->hasOne('App\Bar')->where('val','>','200');
}

in controller

Foo::with('highBars')->get();

returns ALL the FOOS, even though some high_bars relationships are null. Is it possible to only include FOOS results with a relationship value not null? (foos.id = 3,4)

This is retrieved...

  0 => array:3 [▼
    "id" => 1
    "etc" => "one"
    "high_bars" => null
  ]
  1 => array:3 [▼
    "id" => 2
    "etc" => "two"
    "high_bars" => null
  ]
  2 => array:3 [▼
    "id" => 3
    "etc" => "three"
    "high_bars" => array:2 [▼
      "id" => 13
      "val" =>203
      "foo_id" =>3
    ]
  ]
  3 => array:3 [▼
    "id" => 4
    "etc" => "four"
    "high_bars" => array:2 [▼
      "id" => 14
      "val" =>204
      "foo_id" =>4
    ]
  ]

But this is what I want..

0 => array:3 [▼
    "id" => 3
    "etc" => "three"
    "high_bars" => array:2 [▼
      "id" => 13
      "val" =>203
      "foo_id" =>3
    ]
  ]
  1 => array:3 [▼
    "id" => 4
    "etc" => "four"
    "high_bars" => array:2 [▼
      "id" => 14
      "val" =>204
      "foo_id" =>4
    ]
  ]

To quote the documentation .

When accessing the records for a model, you may wish to limit your results based on the existence of a relationship. For example, imagine you want to retrieve all blog posts that have at least one comment. To do so, you may pass the name of the relationship to the has method:

// Retrieve all posts that have at least one comment...
$posts = App\Post::has('comments')->get();

You may also specify an operator and count to further customize the query:

// Retrieve all posts that have three or more comments...
$posts = Post::has('comments', '>=', 3)->get();

Nested has statements may also be constructed using "dot" notation. For example, you may retrieve all posts that have at least one comment and vote:

// Retrieve all posts that have at least one comment with votes...
$posts = Post::has('comments.votes')->get();

If you need even more power, you may use the whereHas and orWhereHas methods to put "where" conditions on your has queries. These methods allow you to add customized constraints to a relationship constraint, such as checking the content of a comment:

// Retrieve all posts with at least one comment containing words like foo%
$posts = Post::whereHas('comments', function ($query) {
    $query->where('content', 'like', 'foo%');
})->get();

Answer

For your specific example, this would be achieved by using:

Foo::has('highBars')->get();

This isn't enough. When you defined your relation, you just tell Laravel what data is associated with the entity, but it doesn't constraints oh how data is fetched.

So when you do in your controller

Foo::with('highBars')->get();

the key here is this get . You don't constraint it to anything, you just saying, get me all the rows you have and in addition to this, get the data associated with this model. What you need to do is to add, well a constraint.

Foo::with('highBars')->whereHas('highBars', function ($query) {
    $query->where('val', '>', '200');
})->get();

Or a shortcut for that would be

Foo::has('highBars')->get();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM