Cómo detectar registros duplicados en Laravel 12 con groupBy e in_array
En este artículo explicamos paso a paso cómo detectar y resaltar registros duplicados (por ejemplo, teléfonos) en una tabla de leads usando Laravel 12 + Livewire. Verás el código exacto que ya tienes y una versión recomendada para normalizar teléfonos y/o detectar duplicados de forma global.
1. Tu método render()
Este es el render() que usas actualmente, con la corrección de orWhere('placa') (evita repetir dos veces telefono):
public function render()
{
$this->authorize('viewAny', Lead::class);
$user = auth()->user();
$query = Lead::query()
->where('state', 1)
->where(function ($q) {
$q->where('nombres', 'like', '%' . $this->search . '%')
->orWhere('telefono', 'like', '%' . $this->search . '%')
->orWhere('placa', 'like', '%' . $this->search . '%')
->orWhere('correoelectronico', 'like', '%' . $this->search . '%');
})
->when($this->stateFilter === 'active', fn($q) => $q->where('perfilcoincide', 'si'))
->when($this->stateFilter === 'inactive', fn($q) => $q->where('perfilcoincide', 'no'))
->when($this->stateFilter === 'iniciar', fn($q) => $q->where('perfilcoincide', 'iniciar'));
if (!$user->hasRole('Admin')) {
$query->where('user_id', $user->id);
}
$leads = $query->orderBy($this->sort, $this->direction)->paginate($this->cant);
// Calcular duplicados en los leads paginados (rápido: solo sobre la página actual)
$duplicatedPhones = $leads->groupBy('telefono')
->filter(fn($group) => $group->count() > 1)
->keys()
->toArray();
return view('livewire.admin.lead-list', compact('leads', 'duplicatedPhones'));
}
orWhere('telefono',...) duplicado. Lo cambiamos por orWhere('placa',...) para que también busque por placa.2. ¿Qué hace exactamente groupBy('telefono')->filter(...)->keys()?
groupBy('telefono'): agrupa la colección$leadspor el valor del campo teléfono.filter(fn($group) => $group->count() > 1): conserva solo los grupos con más de 1 elemento (duplicados).keys(): devuelve los teléfonos duplicados.toArray(): lo convierte en array para pasarlo a la vista.
3. Uso de in_array en Blade
En tu Blade ya tienes esta lógica para resaltar duplicados:
<td class="{{ in_array($lead->telefono, $duplicatedPhones) ? 'bg-yellow-200' : '' }}">
{{ $lead->telefono }}
</td>
in_array busca si un teléfono está dentro del array $duplicatedPhones. Si existe, se aplica la clase bg-yellow-200 para resaltarlo.
4. Problema: formatos distintos de teléfono
El método anterior falla si el mismo número está guardado con formatos distintos (+51 912-345-678 vs 912345678). Para evitar falsos negativos, lo mejor es normalizar.
5. Versión recomendada: normalización mínima
Aquí normalizamos ambos lados (colección y vista):
// 1) Método privado en el componente
private function normalizePhone(?string $phone): string
{
return preg_replace('/\D+/', '', trim($phone ?? ''));
}
// 2) En render() (detección en la página actual, normalizada)
$phonesInPage = $leads->pluck('telefono')->map(fn($t) => $this->normalizePhone($t));
$duplicatedPhones = $phonesInPage->countBy()->filter(fn($c) => $c > 1)->keys()->toArray();
// 3) En Blade (normalizar antes de comprobar)
@php
$normPhone = preg_replace('/\D+/', '', $lead->telefono ?? '');
@endphp
<td class="{{ in_array($normPhone, $duplicatedPhones) ? 'bg-yellow-200' : '' }}">
{{ $lead->telefono }}
</td>
+51.6. Detección global (opcional)
Si quieres detectar duplicados en toda la tabla filtrada (y no solo en la página actual):
// Detección global (cuidado en tablas grandes)
$allPhones = (clone $query)->pluck('telefono')->map(fn($t) => $this->normalizePhone($t));
$duplicatedPhonesGlobal = $allPhones->countBy()->filter(fn($c) => $c > 1)->keys()->toArray();
Luego en Blade comparas con $duplicatedPhonesGlobal.
7. Buenas prácticas
- ✔ Si la tabla es muy grande, calcula duplicados en la base de datos con
GROUP BY ... HAVING COUNT(*) > 1. - ✔ Considera crear una columna
telefono_normalizedindexada. - ✔ Resetea la paginación al cambiar filtros (
updatedCant(),updatingSearch()). - ✔ Asegúrate de incluir
placaen la búsqueda (ya corregido arriba).
🚀 Conclusión
Detectar registros duplicados en Laravel 12 es sencillo combinando groupBy, countBy y in_array. La clave está en normalizar los datos para evitar falsos negativos y decidir si la detección será solo en la página actual (más rápido) o a nivel global (más completo).