如何获取不在collection中的Laravel中的物品Eloquent?

How to get items are not in a collection in Laravel Eloquent?

在我的 Laravel 6.x 项目中,我有 Product 模型、WarehouseWarehouseProduct 模型。

在产品中我存储了我产品的基本信息。在 WarehouseProduct 中,我存储有关仓库中产品的库存量信息。我当然有很多仓库,有很多产品。

我的 Product 看起来像这样:

class Product extends Model
{
    protected $fillable = [
        'name',
        'item_number',
        // ...
    ];
}

Warehouse 看起来像这样:

class Warehouse extends Model
{
    protected $fillable = [
        'name',
        'address',
        // ...
    ];

    public function products() {
        return $this->hasMany(WarehouseProduct::class);
    }

    public function missingProduct() {
        // here I need to return a Product collection which are not in this Warehouse or the
        // stored amount is 0
    }
}

最后 WarehouseProduct 看起来像这样:

class WarehouseProduct extends Model
{
    protected $fillable = [
        'product_id',
        'warehouse_id',
        'amount',
        // ...
    ];

    public function product() {
        return $this->belongsTo(Product::class, 'product_id');
    }

    public function warehouse() {
        return $this->belongsTo(Warehouse::class, 'warehouse_id');
    }

我怎样才能得到一个 Product collection 没有存储在 Warehouse 或者金额是 0

像这样的东西应该可以工作:

use App\Product;

public function missingProduct() {
    $excludedProducts = $this->products()->where('amount', '>', 0)->pluck('id');

    return Product::whereNotIn('id', $excludedProducts)->get();
}

根据@KarolSobański 的解决方案,当您向产品模型添加 warehouse_products 关系时:

use App\Product;
use Illuminate\Database\Eloquent\Builder;

public function missingProduct() {
    return Product::whereDoesntHave('warehouse_products', function (Builder $query) {
        $query->where('warehouse_id', $this->id);
    })->orWhereHas('warehouse_products', function (Builder $query) {
        $query->where('warehouse_id', $this->id);
        $query->where('amount', 0);
    })->get();
}

最短的答案可能与此类似:

Product::doesntHave('warehouse_products')
       ->orWhereHas('warehouse_products', function (Builder $query) {
           $query->where('amount', '=', 0)
       })->get();

虽然我不确定以上是否有效。

但以下较长的查询确实可以解决问题:

Product::where(function ($query) {
    $query->doesntHave('warehouse_products');
})->orWhere(function ($query) {
    $query->whereHas('warehouse_products', function (Builder $query) {
       $query->where('amount', '=', 0);
    });
})->get();