Result reference: @body('Select_Needed_Columns') — returns a direct array of reshaped objects.
Use Select before looping or filtering to reduce payload size and simplify
downstream expressions. Works on any array — SP results, HTTP responses, variables.
Tips:
Single-to-array coercion: When an API returns a single object but you need
Select (which requires an array), wrap it: @array(body('Get_Employee')?['data']).
The output is a 1-element array — access results via ?[0]?['field'].
Null-normalize optional fields: Use @if(empty(item()?['field']), null, item()?['field'])
on every optional field to normalize empty strings, missing properties, and empty
objects to explicit null. Ensures consistent downstream @equals(..., @null) checks.
Flatten nested objects: Project nested properties into flat fields:
Filters an array to items matching a condition. Use the action form (not the filter()
expression) for complex multi-condition logic — it’s clearer and easier to maintain.
Result reference: @body('Filter_Active_Subscriptions') — direct filtered array.
Tip: run multiple Filter Array actions on the same source array to create
named buckets (e.g. active, being-canceled, fully-canceled), then use
coalesce(first(body('Filter_A')), first(body('Filter_B')), ...) to pick
the highest-priority match without any loops.
Converts an array of objects into a CSV-formatted string — no connector call, no code.
Use after a Select or Filter Array to export data or pass it to a file-write action.
Without columns, headers are taken from the object property names in the source array.
With columns, you control header names and column order explicitly.
The output is a raw string. Write it to a file with CreateFile or UpdateFile
(set body to @body('Create_CSV')), or store in a variable with SetVariable.
If source data came from Power BI’s ExecuteDatasetQuery, column names will be
wrapped in square brackets (e.g. [Amount]). Strip them before writing:
@replace(replace(body('Create_CSV'),'[',''),']','')
range(0, N) produces an integer sequence [0, 1, 2, …, N-1]. Pipe it through
a Select action to generate date series, index grids, or any computed array
without a loop:
json
// Generate 14 consecutive dates starting from a base date"Generate_Date_Series": { "type": "Select", "inputs": { "from": "@range(0, 14)", "select": "@addDays(outputs('Base_Date'), item(), 'yyyy-MM-dd')" }}
The json(concat('{', join(...), '}')) pattern works for string values. For numeric
or boolean values, omit the inner escaped quotes around the value portion.
Keys must be unique — duplicate keys silently overwrite earlier ones.
This replaces deeply nested if(equals(key,'A'),'X', if(equals(key,'B'),'Y', ...)) chains.
When you need to find records where any of several fields has changed, run one
Filter Array per field and union() the results. This avoids a complex
multi-condition filter and produces a clean deduplicated set:
Reference: @outputs('All_Changed') — deduplicated array of rows where anything changed.
union() deduplicates by object identity, so a row that changed in both fields
appears once. Add more Filter_*_Changed inputs to union() as needed:
@union(body('F1'), body('F2'), body('F3'))
Before running expensive processing on a file or blob, compare its current content
to a stored baseline. Skip entirely if nothing has changed — makes sync flows
idempotent and safe to re-run or schedule aggressively.
Store the baseline as a file in SharePoint or blob storage — base64()-encode the
live content before comparing so binary and text files are handled uniformly.
Write the new baseline before processing so a re-run after a partial failure
does not re-process the same file again.
When syncing a source collection into a destination (e.g. API response → SharePoint list,
CSV → database), avoid nested Apply to each loops to find changed records.
Instead, project flat key arrays and use contains() to perform set operations —
zero nested loops, and the final loop only touches changed items.
Insert/update/delete sync recipe:
Select_Dest_Keys from destination rows.
Filter_To_Insert: source rows whose key is not in destination keys.
Filter_Already_Exists: source rows whose key is in destination keys.
For each compared field, run Filter_<Field>_Changed; combine them with
union() into Union_Changed.
Select_Changed_Keys from Union_Changed, then filter destination rows to
only those keys before updating.
Select_Source_Keys, then Filter_To_Delete destination rows whose key is
not in source keys.
This changes O(n x m) nested loops to O(n + m) set operations and helps avoid
Power Automate’s 100k-action run limit.
Access fields on the matched row: @outputs('Get_First_Match')?['FieldName']
Use this instead of Apply to each when you only need one matching record.
first() on an empty array returns null; empty() is for arrays/strings,
not scalars — using it on a first() result causes a runtime error.
When to use: Calling Microsoft Graph, Azure Resource Manager, or any
Azure AD-protected API from a flow without a premium connector.
The authentication block handles the entire OAuth client-credentials flow
transparently — no manual token acquisition step needed.
ConsistencyLevel: eventual is required for Graph $search queries.
Without it, $search returns 400.
For PATCH/PUT writes, the same authentication block works — just change
method and add a body.
⚠️ Never hardcode secret inline. Use @parameters('graphClientSecret')
and declare it in the flow’s parameters block (type securestring). This
prevents the secret from appearing in run history or being readable via
get_live_flow. Declare the parameter like:
PowerApps / low-code caller pattern: always return statusCode: 200 with a
status field in the body ("success" / "error"). PowerApps HTTP actions
do not handle non-2xx responses gracefully — the caller should inspect
body.status rather than the HTTP status code.
Use multiple Response actions — one per branch — so each path returns
an appropriate message. Only one will execute per run.
Power Automate supports parent→child orchestration by calling a child flow’s
HTTP trigger URL directly. The parent sends an HTTP POST and blocks until the
child returns a Response action. The child flow uses a manual (Request) trigger.
retryPolicy: none — critical on the parent’s HTTP call. Without it, a child
flow timeout triggers retries, spawning duplicate child runs.
DisableAsyncPattern — prevents the parent from treating a 202 Accepted as
completion. The parent will block until the child sends its Response.
transferMode: Chunked — enable when passing large arrays (>100 KB) to the child;
avoids request-size limits.
limit.timeout: PT2H — raise the default 2-minute HTTP timeout for long-running
children. Max is PT24H.
The child flow’s trigger URL contains a SAS token (sig=...) that authenticates
the call. Copy it from the child flow’s trigger properties panel. The URL changes
if the trigger is deleted and re-created.
Result: @body('Filter_Empty_Rows') — array of objects with header names as keys.
Notes: Detect_Line_Ending handles CRLF/LF/CR. Dynamic keys in Select require
@{...} interpolation. This simple pattern does not safely parse quoted fields
with embedded delimiters; for those, use a dedicated parser or custom action.
Converts a timestamp between timezones with no API call or connector licence cost.
Format string "g" produces short locale date+time (M/d/yyyy h:mm tt).
Result reference: @body('Convert_to_Local_Time') — notoutputs(), unlike most actions.
Common formatString values: "g" (short), "f" (full), "yyyy-MM-dd", "HH:mm"
Common timezone strings: "UTC", "AUS Eastern Standard Time", "Taipei Standard Time",
"Singapore Standard Time", "GMT Standard Time"
This is type: Expression, kind: ConvertTimeZone — a built-in Logic Apps action,
not a connector. No connection reference needed. Reference the output via
body() (not outputs()), otherwise the expression returns null.