Solved

How to parse JSON array

  • 22 November 2023
  • 17 replies
  • 375 views

Badge +1

I have a workflow which makes a web request to our MDM’s API. The MDM returns back a JSON list.

[
{
"device_id": "11111111-4498-4a16-b495-dd6ced251606",
"device_name": "C01234567890-user1",
"model": "MacBook Pro (16-inch, 2019)",
"serial_number": "C01234567890",
"platform": "Mac",
"os_version": "14.0",
"supplemental_build_version": "23A344",
"supplemental_os_version_extra": "",
"last_check_in": "2023-11-07T15:03:37.309525Z",
"user": {
"email": "user1@nuna.com",
"name": "User 1",
"id": 5,
"is_archived": false
},
"asset_tag": "10000809",
"blueprint_id": "11111111-4a1d-4d11-8cf3-53ab707b6336",
"mdm_enabled": true,
"agent_installed": true,
"is_missing": false,
"is_removed": false,
"agent_version": "4.2.9 (4570)",
"first_enrollment": "2021-05-21 16:36:45.787997+00:00",
"last_enrollment": "2023-10-30 03:46:59.102587+00:00",
"blueprint_name": "IT - Sonoma",
"lost_mode_status": ""
},
{
"device_id": "11111111-caea-4d25-a7b4-8e5d1d392530",
"device_name": "987654321-user1",
"model": "MacBook Pro (14-inch, 2021)",
"serial_number": "987654321",
"platform": "Mac",
"os_version": "13.6",
"supplemental_build_version": "22G120",
"supplemental_os_version_extra": "",
"last_check_in": "2023-11-22T04:47:35.872763Z",
"user": {
"email": "user1@nuna.com",
"name": "User 1",
"id": 5,
"is_archived": false
},
"asset_tag": "10001000",
"blueprint_id": "11111111-8127-475f-8a1c-0a64122b1458",
"mdm_enabled": true,
"agent_installed": true,
"is_missing": false,
"is_removed": false,
"agent_version": "4.2.10 (4592)",
"first_enrollment": "2022-02-17 21:49:56.252660+00:00",
"last_enrollment": "2022-10-14 15:41:09.638548+00:00",
"blueprint_name": "IT 2023 (Current)",
"lost_mode_status": ""
}
]

I want to specifically get the device_id from the object where asset_tag = 10001000.

Is there any way to do this purely in workflow automation?

I would normally do this with a simple FOR loop, but there doesn’t seem to be anything like that in the workflow options.

icon

Best answer by DanielRuff 27 November 2023, 15:09

View original

17 replies

Userlevel 3
Badge +5

Hi @alan_13300 

do you always search for this specific asset tag or can this tag change? 

 

1st suggestion:

I don’t know the MDM web request/app/integration but can you use queries to just return the specific asset? something like searching for assets within the asset management api. This should just return the keys/values you want and you can then use this in a parser node.

 

2nd suggestion:

If that doesnt work and you get multiple values as response body - then you need some complex logic:

  • You could use the expression builder to get the position where you find the string “10001000”. Function indexOf.
  • Afterwards you could search backwards with the function lastindexof() to see when “device_id” last occured within that string
  • Then check for the position of the next “,” and isolate this with an expression to get the full device id

We did similar things with a html email to isolate the requesters email within a long text. If you use the response from that web request as simple textinput you can use my logic above with some expression builders to isolate the device id.

Hope that helps.

Userlevel 7
Badge +13

I have a workflow which makes a web request to our MDM’s API. The MDM returns back a JSON list.

[
{
"device_id": "11111111-4498-4a16-b495-dd6ced251606",
"device_name": "C01234567890-user1",
"model": "MacBook Pro (16-inch, 2019)",
"serial_number": "C01234567890",
"platform": "Mac",
"os_version": "14.0",
"supplemental_build_version": "23A344",
"supplemental_os_version_extra": "",
"last_check_in": "2023-11-07T15:03:37.309525Z",
"user": {
"email": "user1@nuna.com",
"name": "User 1",
"id": 5,
"is_archived": false
},
"asset_tag": "10000809",
"blueprint_id": "11111111-4a1d-4d11-8cf3-53ab707b6336",
"mdm_enabled": true,
"agent_installed": true,
"is_missing": false,
"is_removed": false,
"agent_version": "4.2.9 (4570)",
"first_enrollment": "2021-05-21 16:36:45.787997+00:00",
"last_enrollment": "2023-10-30 03:46:59.102587+00:00",
"blueprint_name": "IT - Sonoma",
"lost_mode_status": ""
},
{
"device_id": "11111111-caea-4d25-a7b4-8e5d1d392530",
"device_name": "987654321-user1",
"model": "MacBook Pro (14-inch, 2021)",
"serial_number": "987654321",
"platform": "Mac",
"os_version": "13.6",
"supplemental_build_version": "22G120",
"supplemental_os_version_extra": "",
"last_check_in": "2023-11-22T04:47:35.872763Z",
"user": {
"email": "user1@nuna.com",
"name": "User 1",
"id": 5,
"is_archived": false
},
"asset_tag": "10001000",
"blueprint_id": "11111111-8127-475f-8a1c-0a64122b1458",
"mdm_enabled": true,
"agent_installed": true,
"is_missing": false,
"is_removed": false,
"agent_version": "4.2.10 (4592)",
"first_enrollment": "2022-02-17 21:49:56.252660+00:00",
"last_enrollment": "2022-10-14 15:41:09.638548+00:00",
"blueprint_name": "IT 2023 (Current)",
"lost_mode_status": ""
}
]

I want to specifically get the device_id from the object where asset_tag = 10001000.

Is there any way to do this purely in workflow automation?

I would normally do this with a simple FOR loop, but there doesn’t seem to be anything like that in the workflow options.

You can do it static using the JSON parser node and JSON path expressions. 

JSON Parser Node : Freshservice

Writing JSONPath Expressions - Hevo Data

 

 

There loop function coming, when and in what form I don’t know.

Badge +1

I think I understand how the JSONPath expressions work -- I managed to use https://jsonpath.com/ to refine my expression, but I’m stumbling on how to apply those expressions in the JSON Parser module.

am I putting this in the right place? is this how it should be formatted?

 

I’m trying to achieve this expression, but I don’t know where to put it.

$[?(@.asset_tag==`{{asset_tag_placeholder}}`)].device_id

 

Badge +1

Hi @alan_13300 

do you always search for this specific asset tag or can this tag change? 

It will change with every request.

1st suggestion:

[…] just return the specific asset?

In this case, yes, I think our MDM (thankfully) does allow for filtering on the server side, but I will definitely encounter future scenarios where the API I’m dealing with will won’t offer the ability to filter. I was hoping to use this as an example to learn how to do it “the FreshService way”. 😅

There are no good visual examples of doing complex JSONPath queries in the FS docs (at least that I can find).

 

In workflow automation, achieving the desired outcome typically involves manipulating data through available actions. While specific workflows may vary, one potential approach is to use a combination of "Filter" and "Get Item from List" actions. First, apply a filter to the JSON list based on the condition where "asset_tag" equals 10001000. Next, use the "Get Item from List" action to extract the "device_id" from the filtered result. This way, you can isolate the object with the required asset tag and retrieve the associated device ID. While workflow automation tools may have distinct functionalities, a combination of filtering and extracting actions can often emulate a loop-like behavior for targeted data retrieval.

Userlevel 3
Badge +5

I think I understand how the JSONPath expressions work -- I managed to use https://jsonpath.com/ to refine my expression, but I’m stumbling on how to apply those expressions in the JSON Parser module.

am I putting this in the right place? is this how it should be formatted?

 

I’m trying to achieve this expression, but I don’t know where to put it.

$[?(@.asset_tag==`{{asset_tag_placeholder}}`)].device_id

 

 

Your parser looks kinda weird. You can only use {{W2.response_body}} instead and use the serial number within the web request as a filter. The web request should just return a single object and not a full list so you have to edit W2. Can you share web request W2 with us?

The search term in my post above is from our mac deplyoment. We search the asset database in freshservice for the serial number of the mac device and then apply the asset name automatically to the mac. So quite similar.

Your other case: If your API doesnt allow for filtering this gets really complex. Not impossible though but really hard to handle. I’m talking of pagination. You get 30 assets/tickets or whatever back from your API call but the asset/ticket youre searching is on page 10 and not on the first one.

Userlevel 7
Badge +13

I think I understand how the JSONPath expressions work -- I managed to use https://jsonpath.com/ to refine my expression, but I’m stumbling on how to apply those expressions in the JSON Parser module.

am I putting this in the right place? is this how it should be formatted?

 

I’m trying to achieve this expression, but I don’t know where to put it.

$[?(@.asset_tag==`{{asset_tag_placeholder}}`)].device_id

 

You can’t use placeholders in path as far as I understand but let me know if that works. 

You need to change the path on the right side. 

 

Badge +1

I think I understand how the JSONPath expressions work -- I managed to use https://jsonpath.com/ to refine my expression, but I’m stumbling on how to apply those expressions in the JSON Parser module.

am I putting this in the right place? is this how it should be formatted?

 

I’m trying to achieve this expression, but I don’t know where to put it.

$[?(@.asset_tag==`{{asset_tag_placeholder}}`)].device_id

 

 

Your parser looks kinda weird. You can only use {{W2.response_body}} instead and use the serial number within the web request as a filter. The web request should just return a single object and not a full list so you have to edit W2. Can you share web request W2 with us?

The search term in my post above is from our mac deplyoment. We search the asset database in freshservice for the serial number of the mac device and then apply the asset name automatically to the mac. So quite similar.

Your other case: If your API doesnt allow for filtering this gets really complex. Not impossible though but really hard to handle. I’m talking of pagination. You get 30 assets/tickets or whatever back from your API call but the asset/ticket youre searching is on page 10 and not on the first one.

I agree, I was expecting the response to be a single JSON object, with a list inside it… but no, it returns a list of objects.

https://api-docs.kandji.io/#78209960-31a7-4e3b-a2c0-95c7e65bb5f9

 

Here’s the web request...

 

Userlevel 3
Badge +5

@alan_13300 

I checked the API documentation from kandji. Is there a specific reason why you search for assets via email instead of using parameter for serial number?

 

Instead you could search for that serial number (e.g. entered via service request lookup field for assets) and your web request then just returns one single object so you can the use the parser (for the same value and not the 30th value depending on the position the returned asset is in) and extract the device id for that serial number to use its in any other web request or automation.

Parser node then only contains response boday wothout any params in the source.

Badge +1

@alan_13300

I checked the API documentation from kandji. Is there a specific reason why you search for assets via email instead of using parameter for serial number?

 

Instead you could search for that serial number (e.g. entered via service request lookup field for assets) and your web request then just returns one single object so you can the use the parser (for the same value and not the 30th value depending on the position the returned asset is in) and extract the device id for that serial number to use its in any other web request or automation.

Parser node then only contains response boday wothout any params in the source.

 

Sorry, I didn’t mean for this to become a discussion of the Kandji API -- I’m aware that we can filter for a specific device via serial number. That’s actually how we’ve worked around this particular problem.

 

However, my question still stands -- in the event that I am dealing with an API that doesn’t offer the ability to filter down to a single item in a list, and I’m stuck with a scenario where I have a list of items… I want to know the best way to filter that list down to a specific item.

 

It seems the answer is some combination of JSON Parser + Expression, since the concept of a “for loop” is not an option (yet).

Userlevel 3
Badge +5

@alan_13300 

Yes I’m facing the same issue in some other scenarios. But they are planning to implement looping, I’ve seen some topics in the forum about that. No ETA as of now.

Badge +1

@alan_13300

Yes I’m facing the same issue in some other scenarios. But they are planning to implement looping, I’ve seen some topics in the forum about that. No ETA as of now.

It seems like for loops are built in to Fluid templates, I wonder why they can’t just enable them?

🤷‍♂️

 

Anyway, thanks for your advice!

Userlevel 5
Badge +9

have you ever found an answer how to user placeholders in JSON path expressions?

Like your example:

$[?(@.asset_tag==`{{asset_tag_placeholder}}`)].device_id

I have the same requirement. 

Userlevel 7
Badge +13

have you ever found an answer how to user placeholders in JSON path expressions?

Like your example:

$[?(@.asset_tag==`{{asset_tag_placeholder}}`)].device_id

I have the same requirement. 

Never checked with the support but I haven’t gotten it to work. It would be good to have. 

Userlevel 5
Badge +9

Ok I solved it by sending the whole array of objects into the PowerShell App and do my filtering there:

$Json = '{{P1.root.groups.groups_object}}'

$Object = $Json | ConvertFrom-json

$Object | Where-Object groupId -EQ '{{R1.adobe_admin_groupid}}' | ConvertTo-Json

{{R1.adobe_admin_groupid}} is filled form a Reader node with all the groupIDs in it in that case

Userlevel 7
Badge +16

Thanks @msconfig87, this is really useful. Totally overlooked the ability to use the powershell node to generate the result needed. Brilliant!

Userlevel 7
Badge +13

Ok I solved it by sending the whole array of objects into the PowerShell App and do my filtering there:

$Json = '{{P1.root.groups.groups_object}}' $Object = $Json | ConvertFrom-json $Object | Where-Object groupId -EQ '{{R1.adobe_admin_groupid}}' | ConvertTo-Json

{{R1.adobe_admin_groupid}} is filled form a Reader node with all the groupIDs in it in that case

Thanks, ya that is a workaround :) 

Reply