+ Start a Discussion
ChickenOrBeefChickenOrBeef 

Filtering by the FeedItem "Body" field

Hey everyone,

I received a request to remove the chatter alerts on accounts that say "[NAME] updated this account by converting a lead." I'm sure you've received that complaint before as well, since those alerts can't be removed via the admin setup.

User-added image

So I tried creating a trigger to delete those alerts when a lead is converted, but I get an error that says I can't filter by the FeedItem's "Body" field, which as far as I know, is the only way to distinguish these types of alerts. Here is the trigger I tried writing:

public class ClassDeleteConvertAlerts{
    
    public void deleteAlerts(List<Lead> leads,Map<Id,Lead> oldLeads){
        
        Set<String> convertedLeads = new Set<String>();
        List<FeedItem> feedItemsToDelete = new List<FeedItem>();
        
        FOR(Lead l : leads){
            IF(l.IsConverted == TRUE && oldLeads.get(l.Id).IsConverted == FALSE){
                convertedLeads.add(l.Id);
            }
        }
        
        IF(convertedLeads.size() > 0){
            FOR(FeedItem item : [SELECT
                                   Id,Title
                               	 FROM
                                   FeedItem
                                 WHERE
                                   Body LIKE '%updated this account by converting a lead%']){

                                                       feedItemsToDelete.add(item);

                                                  }
        					                                  
         IF(feedItemsToDelete.size() > 0){
            DELETE feedItemsToDelete;
        }
        
    }

}

Is there any way to accomplish what I'm trying to do? Can I delete feeditems based on what's in the Body?

Thanks!
-Greg
Best Answer chosen by ChickenOrBeef
Community User2Community User2
Sometimes there is a slight delay in deletion otherwise it works great

Trigger DeleteAccountFeed on Lead (after update) {


    Set<String> convertedLeads = new Set<String>();
    List<Id> convertedAccountList = new List<Id>();

    FOR(Lead l : trigger.new){
        IF(l.IsConverted == TRUE && trigger.oldmap.get(l.Id).IsConverted == FALSE){
            convertedLeads.add(l.Id);
           convertedAccountList.add(l.convertedAccountId);
         }
    }

   
    IF(convertedLeads.size() > 0){
        DeleteAccountFeedFutureClass.DeleteFeed(convertedAccountList);
    }
}

global class DeleteAccountFeedFutureClass {

@future
public static void DeleteFeed(List<ID> recordIds)
  {
       list<AccountFeed> listAccountFeedsToDelete = new list<AccountFeed>();
        FOR(AccountFeed objFeed : [SELECT Id,Type,ParentId,(SELECT Id,FieldName FROM FeedTrackedChanges)
                                       FROM AccountFeed WHERE Type = 'TrackedChange' and ParentId in: recordIds]){
                                       system.debug('ObjFeed....'+ObjFeed);
                                       FOR(FeedTrackedChange objChange : objFeed.FeedTrackedChanges){
                                           system.debug('objChange...'+objChange);
                                           IF(objChange.FieldName == 'accountCreatedFromLead' || objChange.FieldName == 'accountUpdatedByLead'){
                                                System.debug('Accound Feeds To Delete is ' + listAccountFeedsToDelete);
                                                listAccountFeedsToDelete.add(objFeed);
                                                System.debug('Accound Feeds To Delete is ' + listAccountFeedsToDelete);
                                           }

                                       }

                                   }
       DELETE listAccountFeedsToDelete;
   }
}


All Answers

Scott McClungScott McClung
These system generated Chatter records have a Type of 'TrackedChange'.  If you query FeedItems with Type = 'TrackedChange' you'll notice that the body is null so even if you could filter on that field, you still wouldn't find what you're looking for.
For each of these tracked changes, SF also creates a FeedTrackedChange record that contains the field name that triggered the entry as well as the old and new values of the field.  In the case of these lead conversion messages, the FieldName is set to 'accountCreatedFromLead'
You still can't filter a SOQL query on this FieldName field on the FeedTrackedChange object, but you could query all of them and just loop through the results to find just the lead conversion messages.
Something like this would work...
List<AccountFeed> lstAccountFeedsToDelete = new List<AccountFeed>();
for(AccountFeed objFeed : [SELECT Id,
                                  (SELECT Id,
                                          FieldName,
                                          OldValue,
                                          NewValue
                                   FROM FeedTrackedChanges)
                           FROM AccountFeed
                           WHERE Type = 'TrackedChange'])
{
    for(FeedTrackedChange objChange : objFeed.FeedTrackedChanges)
    {
        if(objChange.FieldName == 'accountCreatedFromLead')
          lstAccountFeedsToDelete.add(objFeed);
    }
}
delete lstAccountFeedsToDelete;

Unfortunately the FeedTrackedChange object is not accessible directly.  As far as I know, you can only access it in a nested query like this example.
ChickenOrBeefChickenOrBeef
Hey Scott,

Thanks so much for the reply, but it seems the trigger isn't working for me. This is what I changed it to:

public class ClassDeleteConvertAlerts{
    
    public void deleteAlerts(List<Lead> leads,Map<Id,Lead> oldLeads){
        
        Set<String> convertedLeads = new Set<String>();
        List<AccountFeed> listAccountFeedsToDelete = new List<AccountFeed>();
        
        FOR(Lead l : leads){
            IF(l.IsConverted == TRUE && oldLeads.get(l.Id).IsConverted == FALSE){
                convertedLeads.add(l.Id);
            }
        }
        
        System.debug('Converted Leads size is ' + convertedLeads.size());
        
        IF(convertedLeads.size() > 0){
            
            FOR(AccountFeed objFeed : [SELECT Id,
                                  		(SELECT Id,FieldName FROM FeedTrackedChanges)
                           			   FROM AccountFeed
                           			   WHERE Type = 'TrackedChange']){
    
                                           FOR(FeedTrackedChange objChange : objFeed.FeedTrackedChanges){
                                               IF(objChange.FieldName == 'accountCreatedFromLead'){
          
                                                   listAccountFeedsToDelete.add(objFeed);
                                                   
                                               }
    
                                           }

                                       }
            
            System.debug('Accound Feeds To Delete size is ' + listAccountFeedsToDelete.size());

            DELETE listAccountFeedsToDelete;
            
        }
        
    }

}

I tried converting a lead, and here were the results of the system.debug statements:

User-added image

Any idea what I'm doing wrong? Should I be doing this trigger on lead conversion or the creation of an account feed record?

Thanks!
-Greg
ChickenOrBeefChickenOrBeef
Hey Scott,

Just following up again. Would I perhaps need to use a "custom feed"? According to this, it seems I may have to, since it says standard feeds are read-only. But I can't find any documentation on how to create a custom feed:

User-added image

Or perhaps I would have to use batch apex?

Thanks!
-Greg
Community User2Community User2
Hi Greg,

 Were you able to solve it.I have same reqirement to delete chatter feed on Account when Lead gets converted.I found an idea (https://success.salesforce.com/ideaView?id=08730000000ZOlIAAW) related to this.
ChickenOrBeefChickenOrBeef
Hey CM2,

No, I haven't solved this. In fact, I think I have to give up on it for now, since no one I've asked is sure what to do.
Community User2Community User2
Thanks Greg.I also wrote trigger on FeedItem but its not running when I convert lead.There is another post (http://salesforce.stackexchange.com/questions/36591/delete-chatter-post-on-account-after-lead-gets-converted) on stack exchange related to this.
Community User2Community User2
Sometimes there is a slight delay in deletion otherwise it works great

Trigger DeleteAccountFeed on Lead (after update) {


    Set<String> convertedLeads = new Set<String>();
    List<Id> convertedAccountList = new List<Id>();

    FOR(Lead l : trigger.new){
        IF(l.IsConverted == TRUE && trigger.oldmap.get(l.Id).IsConverted == FALSE){
            convertedLeads.add(l.Id);
           convertedAccountList.add(l.convertedAccountId);
         }
    }

   
    IF(convertedLeads.size() > 0){
        DeleteAccountFeedFutureClass.DeleteFeed(convertedAccountList);
    }
}

global class DeleteAccountFeedFutureClass {

@future
public static void DeleteFeed(List<ID> recordIds)
  {
       list<AccountFeed> listAccountFeedsToDelete = new list<AccountFeed>();
        FOR(AccountFeed objFeed : [SELECT Id,Type,ParentId,(SELECT Id,FieldName FROM FeedTrackedChanges)
                                       FROM AccountFeed WHERE Type = 'TrackedChange' and ParentId in: recordIds]){
                                       system.debug('ObjFeed....'+ObjFeed);
                                       FOR(FeedTrackedChange objChange : objFeed.FeedTrackedChanges){
                                           system.debug('objChange...'+objChange);
                                           IF(objChange.FieldName == 'accountCreatedFromLead' || objChange.FieldName == 'accountUpdatedByLead'){
                                                System.debug('Accound Feeds To Delete is ' + listAccountFeedsToDelete);
                                                listAccountFeedsToDelete.add(objFeed);
                                                System.debug('Accound Feeds To Delete is ' + listAccountFeedsToDelete);
                                           }

                                       }

                                   }
       DELETE listAccountFeedsToDelete;
   }
}


This was selected as the best answer
ChickenOrBeefChickenOrBeef
Hey CM2,

It works! Since I'm using a class (that's called in a main trigger) instead of making this a trigger itself, I had to tweak your code to the following:


public class ClassDeleteConvertAlerts{
   
    public void deleteAlerts(List<Lead> leads,Map<Id,Lead> oldLeads){
       
    Set<String> convertedLeads = new Set<String>();
    List<Id> convertedAccountList = new List<Id>();

    FOR(Lead l : leads){
        IF(l.IsConverted == TRUE && oldLeads.get(l.Id).IsConverted == FALSE){
            convertedLeads.add(l.Id);
           convertedAccountList.add(l.convertedAccountId);
         }
    }

  
    IF(convertedLeads.size() > 0){
        ClassDeleteConvertAlerts.DeleteFeed(convertedAccountList);
    }
  }   

@future
public static void DeleteFeed(List<ID> recordIds)
  {
       list<AccountFeed> listAccountFeedsToDelete = new list<AccountFeed>();
     
        FOR(AccountFeed objFeed : [SELECT
                                    Id,Type,ParentId,
                                   (SELECT Id,FieldName FROM FeedTrackedChanges)
                                   FROM
                                    AccountFeed
                                   WHERE Type = 'TrackedChange' and ParentId in: recordIds]){
                                      
                                       FOR(FeedTrackedChange objChange : objFeed.FeedTrackedChanges){
                                           IF(objChange.FieldName == 'accountCreatedFromLead' || objChange.FieldName == 'accountUpdatedByLead'){
                                                listAccountFeedsToDelete.add(objFeed);
                                           }

                                       }

                                   }
       DELETE listAccountFeedsToDelete;
   }
   
}


And yeah, it seems to take a few seconds to delete the feed item, but that's fine. Thanks again!

-Greg