I apologize for all the Velocity posts, but I'm bashing my head against the wall, so I want to get super basic here and explain the issues I am having and make sure I understand the syntax properly.
Here is a junk data image of one of our objects:
We tend to have multiple of these "Customer Profiles" underneath one email - so one "Lead" might actually hold the info for multiple individuals. This starts my rounds of very basic barebones questions:
1) For Custom Objects, to use the #foreach action, is this the correct syntax?
Assuming $individualEmailIdentifier is the field itself and customerProfiles is the object name?
#foreach ($individualEmailIdentifier in $customerProfilesList)
2) If I wanted to output ALL the values in the entire Customer Profile for "Age", would the syntax for the output be:
$customerProfilesList.age
OR
$age
3) If I wanted to output ONLY values related to one profile in the array, how do I ensure that? I'm assuming I would need something more distinct like a ROW ID or other field? I get using a #foreach, but how do I pull only one set of values instead of all?
4) In the case of the below, I get that the "get(0) pulls the 0th value in the Array, but I'm assuming it looks across the entire Customer Profile array regardless of which "profile" it is pulling from? It's pulling the most recent updated data for that particular field?
#if ( $customerProfilesList.get(0).membershipStatus.equals("Member") )
Lead is a Member
#else
Lead IS NOT a Member
#end
Basically, the issue across our data boils down to needing to pull multiple values from a specific row and I'm currently not able to effectively do that.
I apologize for the long post and probably basic questions, but I haven't found a lot of basic data on how to get started with Velocity within the context of Custom Objects - or I am looking for the wrong things 🙂 Thank you!!
Solved! Go to Solution.
Make sure you use the correct API name for the custom object list and the custom object fields. You could check the correct API name for the CO list and field when you pull the respective CO field in the email script editor. Alternatively, you could also check Marketo Admin > Custom Object > Select the correct custom object detail page.
1. Each custom object record has fields with values in it (e.g., the one you have shown in the snapshot represents one CO record with all its values). When you're looping through the custom object list, the first variable in the loop represents one single custom object record at the nth position (where n is the iteration, or the loop counter). You should not use a CO field name in the foreach loop, rather you should use a loop variable that'd be used the custom object record at the nth iteration. e.g., below:
#foreach($item in $customerProfilesList)
##$item would have the reference of custom object record at the nth iteration in the custom object list.
2. If you're accessing the age field for a custom object record in the foreach loop, you should use the loop variable:
$item.age
3. You loop through all the custom object records, in the loop-body check if it's the custom object record that you want based on certain fields and if so, output that CO record's fields as required. You could also user the sort method to sort the customobject list based on a field in either descending or ascending order and then print the CO fields of required CO record using the array index.
#set( $sortedList = $sorter.sort($customObjList,"updatedAt:desc") )
4. The most recently updated custom object is stored at the top (i.e., the 0th index). A lot of people have a misconception that CO records are sorted based on created date, but actually, records are sorted based on the updated At date in descending order. If you want to pull multiple records' fields you can either sort the CO and query it using the array indexing or loop through the entire CO list and check whether the CO record in the loop iteration is the one that you wish to print the data for using #if condition.
#foreach( $item in $customerProfilesList)
${item.field1}<br/>
${item.field2}<br/>
${item.field3}
##..and so on
#end
If you use a trigger campaign with trigger (Added to <CustomObjectName>), you could reference the same CO using the $TriggerObject in both emails. You could define constraints on the CO fields in case you don't want to let all CO additions qualify for the campaign flow.
The flow could be something like the below:
You could identify CO uniquely using the CO record's dedupe field, but there's no way you could write the dedupe field data of the CO record picked by Marketo during the email1 send to a lead field to reference later (so as to ensure you pick the exact same CO record in your next email as well).
Personally speaking, I'm not a fan of creating campaign flows with the first step as a big Wait step, as it depriortizes the campaign execution (granted, you could override the priority, but still!). Are you worried that a differenct CO record would be picked up in the email 2 send using the exact same conditions as the email 1 send? You could probably seal that gap using the createdAt field maybe (safely assuming that there's pretty neglible/almost no chance that there would be more than 1 CO record with same createdAt and other field values used in velocity).
Looking forward to other creative ideas to pull this off. 🙂
Make sure you use the correct API name for the custom object list and the custom object fields. You could check the correct API name for the CO list and field when you pull the respective CO field in the email script editor. Alternatively, you could also check Marketo Admin > Custom Object > Select the correct custom object detail page.
1. Each custom object record has fields with values in it (e.g., the one you have shown in the snapshot represents one CO record with all its values). When you're looping through the custom object list, the first variable in the loop represents one single custom object record at the nth position (where n is the iteration, or the loop counter). You should not use a CO field name in the foreach loop, rather you should use a loop variable that'd be used the custom object record at the nth iteration. e.g., below:
#foreach($item in $customerProfilesList)
##$item would have the reference of custom object record at the nth iteration in the custom object list.
2. If you're accessing the age field for a custom object record in the foreach loop, you should use the loop variable:
$item.age
3. You loop through all the custom object records, in the loop-body check if it's the custom object record that you want based on certain fields and if so, output that CO record's fields as required. You could also user the sort method to sort the customobject list based on a field in either descending or ascending order and then print the CO fields of required CO record using the array index.
#set( $sortedList = $sorter.sort($customObjList,"updatedAt:desc") )
4. The most recently updated custom object is stored at the top (i.e., the 0th index). A lot of people have a misconception that CO records are sorted based on created date, but actually, records are sorted based on the updated At date in descending order. If you want to pull multiple records' fields you can either sort the CO and query it using the array indexing or loop through the entire CO list and check whether the CO record in the loop iteration is the one that you wish to print the data for using #if condition.
#foreach( $item in $customerProfilesList)
${item.field1}<br/>
${item.field2}<br/>
${item.field3}
##..and so on
#end
Oh wow, that makes SO much more sense - I apparently misconstrued the $item as a placeholder for the field name and NOT the actual use it should be.
One more question if you have time - How would you approach pulling multiple values from a single record?
Like if I have 3 total records, but I want to pull fields from each in conjunction like:
Record A |
Field Value A1 |
Field Value A2 |
Field Value A3 |
Record B |
Field Value B1 |
Field Value B2 |
Field Value B3 |
I understand the foreach can loop through the array on a field basis, but is there a way to basically isolate a complete record (like the screencap I posted) and pull values from that single record?
Maybe I'm dumb but is that what the .get(0) would do? Is that looking on the record level? So if I do
$item.get(0).fieldA
$item.get(0).fieldB
$item.get(0).fieldC
$item.get(1).fieldA
$item.get(1).fieldB
$item.get(1).fieldC
This would pull each field on the record level?
I understand the foreach can loop through the array on a field basis, but is there a way to basically isolate a complete record (like the screencap I posted) and pull values from that single record?
Maybe I'm dumb but is that what the .get(0) would do? Is that looking on the record level? So if I do$item.get(0).fieldA $item.get(0).fieldB $item.get(0).fieldC $item.get(1).fieldA $item.get(1).fieldB $item.get(1).fieldC
This would pull each field on the record level?
If you're pulling out the records from the list (i.e., one or multiple CO records), then you could use the index to get the correct CO record using indexes -
The below will return fieldA, fieldB, and fieldC from the first CO record stored in the list (by default CO records are stored by last updated by)
$customerProfilesList.get(0).fieldA
$customerProfilesList.get(0).fieldB
$customerProfilesList.get(0).fieldC
The below will return fieldA, fieldB, and fieldC from the second CO record stored in the list
$customerProfilesList.get(1).fieldA
$customerProfilesList.get(1).fieldB
$customerProfilesList.get(1).fieldC
You should technically use the looping construct instead of quering the random records apart from the first record of the sorted list in most cases.
One more question if you have time - How would you approach pulling multiple values from a single record?
Like if I have 3 total records, but I want to pull fields from each in conjunction like:
Record A Field Value A1 Field Value A2 Field Value A3
Record B Field Value B1 Field Value B2 Field Value B3
When you're looping through the list, in each iteration of the loop, you'd only have access to one CO record (i.e., in the above example, in the first iteration, RecordA would be available in the $item variable, in the next iteration, RecordB would be available in the $item and so on..), so you need not use the indexes as you had to while accessing data directly from the customerProfilesList, you can directly reference the field from the CO record from the loop:
$item.fieldA
$item.fieldB
$item.fieldc
I hope this answers your question.
When you're looping through the list, in each iteration of the loop, you'd only have access to one CO record (i.e., in the above example, in the first iteration, RecordA would be available in the $item variable, in the next iteration, RecordB would be available in the $item and so on..), so you need not use the indexes as you had to while accessing data directly from the customerProfilesList, you can directly reference the field from the CO record from the loop:
$item.fieldA
$item.fieldB
$item.fieldc
I hope this answers your question.
Sort of? In the above to me it reads like you're saying that if I was looking to pull from multiple records I would do something like this:
<table>
</tbody>
<tr>
<td>This Pulls Record A</td>
</tr>
<tr>
<td>
#foreach ($item in $customerProfilesList )
<p>$item.memberName</p>
<p>$item.memberNumber</p>
#end
</td>
</tr>
<tr>
<td>This Pulls Record B</td>
</tr>
<tr>
<td>
#foreach ($item in $customerProfilesList )
<p>$item.memberName</p>
<p>$item.memberNumber</p>
#end
</td>
</tr>
</tbody>
</table>
So each loop is pulling from one record?
Semi-related but if I have an unknown number of potential records to loop through and potentially display values, what is the best way to do that? Obviously the array .get(0) method would not work because if there's more values then indicated in the script.
Is there a way to run a #foreach that loops through all available records AND prints the values out if they coorespond? Like a single version of the above? Or maybe that's what you were saying?
I'm sorry for the questions, I'm trying to learn this as we implement so it's a bit overwhelming 🙂
I’m going to give you a rule: if you’re even contemplating using the expression list.get(1) in your code, you’re doing something wrong.
There’s no reasonable case for directly seeking the second item in a list. The first item (get(0)), yes: that may be the earliest or latest item in a sorted list, which may have true relevance. The second item, no. If you find yourself contemplating that, you should be using #foreach.
Sort of? In the above to me it reads like you're saying that if I was looking to pull from multiple records I would do something like this:<table> </tbody> <tr> <td>This Pulls Record A</td> </tr> <tr> <td> #foreach ($item in $customerProfilesList ) <p>$item.memberName</p> <p>$item.memberNumber</p> #end </td> </tr> <tr> <td>This Pulls Record B</td> </tr> <tr> <td> #foreach ($item in $customerProfilesList ) <p>$item.memberName</p> <p>$item.memberNumber</p> #end </td> </tr> </tbody> </table>
So each loop is pulling from one record?
No, a loop is over the entire List, by definition.
Inside a loop, the loop variable ($item in this case) points to one item in the list. Each time the loop iterates (or, well, loops) $item is set to the next item in the list.
Lists are zero-based, so the 1st item in humanspeak the 0-th item in code.
If you loop again, the loop starts from item 0 again.
So the code you have above is just going to print the memberName and memberNumber property of each record, twice.
Okay got it, that makes total sense.
How would you recommend going about if I need to pull related records in conjunction with each other?
For instance, we have a Loans object that details out Loans (obviously) - so there might be 20 fields related to one particular Loan.
I get that #foreach reiterates through the whole array of records, but I'm still stuck on how to specifically say:
Record A of the CO |
Field 1 from Record A |
Field 2 from Record A |
Field 3 from Record A |
And then potentially do the same for Records B, C, etc. In this case each Loan would have a particular Loan ID that indicates the specific record, so would it be a matter of using #foreach Loan ID and then printing the particular fields wanted?
You could use the below construct to print fields:
#foreach( $item in $customerProfilesList)
${item.loanID}<br/>
${item.loanGivenTo}<br/>
${item.loanAmount}
#end
You could also add conditionals in the loop in case you'd like to print fields of the CO record only if certain condition matches, e.g., display fields only if loanId of the CO record equals "ABC":
#foreach( $item in $customerProfilesList)
#if($item.loanID.equals("ABC"))
${item.loanID}<br/>
${item.loanGivenTo}<br/>
${item.loanAmount}
#end
#end
You can also use all forms of conditionals (#if, #if #else, and #if #else if #else) and could also use the AND / OR operators (&& / ||) for your conditions.
Is there a way to reference back to what a previous token found in order to retain the record consistency?
We have a campaign that basically would run like this:
Email 1: Send to CO Record when "Membership Opening Date" field within past 48 hours
Email 2: 2 days later, send email with field info ONLY to recipient of Email 1, referencing Email 1 CO Record
For tokens in email 2 is there any way to reference back to the exact CO record used in Email 1? Or would it be more-so filtering down to get the correct match?
Again, apologies for all the questions - I just feel like our dataset is very convoluted in that we could have multiple object records under the same email, with very similar field entries and very little distinct between them outside of maybe dates and I don't think that is a very great way to filter down.
If you use a trigger campaign with trigger (Added to <CustomObjectName>), you could reference the same CO using the $TriggerObject in both emails. You could define constraints on the CO fields in case you don't want to let all CO additions qualify for the campaign flow.
The flow could be something like the below:
You could identify CO uniquely using the CO record's dedupe field, but there's no way you could write the dedupe field data of the CO record picked by Marketo during the email1 send to a lead field to reference later (so as to ensure you pick the exact same CO record in your next email as well).
Personally speaking, I'm not a fan of creating campaign flows with the first step as a big Wait step, as it depriortizes the campaign execution (granted, you could override the priority, but still!). Are you worried that a differenct CO record would be picked up in the email 2 send using the exact same conditions as the email 1 send? You could probably seal that gap using the createdAt field maybe (safely assuming that there's pretty neglible/almost no chance that there would be more than 1 CO record with same createdAt and other field values used in velocity).
Looking forward to other creative ideas to pull this off. 🙂