+ Start a Discussion
yujohwan99yujohwan99 

How can I update a specific field from my records?

I'm trying to mass update a specific field using developer's console, but I only end up deleting the record itself. Here is my code: 

Contact[] contactDel = [SELECT Email__c FROM Contact
   WHERE Join_Date__c <= '2000'
   AND Email__c LIKE '%it.work.com’];

delete contactDel;

I'm currently trying to mass delete an email field that ends with "it.work.com," but only from people who joined on or before the year 2000. I don't want to necessarily remove the field from the record, but just delete the entry so that it's blank. However, this ends up deleting the whole record. Is there another way to do this? Maybe such as retrieving the ID's of these record? 
Best Answer chosen by yujohwan99
RovRov
As @Mariusz explained you got the error 'trying to dereference a null object' becuase you are using a <= operator with String. <= is a mathematical operator, and cannot compare strings. 

(For Contact c: cons) {
// it is read as : for every contact c in the cons list
// c is a variable that holds each contact record in that list
// cons is a list of contact records returned by the SOQL 
// we loop through each record in that list to see if the Email__c field has a value that ends with 'it.works.com'
}

c.Email__c.endsWithIgnoreCase('it.work.com'))
// instead of doing a wild card search in the SOQL, i used the function endsWithIgnoreCase becuase it specifically addresses your use case

massupdate
// In salesforce it's easy to hit governor limits. Hence you need to adhere to certain best practices. 
// instead of updating records one at a time, I am collecting all records that need to be updated in a list which i named as massupdate
// Update massupdate means update all the records at the same time. 

Try this code: 
 
// Create a list to collect all the values from the Join_Date__c picklist 
List<String> joinDates = new List<String>();

// this is how you collect all the picklist values
Schema.DescribeFieldResult fieldResult = Contact.Join_Date__c.getDescribe();
List<Schema.PicklistEntry> pEntires = fieldResult.getPicklistValues();
 
for (Schema.PicklistEntry pEntry : pEntires) {
    String pe = pEntry.getValue();
    if (pe.startsWith('1') || pe.equals('2000')) {
        // this is how you add all the picklist values in the list above
        joinDates.add(pe);
    }
}

// create a list of contacts to hold all the records that need to be updated
List<Contact> massupdate = new List<Contact>();

// Create a list of contacts whose Join date is in the list 'joinDates'
List<Contact> cons = [Select Id, Name, Email__c 
                           from Contact 
                           Where Join_Date__c IN :joinDates];
system.debug('Check the number of records in the list above' +cons.size());

// Loop through all the contacts in the above list returned by the SOQL query
// if in that list, there are any records whose email ends with 'it.work.com', 
//then replace that value with blank, 
  For(Contact c: cons){
    if(c.Email__c.endsWithIgnoreCase('it.work.com')){
        System.debug('>>>>>>>>>>>>>>>>> ' +c.Email__c);
        c.Email__c = null;
        // after making the Email__c field blank, add the record to the list 'massupdate'  
       massupdate.add(c);
    }
  }
// outside the for loop, check if the list is empty or not
// if the list is not empty, then update all the records in the list
if(!massupdate.isEmpty()){
 update massupdate;
}

 

All Answers

yujohwan99yujohwan99
While the code ran successfully, the emails were not deleted from the field. What exactly is the for each loop doing? What is Contact c for?
RovRov
In your code what you are doing is, creating a list of contacts and then deleting all those contacts in the list. 

Try the code i have posted. Let me know if you need further explanation or help. 
// First create a list of contacts to hold all the records whose email needs to be blank, so that you can do a bulk update on those records
List<Contact> massupdate = new List<Contact>();

// Create a list of contacts whose Join date was before  year 2000
// I am assuming here that the Join_Date__c is of type DateTime, if not you need to use appropraite methods

List<Contact> cons = [Select Id, Name, Email__c 
                           from Contact 
                           Where Join_Date__c <2000-01-01T23:01:01Z];

// Loop through all the contacts in the above list returned by the SOQL query
// if in that list, there are any records whose email ends with 'it.work.com', then replace that value with blank, 
For(Contact c: cons){
    if(c.Email__c.endsWithIgnoreCase('it.work.com')){
        System.debug('>>>>>>>>>>>>>>>>> ' +c.Email__c);
        c.Email__c = null;
        // after making the Email__c field blank, add the updated records to the list we created called massupdate  
        massupdate.add(c);
    }
}

// outside the for loop, check if the listis empty or not
// if the list is not empty, then update all the records in the list
if(!massupdate.isEmpty()){
 update massupdate;
}

 
yujohwan99yujohwan99
Thanks for the help, Rov. I'm quite new to Apex, SOQL, and DML, so I'm still trying to figure out how the languages work with Salesforce. 

I tried the code you gave me, but I received a "trying to dereference a null object" at around line 14 on your code. I only changed line 9 a little differently: I wrote Join_Date__c <= '2018' instead. 

The data type for Join_Date__c is picklist, so I'm assuming I can just use an <= operator. I'm also still confused as to what (For Contact c: cons) is doing. Why are you comparing cons with Contact c? And I don't understand how creating a massupdate list would actually update the original list.
yujohwan99yujohwan99
Hey, Steven. I tried and checked the result multiple times; there hasn't been any changes to the original email address. 
MariuszMariusz
You recieved this information because you're using a less-than or euqual operator with String. To avoid this, try to create a list with picklist values, for example:
List<String> joinDates = new List<String>();

Schema.DescribeFieldResult fieldResult = Contact.Join_Date__c.getDescribe();
List<Schema.PicklistEntry> pEntires = fieldResult.getPicklistValues();
 
for (Schema.PicklistEntry pEntry : pEntires) {
    String pe = pEntry.getValue();
    if (pe.startsWith('1') || pe.equals('2000')) {
        joinDates.add(pe);
    }
}
or simply:
List<String> joinDates = new List<String>{'2000', '1999', '1998', '1997'}; //and so on
and then change the SOQL query in Rov's code:
List<Contact> cons = [Select Id, Name, Email__c
                                   from Contact
                                   Where Join_Date__c IN :joinDates];
Also make sure that the custom field Email__c is filled in, not the standard Email field.

(For Contact c: cons){ } is a for loop (iterates over all the elements in a cons list, and runs code block for each c value from that list): https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_loops_for_lists.htm

I think that Rov used a massupdate list to avoid the query that use a leading wildcard. Instead, he used the endsWithIgnoreCase() function and collected the appropriate records in this list.
RovRov
As @Mariusz explained you got the error 'trying to dereference a null object' becuase you are using a <= operator with String. <= is a mathematical operator, and cannot compare strings. 

(For Contact c: cons) {
// it is read as : for every contact c in the cons list
// c is a variable that holds each contact record in that list
// cons is a list of contact records returned by the SOQL 
// we loop through each record in that list to see if the Email__c field has a value that ends with 'it.works.com'
}

c.Email__c.endsWithIgnoreCase('it.work.com'))
// instead of doing a wild card search in the SOQL, i used the function endsWithIgnoreCase becuase it specifically addresses your use case

massupdate
// In salesforce it's easy to hit governor limits. Hence you need to adhere to certain best practices. 
// instead of updating records one at a time, I am collecting all records that need to be updated in a list which i named as massupdate
// Update massupdate means update all the records at the same time. 

Try this code: 
 
// Create a list to collect all the values from the Join_Date__c picklist 
List<String> joinDates = new List<String>();

// this is how you collect all the picklist values
Schema.DescribeFieldResult fieldResult = Contact.Join_Date__c.getDescribe();
List<Schema.PicklistEntry> pEntires = fieldResult.getPicklistValues();
 
for (Schema.PicklistEntry pEntry : pEntires) {
    String pe = pEntry.getValue();
    if (pe.startsWith('1') || pe.equals('2000')) {
        // this is how you add all the picklist values in the list above
        joinDates.add(pe);
    }
}

// create a list of contacts to hold all the records that need to be updated
List<Contact> massupdate = new List<Contact>();

// Create a list of contacts whose Join date is in the list 'joinDates'
List<Contact> cons = [Select Id, Name, Email__c 
                           from Contact 
                           Where Join_Date__c IN :joinDates];
system.debug('Check the number of records in the list above' +cons.size());

// Loop through all the contacts in the above list returned by the SOQL query
// if in that list, there are any records whose email ends with 'it.work.com', 
//then replace that value with blank, 
  For(Contact c: cons){
    if(c.Email__c.endsWithIgnoreCase('it.work.com')){
        System.debug('>>>>>>>>>>>>>>>>> ' +c.Email__c);
        c.Email__c = null;
        // after making the Email__c field blank, add the record to the list 'massupdate'  
       massupdate.add(c);
    }
  }
// outside the for loop, check if the list is empty or not
// if the list is not empty, then update all the records in the list
if(!massupdate.isEmpty()){
 update massupdate;
}

 
This was selected as the best answer
yujohwan99yujohwan99
Thanks Rov and Mariusz; I managed to get it to work after a few changes to the code. 

One small question: for "massupdate.add(c)," I'm understanding this as adding each updated record froms variable c. Wouldn't this result in two same records for massupdate except one has an empty email field? What is "update massupdate" exactly doing?
RovRov
Salesforce is built on a multi tenant architecture, hence it has  strict governor limits. 
Instead of individually updating each record, we are collecting all records in a list and updating that list

massupdate.add(c)  //only adds record that need to be updated to the list 
update massupdate // actually saves those new changes in the database; in other words it actually updates the records with the new value 


Example:  if you have 10 shirts to wash, you dont put one shirt in the washer, after it's done washing, put second shirt to wash  and so on..
you collect all 10 shirts in a laundry hamper and wash all 10 shirts at the same time. 

hamper.add(shirt);  // add each shirt to be washed in the hamper
Wash hamper   // wash all shirts that are in the hamper

I think the word massupdate is confusing you. massupdate is just the name i gave to the list, you can call whatever you want. 
yujohwan99yujohwan99
Wouldn't massupdate have the original record AND the new record with the empty email field after doing "massupdate.add(c)?" 

Also, I've ran into a new problem. The code was working fine yesterday, but after running it today, I received the same error "trying to derefence a null object." I don't understand why this is suddenly appearing again after working perfectly fine. 
yujohwan99yujohwan99
I actually figured out the problem; it seems I hit a governor limit as I'm trying to update more than 100 records with the SOQL query. Is there a way to bypass this?
RovRov
massupdate only has updated record, which is held in the variable c 
The code i wrote is already bulkified to get around governor limits. 
The only reason i see it hitting governor limits is the SOQL query returning more than allowed records. 
In that case,remove the  if(c.Email__c.endsWithIgnoreCase('it.work.com')) and put the wild card search filter in the SOQL. This way, SOQL wil return lesser records to process in the for loop. 
here's the modified code...

 
List<Contact> cons = [Select Id, Name, Email__c 
                           from Contact 
                           Where Join_Date__c <2000-01-01T23:01:01Z AND Email__c  LIKE '%it.work.com'];



For(Contact c: cons){
   
        System.debug('>>>>>>>>>>>>>>>>> ' +c.Email__c);
        c.Email__c = null;
        massupdate.add(c);
   
}
Check your debug logs and you will have a better idea as to why and where your code is failing

 
yujohwan99yujohwan99
Yeah, doing the wild card search in the SOQL managed to get it work. Thanks for the help thus far. Here's my code:

List<Contact> listUpdate = new List<Contact>();

List<Contact> cons = [SELECT ID, Name, Email__c, Join_Date__c
                     FROM Contact
//I'm just going to have to enter each year. Not a big deal as there isn't that many.
                     WHERE Join_Date_c = '2013' 
                     AND Email__c LIKE '%it.work.com'];
system.debug('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>' + cons.size());

For(Contact c: cons){
      c.Email__c = null;
      listUpdate.add(c);
}

if(!listUpdate.isEmpty()){
    update listUpdate;
}