> For the complete documentation index, see [llms.txt](https://docs.gridmate.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.gridmate.io/advanced-guides/grid-advanced-filtering.md).

# Grid - Advanced Filtering

## Using Junctions

To filter the records either as an admin or as an end user can combine conditions with conjunctions like ‘OR’, ‘AND’. Below is a complex filter query:

```coffeescript
{
   "or": [
      {
         "ParentId": {
            "operator": "=",
            "value": "$recordId"
         }
      },
      {
         "UltimateParent__c": {
            "operator": "=",
            "value": "$recordId"
         }
      }
   ]
}
```

{% hint style="info" %}
$recordId can be used to implicitly use the current recordId
{% endhint %}

## Using Inline SOQL

An inline SOQL query can be used to filter records within the current record. Inline SOQL can be used with “in” operator only:

```coffeescript
{
   "Id": {
      "operator": "in",
      "value": "SELECT Project__c FROM Assignment__c WHERE Manager__c=$$recordId$"
   }
}
```

{% hint style="info" %}
$$recordId$ can be used to implicitly use the current recordId in the SOQL query
{% endhint %}

## Using Parent Field

Any field from the current object can be used to filter the related records. Parent fields can be referenced in the filter property as a merge field $record.**fieldApiName**&#x20;

```coffeescript
{
   "Country__c": {
      "operator": "=",
      "value": "$record.BillingCountry"
   }
}
```

## Using $USER

Any field from the logged user can be used to filter the related records. User fields can be referenced in the filter property as a merge field $USER.**fieldApiName**&#x20;

```coffeescript
{
   "Amount": {
      "operator": "<",
      "value": "$USER.Minimum_Amount__c"
   }
}
```

## Using $CUSTOMSETTING

Any field from any custom settings can be used to filter the related records. Custom settings fields can be referenced in the filter property as a merge field $CUSTOMSETTING.**objectApiName**.**fieldApiName**&#x20;

```coffeescript
{
   "Discount__c": {
      "operator": ">",
      "value": "$CUSTOMSETTING.Quote_Settings__c.Max_Discount__c"
   }
}
```

## Using $APEX

For complex use cases, an apex class can be provided as a value provider for a filter property as a merge field $APEX.className({params})&#x20;

```coffeescript
{
   "Id": {
      "operator": "in",
      "value": "$APEX.AttachedDocumentFilter({\"recordId\":\"$recordId\"})"
   }
}
```

{% hint style="info" %}
Apex class parameters should be always an escaped JSON string. $recordId can be used to implicitly use the current recordId.&#x20;
{% endhint %}

The value provider class should implement a Callable interface and should be global. GridMate runs the value provider dynamically:

```java
Callable handler = (Callable) Type.forName(handlerClass).newInstance();
return (String) handler.call('getValue', params);
```

The example below showcase a specific value provider to filter ContentVersion based on the current record:

{% tabs %}
{% tab title="AttachedDocumentFilter.cls" %}

```java
global with sharing class AttachedDocumentFilter implements Callable {
    global Object call(String action, Map<String, Object> args) {
        if (action == 'getValue') {
            String recordId = (String) args.get('recordId');

            //Build the list of linked documents
            List<ContentDocumentLink> linkList = [
                SELECT Id, ContentDocument.LatestPublishedVersionId
                FROM ContentDocumentLink
                WHERE LinkedEntityId = :recordId
            ];

            List<Id> idList = new List<Id>();
            for (ContentDocumentLink link : linkList) {
                idList.add(link.ContentDocument.LatestPublishedVersionId);
            }

            return '(\'' + String.join(idList, '\',\'') + '\')';
        } else {
            throw new ExtensionMalformedCallException('Action not implemented');
        }
    }

    public class ExtensionMalformedCallException extends Exception {
    }
}
```

{% endtab %}

{% tab title="AttachedDocumentFilterTest.cls" %}

```java
@isTest
class AttachedDocumentFilterTest {
    @testSetup
    static void createTestData() {
        ContentVersion content = new ContentVersion(
            Title = 'Demo Script',
            PathOnClient = '/demo_script.txt',
            VersionData = Blob.valueOf('Unit Test ContentVersion Body'),
            Origin = 'H'
        );

        insert content;
    }

    static testMethod void testExecute() {
        Test.startTest();

        Callable handler = (Callable) Type.forName('AttachedDocumentFilter').newInstance();
        String values = (String) handler.call(
            'getValue',
            new Map<String, String>{ 'recordId' => UserInfo.getUserId() }
        );

        Test.stopTest();

        System.assert(values != null);
    }
}
```

{% endtab %}
{% endtabs %}

## Querying All Rows

To query all rows set the flag **gmpkg\_\_allRows** to true. The example below showcase a filter fecthing all the emails including the archived ones:

```json
{
    "and": [
        {
            "AccountId": {
                "operator": "=",
                "value": "$recordId"
            }
        },
        {
            "Subject": {
                "operator": "like",
                "value": "Email%"
            }
        },
        {
            "gmpkg__allRows": true
        }
    ]
}
```
