What are foreign filters?
- What are foreign filters?
- What are foreign filters?
- How it works: Normalized vs. Denormalized
- Simple equality filters
- Range filters
- Multiple conditions with AND/OR
- Combine with document filters
- Precise filtering with multiple array items
- Performance considerations
- Hard limit: Foreign filters with maximum 1000 matching documents
- Routes supporting foreign filters
- Next steps
- Define relationships
- Filtering basics
Foreign filters enable you to find documents based on properties of related documents in other indices. Instead of storing all data in one denormalized document, you can define relationships and use foreign filters to query across them.
What are foreign filters?
Without joins, you must denormalize data:
{
"id": "deal_1",
"title": "Enterprise Contract",
"company": {
"name": "Acme Inc",
"industry": "Technology",
"founded_year": 2010
}
}
With joins, you store only the reference:
{
"id": "deal_1",
"title": "Enterprise Contract",
"company_id": "company_42"
}
Then filter deals by company properties:
cURL
curl \
-X POST 'MEILISEARCH_URL/indexes/deals/search' \
-H 'Authorization: Bearer API_KEY' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "contract",
"filter": "_foreign(company, industry = \"Technology\" AND founded_year >= 2000)"
}'
How it works: Normalized vs. Denormalized
Without joins (denormalized)
Duplicate data in each deal:
[
{"id": "deal_1", "company": {"name": "Acme Inc", "industry": "Technology"}},
{"id": "deal_2", "company": {"name": "Acme Inc", "industry": "Technology"}},
{"id": "deal_3", "company": {"name": "Beta Corp", "industry": "Finance"}}
]
Update Acme’s industry and all three deals must be updated.
With joins (normalized)
Store data once: Companies:
[
{"id": "company_42", "name": "Acme Inc", "industry": "Technology"}
]
Deals:
[
{"id": "deal_1", "company_id": "company_42"},
{"id": "deal_2", "company_id": "company_42"},
{"id": "deal_3", "company_id": "company_99"}
]
Update Acme’s industry once. All deals linked to it automatically reflect the change.
Simple equality filters
Filter deals where the company is a specific one:
cURL
curl \
-X POST 'MEILISEARCH_URL/indexes/deals/search' \
-H 'Authorization: Bearer API_KEY' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "contract",
"filter": "_foreign(company, id = \"company_42\")"
}'
Returns deals with the matching company ID.
Multiple equality conditions
Find deals from companies with multiple specific criteria:
cURL
curl \
-X POST 'MEILISEARCH_URL/indexes/deals/search' \
-H 'Authorization: Bearer API_KEY' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"filter": "_foreign(company, industry = \"Technology\" OR industry = \"Finance\")"
}'
Range filters
Filter by numeric or date properties of related documents:
cURL
curl \
-X POST 'MEILISEARCH_URL/indexes/deals/search' \
-H 'Authorization: Bearer API_KEY' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "enterprise",
"filter": "_foreign(company, founded_year >= 2000 AND founded_year <= 2020)"
}'
Returns deals from companies founded between 2000 and 2020.
Date ranges
Filter by date properties:
cURL
curl \
-X POST 'MEILISEARCH_URL/indexes/deals/search' \
-H 'Authorization: Bearer API_KEY' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"filter": "_foreign(company, last_funding_date >= \"2023-01-01\")"
}'
Multiple conditions with AND/OR
Combine conditions using logical operators:
cURL
curl \
-X POST 'MEILISEARCH_URL/indexes/deals/search' \
-H 'Authorization: Bearer API_KEY' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "contract",
"filter": "_foreign(company, (industry = \"Technology\" AND founded_year >= 2010) OR revenue > 1000000)"
}'
Returns deals where:
- Company is in Technology industry AND founded after 2010, OR
- Company has revenue over 1 million
Combine with document filters
Mix filters on source and related documents:
cURL
curl \
-X POST 'MEILISEARCH_URL/indexes/deals/search' \
-H 'Authorization: Bearer API_KEY' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "contract",
"filter": "value >= 100000 AND _foreign(company, industry = \"Technology\")"
}'
Returns deals that are:
- Worth at least 100k, AND
- From a technology company
Precise filtering with multiple array items
When you have array relationships, foreign filters enable AND logic across array items. This means you can find documents where a single related item meets multiple conditions simultaneously. For detailed examples and use cases, see the Precise filtering with array relationships guide.
Performance considerations
Filter specificity
Broader filters on related data may hit the 1000-document limit:
## ✓ Good: Very specific
filter: "_foreign(company, industry = \"Technology\" AND state = \"CA\")"
## ✗ Problematic: May return > 1000 docs
filter: "_foreign(company, industry = \"Technology\")"
Combine filters strategically
Use multiple conditions to narrow results:
## Combine source and target filters to reduce matching documents
filter: "value >= 500000 AND _foreign(company, founded_year >= 2020)"
Test with your data
Before production, verify filter performance:
- Estimate how many target documents match each filter
- Ensure results stay under 1000 documents
- Add more specific conditions if needed
Hard limit: Foreign filters with maximum 1000 matching documents
If a foreign filter returns more than 1000 matching documents from the target index, Meilisearch will return an error. Design your foreign filters carefully to stay within this limit by being more specific with your filtering criteria.
Example: If you filter for _foreign(company, industry = “Technology”) and your database has 1,500 technology companies, the query fails.
Solutions:
- Add additional filter conditions:
_foreign(company, industry = “Technology” AND founded_year >= 2020)(narrows results) - Use other attributes:
_foreign(company, industry = “Technology” AND revenue > 1000000) - Break into multiple queries with narrower filters
- Consider denormalization if filtering patterns require very broad queries
Routes supporting foreign filters
You can use foreign filters only on document retrieval routes:
- GET/POST
/indexes/{index_uid}/search - POST
/indexes/{index_uid}/facet-search - GET/POST
/indexes/{index_uid}/similar - GET
/indexes/{index_uid}/documents - POST
/indexes/{index_uid}/documents/fetch - POST
/multi-search
Other routes that accept filters do not support foreign filters. Meilisearch returns an error if you use _foreign() on them.
Next steps
Define relationships
Learn how to configure join relationships
Filtering basics
Return to basic filtering guide
