function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Tyler HarrisTyler Harris 

Trying to find duplicate leads in Trigger


Trying to find a duplicate lead based on email on a "before insert" trigger. I pushed a SOQL query results into a map. How do I find/compare the duplicates in the Map?
 


trigger LoveMessage on Lead (before insert) {
    List<Lead> newleads = new List<Lead>();
    List<Lead> currentleads = new list<Lead>();
    currentleads = [SELECT Id, Name, Email FROM Lead WHERE Email !=null];
    Map<String, String> compareleads = new Map<String, String>();
   
    for(Lead u: currentleads){
        compareleads.put(u.Name, u.Email);
        System.debug(compareleads);
       
    }
    for(Lead lovelylead:Trigger.new){
        if(lovelylead.Email != null && lovelylead.Email !=compareleads.Email){
            newleads.add(lovelylead);

        }
    }

insert newleads;
}
Best Answer chosen by Tyler Harris
Stephan SpiegelStephan Spiegel
You can make use of the fact that the put() method returns the existing value if the key already exists:

trigger LoveMessage on Lead (before insert) {
    List<Lead> newleads = new List<Lead>();
    List<Lead> currentleads = new list<Lead>();
    currentleads = [SELECT Id, Name, Email FROM Lead WHERE Email !=null];
    Map<String, String> compareleads = new Map<String, String>();
   
    for(Lead u: currentleads){
        compareleads.put(u.Email, u.Name);
        System.debug(compareleads);
       
    }
    for(Lead lovelylead:Trigger.new){
        if(lovelylead.Email != null && 
        		(compareleads.put(lovelylead.Email, lovelylead.Name) == null)){ // if the key already exists, returns value, otherwise null 
            newleads.add(lovelylead);

        }
    }

insert newleads;
}

Note that if there are any duplicates in the list of new leads, this solution will only return the first one.

All Answers

Stephan SpiegelStephan Spiegel
You can make use of the fact that the put() method returns the existing value if the key already exists:

trigger LoveMessage on Lead (before insert) {
    List<Lead> newleads = new List<Lead>();
    List<Lead> currentleads = new list<Lead>();
    currentleads = [SELECT Id, Name, Email FROM Lead WHERE Email !=null];
    Map<String, String> compareleads = new Map<String, String>();
   
    for(Lead u: currentleads){
        compareleads.put(u.Email, u.Name);
        System.debug(compareleads);
       
    }
    for(Lead lovelylead:Trigger.new){
        if(lovelylead.Email != null && 
        		(compareleads.put(lovelylead.Email, lovelylead.Name) == null)){ // if the key already exists, returns value, otherwise null 
            newleads.add(lovelylead);

        }
    }

insert newleads;
}

Note that if there are any duplicates in the list of new leads, this solution will only return the first one.
This was selected as the best answer
Stephan SpiegelStephan Spiegel
Should be ...will only retain the first one.
Tyler HarrisTyler Harris
Thank you so much Stephan! This really helps. Would converting List<Lead> new leads to a Set solve the issue of returning only the first instance of the duplicate? I tried to do this, but it threw a validation error(DML requires SObject or SOBJECT list type:Set<Lead>).

Also, I"m trying to "bulkify" the trigger. Is the code setup to satisfy this requirement? Why or why not?

Thank you so much.
Tyler HarrisTyler Harris
Also I'm getting a DML Exception on my Insert newleads;. Not sure why it won't insert.
Apex script unhandled trigger exception by user/organization: 005F000000496Il/00DF0000000gseU

LoveMessage: execution of BeforeInsert

caused by: System.SObjectException: DML statment cannot operate on trigger.new or trigger.old

Trigger.LoveMessage: line 14, column 1
Stephan SpiegelStephan Spiegel
What I mean when I say the solution will only retain the first duplicate: Let's assume that you insert three leads at the same time, all with the email address bond007@mi6.gov.uk. The database does not yet contain any leads with this email address. The first time we execute the put statement on line 14, it succeeds, because the compareleads map doesn't contain the key bond007@mi6.gov.uk. So the first lead gets added to the map, with the key bond007@mi6.gov.uk, and the lead also gets added to the newleads list. The second time we execute the put statement, apex returns the first lead we just added to the map. The put statment adds the second lead to the map (and removes the first), but because the if statement now evaluates to false, the second lead never gets added to the list. The same happens with the third lead. So the newleads list ends up containing only the first lead.

If you wanted to retain all three leads for some reason, you could use an if statement like this: if (!compareleads.containsKey(lovelylead.Email)) -- this way, your compareleads map never changes, and as long as your database doesn't contain any leads with that email address, any number of duplicates can get added.

The example is indeed bulkified. All this means is that you can call the trigger with a collection of leads, and any SOQL queries or DML statments get executed only once per transaction (rather than once per lead in your collection). The query in your example only executes once, and the insert statemen also only once.

However, and I apologize for missing this earlier, since this is a before insert trigger, you can't call insert again from inside your trigger. This is why you are getting that DML exception. What you want to do instead is add an error to any leads you don't want to get inserted: badlead.addError('Lead with this email address already exists.'); the gotcha with this is that it will also prevent any good leads from being inserted by default, so in the code that inserts the leads, you'll want to use database.insert(listOfLeads, false) to indicate that partial-success DML is allowed.

Tyler HarrisTyler Harris
Thanks again Stephen. I tried adding an error, but it's indicating that the .addError() Method doesn't exist. What's the best route to take? Should this be handled in my current if else statement?   I'm find with the trigger not adding duplicates at all. I would like to know how to use the database.insert(listOfLeads, false) correctly as whe I add this statement it throws the same DML statement.

trigger LoveMessage on Lead (before insert) {
   List<Lead> newleads = New List<Lead>();
   List<Lead> currentleads = new List<Lead>();
    List<Lead> duplicates = new List<Lead>();
   currentleads = [SELECT Id, Name, Email FROM Lead WHERE Email !=null];
   
   
   Map<String, String> compareleads = new Map<String, String>{};
   
    for(Lead u: currentleads){
        compareleads.put(u.Name, u.Email);
       
    }
   
    for(Lead lovelylead:Trigger.new){
        if(lovelylead.Email != null && (compareleads.put(lovelylead.email, lovelylead.name)==null)){
            newleads.add(lovelylead);
          

        }
       
        else{
          duplicates.add(lovelylead);
      duplicates.addError('This is a duplicate');

        }
    }
}