How to use .where formatter with nested objects

Similar to my earlier topic I now run into an issue where (punt intended) I can’t seem to get the .where formatter to do what I want.

I have this array, with objects inside of it. I created a simple example:

{{[
        {
            "type": "document",
            "instance": {
                "file": {
                    "reference": "bcaed297-44ab-446a-8347-a0fa3f56336a"
                },
                "number": 20339,
                "name": "230809 overig klant - 1.pdf",
                }
        },
        {
            "type": "document",
            "instance": {
                "file": {
                    "reference": "e75823c4-a42b-4bad-936d-8325910aaf22"
                },
                "number": 20338,
                "filename": "230809 overig klant - 1 - kopie.pdf.pdf"
            }
        }
    ]}}

Now I want to retrieve the object where the number is 20338.
So I try

{{list.where('instance.number', '==', 20338)}}

Or

{{list.where('instance.number', '==', '20338')}}

But they both return empty.

Can anybody chime in on how to handle this?

ps: I didn’t choose this json structure for joy, I happend to get a much more complicated version of this in an api-call.

It might be your ordering. Try this

{{list.where('instance.number', 20338, '==')}}

Thanks to @Apple’s suggestion that perhaps the .where formatter does not support nesting or dot notation, I let chatgpt create a custom formatter that does.

And now it correctly retrieves the right object based on a value in a nested object! :tada: :tada: :tada: :tada:

Place this in your extensions/server_connect/formatters/somefile.js

// Custom formatter to filter array based on nested property, operator and value
exports.whereWithDot = function (arr, path, operator, value) {
    // Function to get nested property value using dot notation
    function getNestedValue(obj, path) {
        var keys = path.split('.');
        var current = obj;
        for (var i = 0; i < keys.length; i++) {
            if (current[keys[i]] !== undefined) {
                current = current[keys[i]];
            } else {
                return undefined;
            }
        }
        return current;
    }

    // Function to compare values based on operator
    function compare(val1, operator, val2) {
        switch (operator) {
            case '==':
                return val1 == val2;
            case '!=':
                return val1 != val2;
            case '>':
                return val1 > val2;
            case '>=':
                return val1 >= val2;
            case '<':
                return val1 < val2;
            case '<=':
                return val1 <= val2;
            default:
                throw new Error('Invalid operator: ' + operator);
        }
    }

    // Filter the array
    return arr.filter(function(item) {
        var nestedValue = getNestedValue(item, path);
        return compare(nestedValue, operator, value);
    });
};

And now this

{{list.whereWithDot('instance.number', '==', 20338)}}

Returns the proper object!

Thanks for your comment! When I make your edit it returns both objects, so the .where is not functioning correctly.

I am able to do some fairly complex logic, but all of this has to be manually created in code. Attempting to use the Wappler UI for any updates will completely rewrite this into something that doesn’t work.

Here’s some examples for my needs.
{{GetThreads.data.repeat.where('thread.data.messages[0].id',query.t,'==')[0].thread.data.messages[0].payload.headers.where(name, 'From', '==')[0].value.split('&lt;')[0].replace('"','').substr(0, 1)}}

thread.data.messages[0].labelIds.where('$value','TRASH','contains').values('$value')=='TRASH'

thread.data.messages.last(1)[0].payload.headers.where(name, 'Date', '==')[0].value.formatDate('h:mm a')

thread.data.messages.last(1)[0].payload.headers.where(name, 'Date' , '==' )[0].value.formatDate('yyyy-MM-ddTHH:MM:ssZ') &lt; currentDay.datetime && (thread.data.messages.last(1)[0].payload.headers.where(name, 'Date' , '==' )[0].value.formatDate('yyyy-MM-ddTHH:MM:ssZ') &gt; currentDay.datetime.addYears(-1))

Then you’re part way there. You’ll need to figure out how to target the right one based on your needs. There are ways to walk down the json and target the right portion, just requires some deep thinking sometimes. :slight_smile:

Maybe you need to make the number a string?

{{list.where('instance.number', '20338', '==')}}

or

{{list.where('instance[0].number', '20338', '==')}}

I think it is as @Apple said. That perhaps the where formatter does not supported nesting. But the custom where formatter in my comment above does and works perfectly!

And I’m saying I have no problems with nesting. :slight_smile:

Ok I’ll try your suggestion later tonight. Would only be easier if it supports nesting by default!

@kfawcett,

I have tried all these options, but only the bottom one returns the correct object. First 2 return all objects, 3 and 4 return no objects. 5 returns the correct object.

differentoptions

It would be great if you could share an example of a .where that filters on a value within a nested object. :smiley:

Did you try this?

{{list.where('instance[0].number', '20338', '==')}}

I did now. Still returns 2 objects, so no actual filtering. Thanks for your help and effort, @kfawcett

ok, let me build out a test with your json.

This is the server connect file. Note that for you it will error because you don’t have my custom formatter, most likely.

{
  "meta": {
    "options": {
      "linkedFile": "/views/somefile.ejs",
      "linkedForm": "register1"
    }
  },
  "exec": {
    "steps": [
      {
        "name": "list",
        "module": "core",
        "action": "setvalue",
        "options": {
          "value": "{{[\n        {\n            \"type\": \"document\",\n            \"instance\": {\n                \"file\": {\n                    \"reference\": \"bcaed297-44ab-446a-8347-a0fa3f56336a\",\n                    \"instance\": {\n                        \"md5\": \"7b68abe78f9b1998546e5e424fae5d\"\n                    }\n                },\n                \"number\": 20339,\n                \"name\": \"230809 overig klant - 1.pdf\",\n                \"filename\": \"230809 overig klant - 1.pdf.pdf\"\n                }\n        },\n        {\n            \"type\": \"document\",\n            \"instance\": {\n                \"file\": {\n                    \"reference\": \"e75823c4-a42b-4bad-936d-8325910aaf22\",\n                    \"instance\": {\n                        \"md5\": \"4ed02e60a6d31678ef85b180ee4a6b\"\n                    }\n                },\n                \"number\": 20338,\n                \"name\": \"230809 overig klant - 1 - kopie.pdf\",\n                \"filename\": \"230809 overig klant - 1 - kopie.pdf.pdf\"\n            }\n        }\n    ]}}"
        },
        "meta": [],
        "outputType": "array"
      },
      {
        "name": "first_object",
        "module": "core",
        "action": "setvalue",
        "options": {
          "value": "{{list[0]}}"
        },
        "meta": [],
        "outputType": "object"
      },
      {
        "name": "first_object_name",
        "module": "core",
        "action": "setvalue",
        "options": {
          "value": "{{list[0].instance.name}}"
        },
        "meta": [],
        "outputType": "object"
      },
      {
        "name": "object_for_reference",
        "module": "core",
        "action": "setvalue",
        "options": {
          "value": "{{list.where('instance.number', 20338, '==')}}"
        },
        "meta": [],
        "outputType": "object",
        "output": true
      },
      {
        "name": "object_for_reference_string",
        "module": "core",
        "action": "setvalue",
        "options": {
          "value": "{{list.where('instance.number', '20338', '==')}}"
        },
        "meta": [],
        "outputType": "object",
        "output": true
      },
      {
        "name": "object_for_reference_string_0",
        "module": "core",
        "action": "setvalue",
        "options": {
          "value": "{{list.where('instance[0].number', '20338', '==')}}"
        },
        "meta": [],
        "outputType": "object",
        "output": true
      },
      {
        "name": "object_for_reference_string_switch",
        "module": "core",
        "action": "setvalue",
        "options": {
          "value": "{{list.where('instance.number', '==', '20338' )}}"
        },
        "meta": [],
        "outputType": "object",
        "output": true
      },
      {
        "name": "object_for_reference_switch",
        "module": "core",
        "action": "setvalue",
        "options": {
          "value": "{{list.where('instance.number', '==', 20338 )}}"
        },
        "meta": [],
        "outputType": "object",
        "output": true
      },
      {
        "name": "object_for_reference_gpt",
        "module": "core",
        "action": "setvalue",
        "options": {
          "value": "{{list.whereWithDot('instance.number', '==', 20338)}}"
        },
        "meta": [],
        "outputType": "object",
        "output": true
      }
    ]
  }
}