3
votes

Basically, I need a single SOQL query, executable using the web service API, that will return all NoteAndAttachment items that would normally show in the Notes And Attachments section of an Account page in the Salesforce Web UI. This includes not only N&A that are attached to the Account itself, but also those that are attached to any Case, Opportunity, or Contact that is related to the Account. Salesforce itself seems to have no problem getting that information, but between SOQL limitations and restrictions on the data model, I have yet to find a satisfactory solution.

Here's what I have so far:

SELECT Id,
(select Id, Title, IsNote from NotesAndAttachments),
(select Id, Title, IsNote from Contacts.NotesAndAttachments),
(select Id, Title, IsNote from Cases.NotesAndAttachments),
(select Id, Title, IsNote from Opportunities.NotesAndAttachments)
FROM Account a WHERE Id = '{0}'

The {0} is for use with a .NET String.Format; it'll be the account ID I'm pulling records for. This particular query fails with the following exception:

System.Web.Services.Protocols.SoapException : INVALID_FIELD: 
(select Id, Title, IsNote from Contacts.NotesAndAttachments),
                               ^
ERROR at Row:3:Column:48
Didn't understand relationship 'Contacts' in field path. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names.

These are all basic, system-defined relationships, and it didn't recognize the singular "Contact" either, so I'm at a loss.

Other solutions have involved semi-join sub-selects (there's a limit of two and you can't combine them with "OR", so no dice), nested subqueries (can't), etc. I'm really at my wits end with this query language's limitations; no UNION, limited subqueries, limited subquery depth, and the NoteAndAttachment entity cannot be queried directly. There simply has to be a way to get these records the same way they're shown in the website, but I'm being frustrated at every turn.

EDIT: My answer for now is to query the NotesAndAttachments property of each of the containing object types (Account, Contact, Opportunity) and also pull Attachments from Case and project them as NotesAndAttachments to get the information I need. This process requires four roundtrips, and takes an average of about 15 seconds for 5 records' summary information (no note bodies or file binaries). I was able to push the data retrieval off to an asynchronous thread, which mitigates the retrieval time, but the performance will probably still be unsatisfactory. I'll continue to work on something more performant, but for now I've got it working.

5

5 Answers

5
votes

There appears to be two issues here...

  1. You cannot query the NotesAndAttachments object directly - this is a combination of the Notes and the Attachments object.
  2. You can only query down to 1 level on parent-to-child relationships. You can have a sub-query to Contacts, but you cannot have a sub-query to notes or attachments on contacts.

I think your only option here would be to do four queries. However this could cost you a lot of API calls if you are looping over multiple Account Ids.

SELECT Id,
(SELECT Id, Title FROM Notes),
(SELECT Id, Name FROM Attachments)
FROM Account WHERE Id = '{0}'

SELECT Id,
(SELECT Id, Title FROM Notes),
(SELECT Id, Name FROM Attachments)
FROM Contact WHERE AccountId = '{0}'

SELECT Id,
(SELECT Id, Title FROM Notes),
(SELECT Id, Name FROM Attachments)
FROM Case WHERE AccountId = '{0}'

SELECT Id,
(SELECT Id, Title FROM Notes),
(SELECT Id, Name FROM Attachments)
FROM Opportunity WHERE AccountId = '{0}'
0
votes

You may have better luck starting with the Attachment sobject.

You are probably going to have to do this in more than one query. There are limitations on relationship queries depending on the direction of the relationship. See relationship queries

0
votes

I was wondering if it wouldn't be even better to do a query for all Attachments and another for all Notes, no matter the kind of father object they have, like so:

SELECT Id, Name, parent.Id, parent.Name, parent.Type FROM Attachment
SELECT Id, Title, parent.Id, parent.Name, parent.Type FROM Note

This way you can use the parent Type to group the attachments, you will get all the attachments available and it should be faster.

If you really need to be limited to this types of objects you cloud do something like:

SELECT Id, Name, parent.Id, parent.Name, parent.Type FROM Attachment where parent.type like '%Account%' OR parent.type like '%Contact%' OR parent.type like '%Case%' OR parent.type like '%Opportunity%' 

Hope it helps.

0
votes

I found from salesforce side.

The following objects are not currently supported in subqueries:

ActivityHistory

Attachments

Event

EventAttendee

Note

OpenActivity

Tags (AccountTag, ContactTag, and all other tag objects)

Task

refer: http://www.salesforce.com/us/developer/docs/officetoolkit/Content/sforce_api_calls_soql_select.htm

0
votes

Point 1: Notes independent of the parent object.

With the latest spring 2021, I saw that the details that we want to capture from Notes and Attachment have been moved to a different object all together.

For getting the text and other infos these notes now, we can query on ContentVersion object, this is a standard object and you can simply make the SOQL query to retrieve the data, In my case I had to retrieve the information of Notes so here is the below query.

SELECT Id, Title, Description, TextPreview FROM ContentVersion

Point 2: Notes based on a parent object like Opportunity

If you wish to retrieve the Notes based on parent Object like Opportunity or Account. You can go with the following SOQL which will be made on a separate object.

Opportunity opp = [SELECT Id,
(SELECT ID, Title FROM AttachedContentNotes)
FROM Opportunity where id = 'xxxxx'];

Benefit : YOU CAN HAVE ALL THE NOTES ASSOCIATED TO A SINGLE OBJECT

I hope this will help all.