Skip to main content

Documentation Index

Fetch the complete documentation index at: https://www.meilisearch.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

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 \
  -X POST 'MEILISEARCH_URL/indexes/deals/search' \
  -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 \
  -X POST 'MEILISEARCH_URL/indexes/deals/search' \
  -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 \
  -X POST 'MEILISEARCH_URL/indexes/deals/search' \
  -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 \
  -X POST 'MEILISEARCH_URL/indexes/deals/search' \
  -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 \
  -X POST 'MEILISEARCH_URL/indexes/deals/search' \
  -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 \
  -X POST 'MEILISEARCH_URL/indexes/deals/search' \
  -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 \
  -X POST 'MEILISEARCH_URL/indexes/deals/search' \
  -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 100-document limit:
# ✓ Good: Very specific
filter: "_foreign(company, industry = \"Technology\" AND state = \"CA\")"

# ✗ Problematic: May return > 100 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 100 documents
  • Add more specific conditions if needed

Hard limit: Foreign filters with maximum 100 matching documents

If a foreign filter returns more than 100 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 150 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

Next steps

Define relationships

Learn how to configure join relationships

Filtering basics

Return to basic filtering guide