You should use whereDoesntHave instead
return Product::whereDoesntHave('plans', function ($q) {
$q->where('type', 'off');
})->with('plans')->get();
Working Example:
products migration
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->timestamps();
});
plans migration
Schema::create('plans', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('product_id');
$table->foreign('product_id')->references('id')->on('products')
->onDelete('cascade');
$table->decimal('price');
$table->string('type');
$table->timestamps();
});
Product Model Relationship
public function plans()
{
return $this->hasMany(Plan::class);
}
Plan Model Relationship
public function product()
{
return $this->belongsTo(Product::class);
}
Sample Data Seeder
$productWithOnePlanOff = Product::create([
'title' => 'A product with one of its plans off'
]);
$productWithOnePlanOff->plans()->createMany([
['price' => rand(1, 50), 'type' => 'off'],
['price' => rand(50, 100), 'type' => 'on']
]);
$productWithNoPlanOff = Product::create([
'title' => 'A product with none of its plans off'
]);
$productWithNoPlanOff->plans()->createMany([
['price' => rand(1, 50), 'type' => 'on'],
['price' => rand(50, 100), 'type' => 'on']
]);
Query Part and Results
WhereHas looks for a model that has ANY of its related model match the query's condition
return Product::whereHas('plans', function ($q) {
$q->where('type', 'off');
})->with('plans')->get();
Results
[
{
"id": 1,
"title": "A product with one of its plans off",
"created_at": "2019-09-03 16:30:30",
"updated_at": "2019-09-03 16:30:30",
"plans": [
{
"id": 1,
"product_id": 1,
"price": "46.00",
"type": "off",
"created_at": "2019-09-03 16:30:30",
"updated_at": "2019-09-03 16:30:30"
},
{
"id": 2,
"product_id": 1,
"price": "50.00",
"type": "on",
"created_at": "2019-09-03 16:30:30",
"updated_at": "2019-09-03 16:30:30"
}
]
}
]
While the query with whereDoesntHave makes sure NONE of its related model match the query's condition
return Product::whereDoesntHave('plans', function ($q) {
$q->where('type', 'off');
})->with('plans')->get();
Results
[
{
"id": 2,
"title": "A product with none of its plans off",
"created_at": "2019-09-03 16:30:30",
"updated_at": "2019-09-03 16:30:30",
"plans": [
{
"id": 3,
"product_id": 2,
"price": "49.00",
"type": "on",
"created_at": "2019-09-03 16:30:30",
"updated_at": "2019-09-03 16:30:30"
},
{
"id": 4,
"product_id": 2,
"price": "93.00",
"type": "on",
"created_at": "2019-09-03 16:30:30",
"updated_at": "2019-09-03 16:30:30"
}
]
}
]
Hope this helps