Working with nested arrays

Options

I've come across a strange issue. I have a nested json that I'm using the Arrays function under data manipulation to pull out information using Find All.

Works great for first level, but when I include a filter for the second level using dot notation the error I'm getting is it can't find the variable.

The data structure is like below for one record

match:[{N: 1, B: 2, C:{a: 1, b: [{x:3,y:2},{x:2, y:4}]},},…] (with the 3 dots denoting other records in the array.

So when I use dot notation to filter below

$this.C.b.y = 2 to find the objects that contain 2, I get the error "Unable to locate var"

Comments

  • Pawel Magdanski
    Pawel Magdanski Member ✭✭✭
    Options

    Hi,

    Can you show how it looks like in Xano function stack? Both the data structure and the debugger?

  • MattLaro
    MattLaro Member ✭✭
    edited June 2023
    Options

    There's two things to consider here.

    The dotation form in Xano has to be used carefully, as it requires all objects in you array to have the existing path. As soon as there is ONE object that has not the given path, it will give you the "Unable to locate var" error.

    Consider this json as an example :

    [{"PA":{"CA":"Hello","CB":"World","CC":[{"GCA":"Hi","GCB":"Marcie"}]},"PB":{"CA":"Goodbye","CB":"Universe"},"PC":{"CB":"John"}},{"PA":{"CA":"Orange","CB":"Banana"},"PB":{"CA":"Car","CB":"Truck"},"PC":{"CB":"John"}}]

    (You can format it to see the result)

    If we use the dotation mark here to find $this.PA.CC.GCA, it will raise the var error, because only the first element of this array has that path.

    The solution here is to use the GET filter, which will return null if the path doesn't exist and bypass the fact that the path doesn't exist in all objects.

    Super ! No more var error…. however, we have a second problem here. We got no results… but we do have a $this.PA.CC.GCA that has the value "Hi" in our nested array.

    This is because it is not represented in the same way in Xano as we would believe.

    Let's try out just extracting the value from the Object first :

    So here, we see it returns two results, because in the first array level, there is two objects. However, only one of them has the path PA.CC.GCA, hence why the second one returns null (the default value).

    For this sole reason, you'll have to represent the searched object as a value in an array. I know it sounds weird, but check this out :

    This, of course, is an oversimplified example that will probably not suit your data structure. Let's say I add another GCA, GCB object in the first object of the Array explored by Find All, it won't yield any results anymore unless I include ALL values in the nested array on the right side of the equation. Nested arrays may get complicated very quickly!

    There's always a way of course. Here's what I've done to make the Find all find only objects having a GCA = Bonjour in my nested array :

    some is an Array filter that will return either true or false if it finds at least one element that matches the provided lambda function.

    The second condition is because the some filter will return true when the path does not exist for some weird reason, so I also verify that the path exists.

    If it gets too complicated, perhaps consider using a For each to eliminate subnesting levels? :). Then you can issue a Find All directly on the subnested array.

  • enyarick
    enyarick Member
    Options

    This is amazing...I had suspected the need for the criteria to be an array but had no idea how to build the stack.

    And you were also able to cover filtering using a boolean.

    Let me attempt to unpack this and give a shout once successful.

    I was trying to avoid a loop because the data is coming from an api first and it feels like xano runs through all records with each function added to the stack even if you refer to a variable that reduces the number of iterations required.

  • MattLaro
    MattLaro Member ✭✭
    Options

    Alright! :) I'd suggest experimenting both ways. Even though for each runs through records individually, it could be more efficient anyway as context switching between JS lambda and Xano no-code may add some overhead latency. Perhaps not though!



  • enyarick
    enyarick Member
    Options

    Hey Matt! The first way worked like a charm. Much appreciated for your response.

    I should mention, I'm trying to wring some functionality from the free tier so that I get a good sense of what's doable on the paid tiers. This means looking at doing Lambda things without Lambda (also not very good with JS).

    Of course plugging in the array as the condition has me experimenting further with my data for things like

    • More than 1 item pushed into the array for an "or" type of result. This failed when I set input as an array and put any item (one or more)
    • Wildcard type of result. Here I used the greater than or equal to combined with a less than or equal to. Seems to return results that I'm currently comparing against raw data.

    Any ideas here?

    Xano seems pretty versatile but needs further exploring and experimenting.

  • enyarick
    enyarick Member
    Options

    Hi Pawel, I think Matt represented the data in a similar way to the way mine is structured on Xano.

    Sorry about the delay in responding.

    Let me know if you need further info. Thanks!

  • enyarick
    enyarick Member
    Options

    @MattLaro now also realizing that some results using the array push can be skipped due to different cases.

  • MattLaro
    MattLaro Member ✭✭
    Options

    @enyarick Ah ! I didn't realize Lambda was part of the paid tier :) I've been in the paid tier almost from day 1 .

    If Lambda is not available, then for simplicity's sake, even though it does not sound intuitive or efficient, I'd suggest you should probably opt for "For each" until you reach the desired subnested array and then Find all on that array. There are probably doable options without it with filters and conditions, but you'll be twisting arms and legs to a point it will be worst in efficiency than a simple For Each.

  • enyarick
    enyarick Member
    Options

    @MattLaro Thanks.

    Let me check out the For each.

    More testing with the push to array seems to allow "leakage" of items not meeting the criteria.

  • MattLaro
    MattLaro Member ✭✭
    Options

    @enyarick Interesting. Could you provide an example of leakage with an array with a push?

  • enyarick
    enyarick Member
    Options

    Tweaked your array a little as below.

    [{"CA":"Hello","CB":"World","CC":[{"GCA":"Hi","GCB":"Marcie"},{"GCA":"Run","GCB":"Fast"},{"GCA":"Not","GCB":"Here"}]},{"CA":"Note","CB":"This","CC":[{"GCA":"Hour","GCB":"Minus"},{"GCA":"Ten","GCB":"Marcie"}]},{"CA":"Hair","CB":"Done","CC":[{"GCA":"Good","GCB":"Now"}]}]

    When the stack with the Array push runs using an input to search for Marcie, I'm now getting no result. Quite odd.

  • MattLaro
    MattLaro Member ✭✭
    edited June 2023
    Options

    Yes indeed :), as now only ["Marcie","Fast","Here"], ["Minus","Marcie"] or ["Now"] on the right side of the equation would yield results :

    "Let's say I add another GCA, GCB object in the first object of the Array explored by Find All, it won't yield any results anymore unless I include ALL values in the nested array on the right side of the equation. Nested arrays may get complicated very quickly!"

    The push method on the right side of the equation was used as an example here to point out how Xano handle data, but would be clearly the wrong way to go for what you're trying to accomplish.

  • enyarick
    enyarick Member
    Options

    Gotcha!

    Also getting some interesting results with >= and <= which does two things

    1. Returns some of the results required without putting the entire array (They need to be in order on the right side to match up with the Array)
    2. Returns results not needed as long as they they start with a letter greater than in this case M (Marcie) and the operand is >= or one lower than M for the opposite.

    I'm trying to figure out how to use a For Each that returns the first level of JSON based on one of the nested levels i.e. the entire object where a nested object value meets the criteria.

  • enyarick
    enyarick Member
    Options

    I was able to do this with a For Each that also managed provide "contains" and deal with case insensitivity in the results.

    Xano FTW.

  • Liz Anaya
    Liz Anaya Member, Administrator

    ADMIN

    Options

    @MattLaro , thank you so much for sharing your expertise! Your depth of knowledge and willingness to help is super appreciated. 🙌