+ Start a Discussion
Olavo ZapataOlavo Zapata 

Update child records Lookup ID from parent using Process Builder

Hello guys,

I have a custom object that I need to update it via API with our product's information.
For this, we create an Object ('Tests1intgre') with an External ID ("RDStationID") that the external ID also exists in the Account object.

My question is, how to reference these objects? There is already a Lookup Relationship field of the Account in the Test object.

What I tried was to create a process builder to identify the RD Station ID in the 2 objects and bring me the account into the test object.
However, show me that it isn't possible to register.

Process Builder print 1: http://prntscr.com/jxbqme
Process Builder print 2: http://prntscr.com/jxbq5v

I hope you can help me. Thanks,
Best Answer chosen by Olavo Zapata
Abdul KhatriAbdul Khatri
My bad forgot the field in the query

Try this
trigger UpdateAccountId on Tests1intgre__c (before update, before insert) {

    Map<String, Tests1intgre__c> tintgreMap = new Map<String, Tests1intgre__c>();
    
    for(Tests1intgre__c ti : trigger.new) {
        
        if(trigger.isInsert || (trigger.isUpdate && ti.RDStationID__c != trigger.oldMap.get(ti.Id).RDStationID__c)) {
            tintgreMap.put(ti.RDStationID__c, ti);
        }
    }

    if(tintgreMap == null) return;
    
    Map<String, Account> accountMap = new Map<String, Account>();
    for (Account account : [Select Id, RDStationID__c From Account Where RDStationID__c = :tintgreMap.KeySet()]) {
        accountMap.put(account.RDStationID__c, account);
    }
    
    if(accountMap == null) return;
    
    for(Tests1intgre__c tiRecord : tintgreMap.Values()) {
        
        tiRecord.Account__c = accountMap.get(tiRecord.RDStationID__c).Id;
        
    }

}

 

All Answers

Abdul KhatriAbdul Khatri
Please confirm if it is the right understanding
  • Tests1intgre (Custom Object)
    • AccountId (Lookup Account)
    • RDStationID (External ID)
  • Account (Standard Object)
    • RDStationID (Text)

When RDStationID gets updated via API, you wanted the same value get updated on the Account Level.
Olavo ZapataOlavo Zapata
Hi @Abdul Khatri,

Confirming:
  • Tests1intgre (Custom Object)
    • AccountId (Lookup Account)
    • RDStationID (External ID)
  • Account (Standard Object)
    • RDStationID (External ID)
What I want is when the RDStationID gets updated via API in the Test object a process automatically insert de AccountID in Test Object as well to make the lookup.
 
Abdul KhatriAbdul Khatri
OK so what I understand you want to update the AccountId Lookup Field automatically on the Tests1intgre Custom Object.

If that is true then what is my filter point of selecting which Account to pick?
Olavo ZapataOlavo Zapata
The connection should be by the External ID (rdstationID)
Abdul KhatriAbdul Khatri
So can't you update AccountId at the same time when you are updating RDStationID, I guess both on the Test Object and the Account Object via API. Why you need a separate process for that.

What is you process of updating the RDStationID via API for example a trigger or a webservice etc. Can you share?
Olavo ZapataOlavo Zapata
Ok, I understand your point.
I could update both in the same time RDStationID and AccountID, but in our product (what will send the information) we don't have SFDC Account ID So we would need to first match the RDStationID in Account to get back the AccountID and after save to Test Object both in the same time.

I would like to request the API just one-time, upserting information and not just selecting the Account ID.

 
Olavo ZapataOlavo Zapata

Just sharing my connections is almost like this:

def sync_accounts(accounts)
    upsert('Account', map_accounts(accounts), 'rdstationid__c', true)
  end
 def fetch_salesforce_accounts_ids(accounts)
    return {} unless accounts && accounts.size > 0
    rows = select_ids_from_salesforce(accounts)
    rows.inject({}) { |a, e| a.merge(SalesforceHelper.salesforce_row_to_ids_hash(e)) }
  end

  def select_ids_from_salesforce(accounts)
    query = fetch_accounts_query(accounts)
    response = @salesforce_bulk_client.query('Account', query)
    response['batches'][0]['response'] || []
  end

  def fetch_accounts_query(accounts)
    ids = accounts.map(&:external_code).join("','")
    "select rdstationid__c, id from Account where rdstationid__c in ('#{ids}')"
  end

  def upsert(data_type, map, gs_table, get_response = false)
    @salesforce_bulk_client.upsert(data_type, map, gs_table, get_response, fieldsToNull: fields_to_null(map))
  end
Abdul KhatriAbdul Khatri
I think you are using some third party api in order to interact with salesforce. Not sure which one. What I can see here is that you are bascially creating the Test1intgre and Account at the same time for the RDStationID.

The issue here is that you want to update the AccountId on the custom Object Test1intgre based on RDStationID__c which are basically linked with Account. This is what I understood. 

Keeping this perspective I don't think you can achieve that through Process builder because you need to match the Tests1intgre record to the Account record based on RDStationID in order to get the AccountId. You can only do that through Referencing AccountId on Tests1intgre object but that value is null which is actually you wanted to update. The process builder will fail because of the AccountId null, which make sense.

For now I think you can do that through triigger and here is that. Not sure if you want to go through this route
trigger UpdateAccountId on Tests1intgre__c (before update, before insert) {

    Map<String, Tests1intgre__c> tintgreMap = new Map<String, Tests1intgre__c>();
    
    for(Tests1intgre__c ti : trigger.new) {
        
        if(trigger.isInsert || (trigger.isUpdate && ti.RDStationID__c != trigger.oldMap.get(ti.Id).RDStationID__c)) {
            tintgreMap.put(ti.RDStationID__c, ti);
        }
    }

    if(tintgreMap == null) return;
    
    Map<String, Account> accountMap = new Map<String, Account>();
    for (Account account : [Select Id From Account Where RDStationID__c = :tintgreMap.KeySet()]) {
        accountMap.put(account.RDStationID__c, account);
    }
    
    if(accountMap == null) return;
    
    for(Tests1intgre__c tiRecord : tintgreMap.Values()) {
        
        tiRecord.Account__c = accountMap.get(tiRecord.RDStationID__c).Id;
        
    }

}
Abdul KhatriAbdul Khatri
Hi, Please let me know your thoughts.
Olavo ZapataOlavo Zapata
Hi @Abdul,

First of all, I would like to say many thanks for your attention.
My application is in Ruby because this is a bit different. Anyway, you are completely right with my intentions to update the AccountId on the Custom Object.

But from what I understood of your code, the logic is basically what I have today in my integration.
The combining of account and rdstationID fields are done externally, not in Salesforce.

What I would like to try is for Salesforce to do this.
That when I enter my External ID into a custom object it checks the account for the respective accountID and writes this to me in the custom object.

The benefits I see are:
Reduced connection to the API.
Performance Improvement, avoiding getting access to the Account to get the ID I can be writing to different objects in parallel.

I can't believe it is not possible to do this. Even if it is not for Process Builder there must be some way.
Abdul KhatriAbdul Khatri
Isn't my trigger doing the same what you are asking

What I would like to try is for Salesforce to do this.
That when I enter my External ID into a custom object it checks the account for the respective accountID and writes this to me in the custom object.

 
Olavo ZapataOlavo Zapata
Oh man,

Now I understood what you mean.
You are suggesting to do trough Trigger Apex, aren't you?

I'm totally newbie in this feature, I taught your suggestion was to try something similar in our integration side.
I will get to study the apex and try your code.

Thanks for the moment.
Abdul KhatriAbdul Khatri
Yes Sir
Abdul KhatriAbdul Khatri
I have a trigger ready for you above which you can try. It should work with no issues.
Olavo ZapataOlavo Zapata
Hi Abdul, 

I tried you trigger in the Test1 Object.
But when I tried to insert a new record shows me a warning message:
Apex trigger UpdateAccountId caused an unexpected exception, contact your administrator: UpdateAccountId: execution of BeforeInsert caused by: System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: Account.rdstationid__c: Trigger.UpdateAccountId: line 16, column 1
So I tried many combinations to try to fix it but I didn't understand what happened.
Have any idea what could be?

Thanks.
 
Abdul KhatriAbdul Khatri
My bad forgot the field in the query

Try this
trigger UpdateAccountId on Tests1intgre__c (before update, before insert) {

    Map<String, Tests1intgre__c> tintgreMap = new Map<String, Tests1intgre__c>();
    
    for(Tests1intgre__c ti : trigger.new) {
        
        if(trigger.isInsert || (trigger.isUpdate && ti.RDStationID__c != trigger.oldMap.get(ti.Id).RDStationID__c)) {
            tintgreMap.put(ti.RDStationID__c, ti);
        }
    }

    if(tintgreMap == null) return;
    
    Map<String, Account> accountMap = new Map<String, Account>();
    for (Account account : [Select Id, RDStationID__c From Account Where RDStationID__c = :tintgreMap.KeySet()]) {
        accountMap.put(account.RDStationID__c, account);
    }
    
    if(accountMap == null) return;
    
    for(Tests1intgre__c tiRecord : tintgreMap.Values()) {
        
        tiRecord.Account__c = accountMap.get(tiRecord.RDStationID__c).Id;
        
    }

}

 
This was selected as the best answer
Olavo ZapataOlavo Zapata
Woooow!

Abdul works perfectly! It was exactly what I was looking for.
You were amazing!

Thanks a lot for that man.
Abdul KhatriAbdul Khatri
Thank you for providing me this opportunity.