We have a problem in our org whereby we’re using 122% of our Salesforce File storage, looking at what we have stored and where, almost all of that is within the Attachment
object.
Record Type – Record Count – Storage – Percent
Attachments – 14,453,216 – 1.1 TB – 100%
I have a requirement to bring that percentage down and one way we can do that is to remove all unnecessary word documents. We have a parcer that, when we upload attachments (specifically Resumes), the document gets the name Resume_
appended to it and a .pdf
is also created which is then used by a Visualforce page embedded within the Contact page layout, making the Word document vesion redundant.
I figured we could create a lot of space by first removing all word documents that start with Resume_
(we might have other documents that we shouldn’t delete, this is why I need to specifically look for this). I’ve written the script below that should do just that:
List<Id> contactIds = new List<Id>(); List<Attachment> attachmentList = new List<Attachment>(); List<Attachment> toDelete = new List<Attachment>(); for (Contact c : [SELECT Id FROM Contact WHERE Id = '0032500000M1uXO' LIMIT 200]) { contactIds.add(c.Id); } System.debug('List of Contact Ids: ' + contactIds); for (Attachment a : [SELECT Id, Name, CreatedDate, ContentType FROM Attachment WHERE ParentId IN :contactIds And ContentType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ORDER BY CreatedDate DESC]) { attachmentList.add(a); } System.debug('List of Attachments: ' + attachmentList); for (Attachment a : attachmentList) { if (a.Name.startsWithIgnoreCase('Resume')) { toDelete.add(a); } } System.debug('These will be deleted:' + toDelete); //DELETE toDelete
In a nutshell, what I’m doing here is:
- Looping through and getting a list of Contact Ids
- Looping through that list of Contact Ids to get a list of Attachments
- Looping through that list of attachments, checking if they start with
Resume
and adding them to atoDelete
list - That list will then get deleted (commented out, for now)
Based off of the test contact I made and the resume uploaded, the following appears to be the ContentType for Word documents:
application/vnd.openxmlformats-officedocument.wordprocessingml.document
This seems to retrieve what I need to delete based off of the System.debug()
I’m printing, but I do have a couple of questions in what I’m doing here:
- Is the code good? I’m slightly unfamiliar with bulkification. I feel like I’ve done this in a good way, but not the best way.
- We have about 2,100,000+ Contact records, is there anything that should concern me with this? Performance issues for example?
- Because we have such a large quantity of Contacts and even more attachments, what would be the best way of running this script? As a batch, perhaps?
- Will the content type:
application/vnd.openxmlformats-officedocument.wordprocessingml.document
remove both.doc
and.docx
files, or is there a better way of getting these? - If I do run this as a batch class, won’t it re-query the same Contact records?
Advice here would be greatly appreciated!
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You can try it in batch
global class ExampleBatchClass implements Database.Batchable<sObject>{ global ExampleBatchClass(){ // Batch Constructor } // Start Method global Database.QueryLocator start(Database.BatchableContext BC){ return Database.getQueryLocator('SELECT ID FROM Contact); } // Execute Logic global void execute(Database.BatchableContext BC, List<contact>scope){ // Logic to be Executed batch wise for (Attachment a : [SELECT Id, Name, CreatedDate, ContentType FROM Attachment WHERE ParentId IN :scope And ContentType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ORDER BY CreatedDate DESC]) { attachmentList.add(a); } System.debug('List of Attachments: ' + attachmentList); for (Attachment a : attachmentList) { if (a.Name.startsWithIgnoreCase('Resume')) { toDelete.add(a); } } System.debug('These will be deleted:' + toDelete); //DELETE toDelete } global void finish(Database.BatchableContext BC){ // Logic to be Executed at finish // may be an email } }
Now execute your batch as
ExampleBatchClass b = new ExampleBatchClass(); //Parameters of ExecuteBatch(context,BatchSize) database.executebatch(b,1);
It will process one record of contact at a time.
Note:
Also in your code you are giving id and limit 200 don’t understand the reason.
for (Contact c : [SELECT Id FROM Contact WHERE Id = '0032500000M1uXO' LIMIT 200]) { contactIds.add(c.Id); }
And for your concern batch query record only one time so it will not call same record again. Hope this code help you or let us know if you have any other doubts.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0