Ticom Perú

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'));
}
    
👉 Atención: en tu código original tenías 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 $leads por 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>
    
✅ Con esto marcas duplicados aunque estén guardados con espacios, guiones o con +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_normalized indexada.
  • ✔ Resetea la paginación al cambiar filtros (updatedCant(), updatingSearch()).
  • ✔ Asegúrate de incluir placa en 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).


Etiquetas :
F