You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel查询作用域结合orWhere导致分页计数错误

Fixing Pagination Count Mismatch with Full-Text Search + orWhere

I've run into this exact issue before with Laravel scopes and orWhere combinations—let's break down why this happens and how to fix it.

Why the Pagination Count is Wrong

When you chain orWhere() directly after your search() scope, Laravel builds a WHERE clause that looks like this:

WHERE MATCH (your_searchable_columns) AGAINST ('+foo*' IN BOOLEAN MODE) OR name LIKE '%foo%'

If your model uses global scopes (like SoftDeletes for example), Laravel appends those as AND conditions. Because MySQL evaluates AND before OR, the final query becomes:

WHERE (MATCH (...) AGAINST (...)) OR (name LIKE '%foo%' AND deleted_at IS NULL)

This can lead to the count query including unintended rows (like all rows matched by the MATCH condition, even if they're soft-deleted) or miscalculating the total entirely. Even without global scopes, ungrouped OR conditions can throw off Laravel's pagination count logic.

The Fix: Group Your OR Conditions

Wrap your search() and orWhere() calls in a closure passed to where(). This groups all your OR conditions together, ensuring they're evaluated as a single unit alongside any global scopes:

$searchTerm = 'foo';

$results = Model::where(function ($query) use ($searchTerm) {
    $query->search($searchTerm)
          ->orWhere('name', 'like', "%{$searchTerm}%");
})->paginate(10);

This generates a clean, correctly prioritized SQL query:

WHERE (MATCH (your_searchable_columns) AGAINST ('+foo*' IN BOOLEAN MODE) OR name LIKE '%foo%') AND deleted_at IS NULL

Now the pagination count query will accurately count only the rows that match either the full-text search OR the name LIKE condition (plus any global scope rules), so your pagination links will reflect the actual number of results.

Quick Checks to Ensure Everything Works

  • Double-check that your model has the $searchable property defined correctly (e.g., protected $searchable = ['title', 'description'];). Missing or incorrect fields here can cause the full-text match to fail silently.
  • Verify that your MySQL table has a full-text index on the columns listed in $searchable—without this, the MATCH ... AGAINST query will still run but be slow and might not behave as expected.

内容的提问来源于stack exchange,提问作者Patrick Heppler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 12:02:46