Query of records based on relationships - salesforce

I have an object Contract that has a look-up to another object Indexationtype. I have another object IndexationEntry that has master-detail to Indexationtype. Now I would like to get the value of the percentage field in the IndexationEntry onto Contract based on the yer fields. The year in the IndexationEntry matches Year in Contract. How should I achieve this?

From Contract "up" to IndexationType__c, then "down" to IndexationEntry__c?
If there's no direct link between them it's not going to be pretty. One way would be something like this
SELECT Id, Name,
(SELECT Id, ContractNumber FROM Contracts__r WHERE Year__c = '2021'),
(SELECT Id, Percent__c FROM IndexationEntries__r WHERE Year__c = '2021')
FROM IndexationType__c
You'd have to run it once for each year. Or (since you tagged it Apex) maybe you can prepare the reference data a bit, query Indexation Types + Entries and build something like Map<Id, Map<Integer, IndexationEntry__c>> (1st key is by Indexation Type Id, then by year). Query them, populate the Map, then loop through your contracts and use map.get() to fetch your values.

Related

Elasticsearch equivalent of NOT IN (SELECT ..)

We have something like this (we save an item for each episode, show and user. And all items are saved on the same index.):
and we need to list all episodes from a show, but we need to filter the episodes already watched by the user.
In PostgreSQL i would have run something like this:
SELECT * FROM Episode WHERE show_id = 'showID' AND episode_id NOT IN (SELECT episode_id FROM watched WHERE user_id = 'userId')
But since we are using Elasticsearch, we are not sure what would be the alternative.
We also assume that the watched list is going to scale, so we can't just send an array of ids to ES.
Is there a way for Elasticsearch to handle all the logic, and filter from a dynamic array of values on a single query.
We just used joins, and has_child.
We filter all parents that have a watched child item.

Didn't understand relationship 'LinkedEntityId' in field path

So I am generally able to query the relationships but I do not have the access to this object in object manager, so what should be the query to access accountId from ContentDocumentLink object when I know LinkedEntity is a case.
My Code:
List<ContentDocumentLink> case_file_links=
[
SELECT Id,ContentDocumentId,LinkedEntityId.AccountId,ShareType
FROM ContentDocumentLink
WHERE Id IN: case_file_link_Ids
];
Error:
SELECT Id,ContentDocumentId,LinkedEntityId.AccountId,ShareType
^
ERROR at Row:2:Column:45
Didn't understand relationship 'LinkedEntityId' in field path. If you..
LinkedEntityId is a weird mutant lookup to many tables, any table that supports File upload. Official name is "polymorphic lookup".
Maybe you worked with Tasks before, they have similar fields. WhatId can point to Account, Case, Opportunity plus many custom objects. and WhoId points to User/Contact/Lead.
So it's a lookup to "something". It's not guaranteed it's to Cases so at compile time SF can't just blindly accept AccountId. What if the field is not there.
You might have to use TYPEOF in SOQL.
SELECT Id, ContentDocumentId, ShareType,
TYPEOF LinkedEntity WHEN Case THEN CaseNumber, Subject, AccountId END
FROM ContentDocumentLink
WHERE Id IN ('06A7a000001VafmEAC', '06A7a000001VafnEAC')
Developer Console is too stupid to display it properly but workbench should manage
In Apex you'll need an instanceof to check and cast the LinkedEntity to right sObject... or use the generic sObj.get('AccountId') and if it's not there it'll return null?
If this sounds like too much hassle - you can always split it into 2 queries.
Query just SELECT Id, ContentDocumentId, LinkedEntityId, ShareType FROM ContentDocumentLink
Loop through results, collect LinkedEntityId into a helper Set<Id>.
Map<Id, Case> cases = new Map<Id, Case>([SELECT Id, AccountId FROM Case WHERE Id IN :mySet]);

Query of Arrays in Salesforce

I need to do 1 of two things (I believe):
1- Get a Custom Object ID so I can query it directly
2- Get a list of values of a specific field within the Object entries.
Ultimate End goal:
Add and modify rows in my custom object via external API. However to do this I need to check and make sure my new entry/row does not already exist.
What I have:
I have a custom object (called Customer_Arrays__c). It is a table that I can add new rows to (I will call entrys). Each entry has 6 or 7 fields. 1 of these fields is called (external_ID__c). This is the field I utilize to match to new incoming data to see if the entry already exists, or if it needs to add a new row to my table. This Customer_Arrays__c is a child to my opportunity I believe – it is part of every opportunity and each line item I add has a field defaulted to the opportunity.
Help I need:
1- How do I query the value of my Cutomer_Arrays__c based upon an opportunity ID?
2- How do I query a list of values in my (external_ID__c) based upon an opportunity ID?
Thanks for your help! I have read half a dozen+ posts on similar topics and am missing something. Examples of some Past try's that failed:
Select external_ID__c,FROM Custom_Arrays__c WHERE Opportunity='00...'
Select Id (Select ID, Custom_Arrays__c from Custom_Arrays__c) from Opportunity where id ='00...'
List FROM Custom_Arrays__c WHERE Opportunity='00...'
Select Id, external_ID__c, (Select external_ID__c FROM Custom_Arrays__c) WHERE Opportunity__c='00...'
Thanks again!
Only you know how did you name the lookup field (foreign key) from arrays to Opportunity. You'll need to check in setup, next to where external_ID__c is. Since it's a custom field (gets __c at the end), my guess is you went with default.
Try
SELECT Id, Name, External_Id__c
FROM Customer_Arrays__c
WHERE Opportunity__c = '006...'
Thank you eyescream, that got me almost all the way there. Turns out I also needed a __r for the parent child relationship.
Here is a snip out of my final code that works - I think it covers everything:
SELECT Field1__c, Opportunity__r.Id, Opportunity__r.Opportunity__c,
FROM Customer_Arrays__c
WHERE Opportunity__r.Id = '006...'.
Thank you so very much!!!

is SOQL capable of self joins mysql style?

Is it possible to do a self join with table aliasing? Lets's say I'm a book shop and I want to get all customers that purchased a book last week AND this week. In MySQL this would look somehow like this:
SELECT Account.id from Opportunity o1, Opportunity o2
WHERE o1.closeDate = Last_WEEK AND o2.closeDate = This_WEEK
AND o1.Account = o2.Account
What would be the equivalent in MySQL? It keeps puzzling me.
You can't compare one Opportunity Account Id with another in SOQL (o1.Account = o2.Account). If you try you will get the message:
Bind variables only allowed in Apex code
If instead you rework the SOQL to use a sub query you will get a different error.
SELECT AccountId from Opportunity o1
where o1.closeDate = LAST_WEEK
AND o1.Account in
(SELECT AccountId from Opportunity o2 WHERE o2.closeDate = THIS_WEEK)
Gives:
The inner and outer selects should not be on the same object type.
You will need to either:
perform two queries to get the required data. You could feed the resulting Account Ids of the first query into the second query as a where clause filter.
retrieve the Account Ids with either close date in one SOQL query and then build up the required sets with code.
Incidentally, the Salesforce StackExchange site is a great place to ask Salesforce specific questions.

Updating records on cousin object using SF Apex

We have an app that is made up of almost entirely custom objects. Creating a smooth workflow for our users is vital for this app. I'm new to apex, but familiar with basic code writing.
Here are the relationships between the objects: (--< = 1 to many, M/D = Master/Detail)
Object_a --< Object_b --M/D--< Object_c;
Object_a --M/D--< Object_d
When a user populates a date field on Object_c and saves, we'd like a date field on all related records on Object_d (i.e. all Object_d's records for that specific Object_a record) to be updated with the same value.
Any help is appreciated.
You'll need to write a trigger on insert / update of Object_c as workflow rules can't fire on update of multiple objects and rollup summary fields won't help (master-details aren't set everywhere).
Before you deep dive into coding please consider what should happen if you have more than 1 Object__c modified at the same time (with Data Loader for example, through integration with some external system or other piece of code). If you have 2 records that both are related to same Object_A and one has "today" while other has "today + 7", which value should "win"?
One way of solving it would be to start with a map of Object_A Ids and date values to set. The way I'll be building the map means I'll keep overwriting the values on case of duplicate id which is not what you might need (select later of the dates maybe?).
Map<Id, Date> datesToSet = new Map<Id, Date>(); // you could make it Map<Id, Object_C__c> too, principle would be similar
for(Object_C__c c : [SELECT Id, Date_Field__c, Object_B__r.Object_A__c FROM Object_C__c WHERE Id IN :trigger.new AND Object_B__r.Object_A__c != null]){
datesToSet.put(c.dObject_B__r.Object_A__c, c.Date_Field__c);
}
System.debug(datesToSet);
Now we have map of unique A ids and values we should apply to all their child D records.
List<Object_D__c> childsToUpdate = [SELECT Id, Some_Other_Date_Field__c, Object_A__c FROM Object_D__c WHERE Object_A__c IN :datesToSet.keyset()];
System.debug('BEFORE: ' + childsToUpdate);
for(Object_D__c d : childsToUpdate){
d.Some_Other_Date_Field__c = datesToSet.get(d.Object_A__c);
}
System.debug('AFTER: ' + childsToUpdate);
update childsToUpdate;

Resources