1

We imported numerous notes into Salesforce and we were able to connect most of them to their corresponding objects with ContentDocumentLink. However, a few of need to be manually connected. So how can I list all notes which are not related to anything yet?

I tried querying all ContentDocumentLinks, but then I get the error message:

Implementation restriction: 
ContentDocumentLink requires a filter by a single Id 
on ContentDocumentId or LinkedEntityId using the equals operator 
or multiple Id's using the IN operator.
2

You need to do a couple of things here.

1. You need the list of your Opportunities.

2. Then you need a list of the ContentDocumentLinks that are related to the Opportunities in that list.

3. Then we can get all ContentNotes that are not part of anything or related to any object.

    List<Opportunity> oppList = [SELECT Id FROM Opportunity];
    Set<Id> oppIds = new Set<Id>();
    Set<Id> contentDocutIds = new Set<Id>(); 

    for(Opportunity opp : oppList) {
        oppIds.add(opp.Id)
    }

    for(ContentDocumentLink conDocuments : [
         SELECT ContentDocumentId 
         FROM ContentDocumentLink 
         WHERE LinkedEntityId IN :oppIds]){
         contentDocutIds.add(conDocuments.ContentDocumentId);
     }

     // Now we get all parentless ContentNotes
     List<ContentNote> contentNotes = [SELECT Id FROM 
     ContentNote WHERE Id NOT IN: contentDocutIds];

     for(ContentNote conNote : contentNotes) {
      System.debug(conNote.Id);
     }

You can test this in a sandbox first if you want to. Create a new ContentNote using the Developer Console, Execute Anonymous:

ContentNote cn = new ContentNote();
cn.Title = 'test2';
String body = 'Hello World';
cn.Content = Blob.valueOf(body);
insert(cn);

Run the code on an Execute Anonymous:

List<Opportunity> oppList = [SELECT Id FROM Opportunity];
Set<Id> oppIds = new Set<Id>();
Set<Id> contentDocutIds = new Set<Id>(); 

for(Opportunity opp : oppList) {
    oppIds.add(opp.Id)
}

for(ContentDocumentLink conDocuments : [
     SELECT ContentDocumentId 
     FROM ContentDocumentLink 
     WHERE LinkedEntityId IN :oppIds]){
     contentDocutIds.add(conDocuments.ContentDocumentId);
 }

 // Now we get all parentless ContentNotes
 List<ContentNote> contentNotes = [SELECT Id FROM 
 ContentNote WHERE Id NOT IN: contentDocutIds];

 for(ContentNote conNote : contentNotes) {
  System.debug(conNote.Id);
 }

Check output: In my case one new ContentNote:

enter image description here

UPDATE

You probably want to do something like this then: Extract parent Id of ContentNotes

This gets a bit complex because there is not a ParentId in the ContentNotes.

You can get all your ContentNotes like this:

List<ContentNote> contentNotes = [
        SELECT Id
        FROM ContentNote
];

Then you can pass the ids from that SOQL to strings like this:

List<String> stringIds = new List<String>();

for(ContentNote cn : contentNotes) {
    stringIds.add(String.valueOf(cn.Id));
}

Now that we have our ContentNotes ids we can do something like this:

List<ContentDocumentLink> clist = [SELECT Id, ContentDocumentId, ContentDocument.Title, ContentDocument.FileType, LinkedEntityId, ShareType, Visibility FROM ContentDocumentLink WHERE ContentDocumentId IN : stringIds];

Now you can access the LinkedEntityId which it is the ParentId for the ContentNotes. But there is a catch here. This fields will keep track of the Owner and the Related Object.

This means that you can see one ContentDocumentId with two LinkedEntityId.

If you execute this on a execute anonymous window:

List<ContentNote> contentNotes = [
            SELECT Id
            FROM ContentNote
    ];

    List<String> stringIds = new List<String>();

    for(ContentNote cn : contentNotes) {
        stringIds.add(String.valueOf(cn.Id));
    }

List<ContentDocumentLink> clist = [SELECT Id, ContentDocumentId, ContentDocument.Title, ContentDocument.FileType, LinkedEntityId, ShareType, Visibility FROM ContentDocumentLink WHERE ContentDocumentId IN : stringIds];
System.debug(clist);

You can get something similar to this if you have a ContentNote that is related to an SObject and one that is not (except USER object):

enter image description here

On the screenshot from above there is one ContentNote related to the Account object '001', and to the user object, '005'. The last ContentDocumentLink has only one LinkedEntityId starting with 005.. user object.. perhaps you can use that as a way to find out which ContentNotes are not related to any SObjects, expect the User object. On my test the last ContentDocumentLink is only connected to the user object, so I know that it is parentless to any other object.

I can see that there is a difference between the ShareType on ContentDocumentLinks that are related to a user and any other SObject. On the screenshot from above take a look to the ShareType for the two first records. The User have I on the ShareType and the other SObject has a V. You can explore that as well to see if it is something standard after creating a ContentNote.... well ... I hope it helps.

4
  • That's Classic Notes. If ContentDocumentLink is involved these records would be ContentNote or ContentDocument records.
    – David Reed
    Jan 19 '20 at 20:37
  • Yes, you right.. let me change a few things to make this answer more accurate. Jan 19 '20 at 20:52
  • @CarlosNaranjo Cool, thx, but it's not quite right yet. I need all notes which aren't related to anything, not just not related to opportunities.
    – adius
    Jan 21 '20 at 11:20
  • @adius, check the update... is not an easy task.. but I think that this may help. Jan 22 '20 at 0:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.