Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Grow your Fabric skills and prepare for the DP-600 certification exam by completing the latest Microsoft Fabric challenge.

Reply
eddiehartman
Frequent Visitor

Struggling with the cyclic reference error

I have coded the following function, which recursively calls itself in order to retrieve the full list of users from a REST API:

 

let
    GetUserData = (startFrom as number, uCount as number, result) => 
    let
        userCount = if uCount <> null then
                        uCount
                    else
                        Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/count", 
                                        [Headers=[Accept="application/vnd.api+json",#"X-Authorization-Key"= Text.From(#"PUSapikey")]])),
        userResult = Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/?From=" & Text.From(startFrom), 
                                        [Headers=[Accept="application/vnd.api+json",#"X-Authorization-Key"= Text.From(#"PUSapikey")]])),

        // See if more need to be read
        combinedResult = List.Distinct(List.Combine(userResult, result)),
        startFrom = if userCount < List.Count(combinedResult) then List.Count(combinedResult) else null,

        #"Converted to Table" = Record.ToTable(combinedResult),
        #"Expanded Value" = Table.ExpandListColumn(#"Converted to Table", "Value"),
        #"Expanded Value1" = Table.ExpandRecordColumn(#"Expanded Value", "Value", {"links", "firstName", "lastName", "middleName", "fullName", "title", "location", "department", "notes", "isAnonymized", "isSuperuser", "role", "notificationScheme", "highlightNotifications", "flushNotifications", "accessKeyNonceId", "pictureId", "emailAddressId", "phonenumberId", "addressId", "companyId", "companyDepartmentId", "companyLocationId", "languageId", "credentialsId", "unavailable", "unavailableChangedById", "unavailableChangedByDate", "disabled", "importUniqueKey", "cf_1", "cf_2", "cf_3", "cf_4", "cf_5", "cf_6", "cf_7", "cf_8", "cf_9", "type", "id", "created", "modified", "createdById", "modifiedById"}, {"Value.links", "Value.firstName", "Value.lastName", "Value.middleName", "Value.fullName", "Value.title", "Value.location", "Value.department", "Value.notes", "Value.isAnonymized", "Value.isSuperuser", "Value.role", "Value.notificationScheme", "Value.highlightNotifications", "Value.flushNotifications", "Value.accessKeyNonceId", "Value.pictureId", "Value.emailAddressId", "Value.phonenumberId", "Value.addressId", "Value.companyId", "Value.companyDepartmentId", "Value.companyLocationId", "Value.languageId", "Value.credentialsId", "Value.unavailable", "Value.unavailableChangedById", "Value.unavailableChangedByDate", "Value.disabled", "Value.importUniqueKey", "Value.cf_1", "Value.cf_2", "Value.cf_3", "Value.cf_4", "Value.cf_5", "Value.cf_6", "Value.cf_7", "Value.cf_8", "Value.cf_9", "Value.type", "Value.id", "Value.created", "Value.modified", "Value.createdById", "Value.modifiedById"}),
        #"Removed Columns" = Table.RemoveColumns(#"Expanded Value1",{"Name"})
    in
        if startFrom <> null then
            @GetUserData(startFrom, userCount, combinedResult)
        else
            #"Removed Columns"
in
    GetUserData

 

When I try to call the function, or invoke it from Power Query, I get the cyclic reference error. 

Could one of you PQ masters out there help me tackle this issue?

1 ACCEPTED SOLUTION

Your first steps are correct

 

let
    userCount = Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/count", 
        [
            Headers=[
                Accept="application/vnd.api+json",
                #"X-Authorization-Key"= Text.From(#"PUSapikey")
            ]
        ]))[count],
    pages = Number.RoundUp(userCount / 500),

 

but then you veer off track. Next step is to create a list with all the URLs you need to fetch the data chunks.

 

since you already know the number of pages you need there is not really a reason to use list.generate any more. A simple 

 

{1..pages}  

 

is enough.  Convert that to a table, add your GetUserData function as a custom column, and combine the output.

View solution in original post

5 REPLIES 5
eddiehartman
Frequent Visitor

Ok, so I am trying List.Generate, but for some reason my resulting list seems endless. The function GetUserData performs a web call to return a list of Users (one page = 500 items). So I want to call this function with multiple pages. However, as I said, it seems not to stop.

 

Perhaps my lack of understanding of variable scope - for example, that I must defined pageNumber outside the List.Generate() construct, otherwise I get an error. Any advice and enlightment on scoping is greatly appreciated!

 

let
    userCount = Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/count", 
        [
            Headers=[
                Accept="application/vnd.api+json",
                #"X-Authorization-Key"= Text.From(#"PUSapikey")
            ]
        ]))[count],
    pages = Number.RoundUp(userCount / 500),
    pageCount = 0,
    Result = {},
   
    totalUserList = List.Generate(
        () => [
            pageCount = 1,
            Result = GetUserData(pageCount)
        ],
        each pageCount <= pages,
        each [
            pageCount = pageCount + 1,
            Result = GetUserData(pageCount)
        ]
    ),
    
    #"Converted to Table" = Table.FromList(totalUserList, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"Result"}, {"Column1.Result"}),
    #"Column1 Result1" = #"Expanded Column1"{0}[Column1.Result],
    #"Converted to Table1" = Table.FromList(#"Column1 Result1", Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Expanded Column2" = Table.ExpandRecordColumn(#"Converted to Table1", "Column1", {"links", "firstName", "lastName", "middleName", "fullName", "title", "location", "department", "notes", "isAnonymized", "isSuperuser", "role", "notificationScheme", "highlightNotifications", "flushNotifications", "accessKeyNonceId", "pictureId", "emailAddressId", "phonenumberId", "addressId", "companyId", "companyDepartmentId", "companyLocationId", "languageId", "credentialsId", "unavailable", "unavailableChangedById", "unavailableChangedByDate", "disabled", "importUniqueKey", "cf_1", "cf_2", "cf_3", "cf_4", "cf_5", "cf_6", "cf_7", "cf_8", "cf_9", "type", "id", "created", "modified", "createdById", "modifiedById"}, {"links", "firstName", "lastName", "middleName", "fullName", "title", "location", "department", "notes", "isAnonymized", "isSuperuser", "role", "notificationScheme", "highlightNotifications", "flushNotifications", "accessKeyNonceId", "pictureId", "emailAddressId", "phonenumberId", "addressId", "companyId", "companyDepartmentId", "companyLocationId", "languageId", "credentialsId", "unavailable", "unavailableChangedById", "unavailableChangedByDate", "disabled", "importUniqueKey", "cf_1", "cf_2", "cf_3", "cf_4", "cf_5", "cf_6", "cf_7", "cf_8", "cf_9", "type", "id", "created", "modified", "createdById", "modifiedById"}),
    #"Removed Columns" = Table.RemoveColumns(#"Expanded Column2",{"links"})

in
    #"Removed Columns"

Your first steps are correct

 

let
    userCount = Json.Document(Web.Contents("https://storfolloikt.pureservice.com/agent/api/user/count", 
        [
            Headers=[
                Accept="application/vnd.api+json",
                #"X-Authorization-Key"= Text.From(#"PUSapikey")
            ]
        ]))[count],
    pages = Number.RoundUp(userCount / 500),

 

but then you veer off track. Next step is to create a list with all the URLs you need to fetch the data chunks.

 

since you already know the number of pages you need there is not really a reason to use list.generate any more. A simple 

 

{1..pages}  

 

is enough.  Convert that to a table, add your GetUserData function as a custom column, and combine the output.

Brilliant!! Thanks so much for your help! I keep forgetting to use the powerful features provided in the UI. 

eddiehartman
Frequent Visitor

That looks promising. Thanks for the tip! However, I have seen a lot of examples with recursion. How do you get this to work without triggering a cyclic reference error?

lbendlin
Super User
Super User

- don't use recursive functions for this. Use List.Generate instead.

- try not to do any transforms until after you combined the data.

Helpful resources

Announcements
RTI Forums Carousel3

New forum boards available in Real-Time Intelligence.

Ask questions in Eventhouse and KQL, Eventstream, and Reflex.

MayPowerBICarousel1

Power BI Monthly Update - May 2024

Check out the May 2024 Power BI update to learn about new features.

Europe Fabric Conference

Europe’s largest Microsoft Fabric Community Conference

Join the community in Stockholm for expert Microsoft Fabric learning including a very exciting keynote from Arun Ulag, Corporate Vice President, Azure Data.

Top Solution Authors
Top Kudoed Authors