---
title: "Conditional filters"
description: "GraphQL filtering documentation for applying conditional logic to refine search results."
url: https://docs.weaviate.io/weaviate/api/graphql/filters
---

# Conditional filters

> [!WARNING]
>
> **The GraphQL API is deprecated**
>
> Weaviate Cloud switches off the GraphQL API on **May 1, 2027**. Clusters that have not used GraphQL in the last 30 days have it switched off from December 1, 2026. New Weaviate Cloud clusters are already created with GraphQL disabled. Self-hosted Weaviate keeps GraphQL until at least May 1, 2027. The first minor release after that date disables it by default, and you can switch it back on. It is removed in a later release.
>
> Use a [client library](https://docs.weaviate.io/weaviate/client-libraries), the [web client](https://docs.weaviate.io/weaviate/client-libraries/typescript/web-client) or the REST Search API instead. See [Migrating from the GraphQL API](https://docs.weaviate.io/weaviate/api/graphql/migration).

Conditional filters may be added to queries such as [`Object-level`](https://docs.weaviate.io/weaviate/api/graphql/get) and [`Aggregate`](https://docs.weaviate.io/weaviate/api/graphql/aggregate) queries, as well as [batch deletion](https://docs.weaviate.io/weaviate/manage-objects/delete#delete-multiple-objects). The operator used for filtering is also called a `where` filter.

A filter may consist of one or more conditions, which are combined using the `And` or `Or` operators. Each condition consists of a property path, an operator, and a value.

## Single operand (condition)

Each set of algebraic conditions is called an "operand". For each operand, the required properties are:

- The operator type,
- The property path, and
- The value as well as the value type.

For example, this filter will only allow objects from the class `Article` with a `wordCount` that is `GreaterThan` than `1000`.

**Python**

```py
import weaviate
from weaviate.classes.query import Filter, GeoCoordinate, MetadataQuery, QueryReference  # Import classes as needed
import os

client = weaviate.connect_to_local()

collection = client.collections.use("Article")
response = collection.query.fetch_objects(
    filters=Filter.by_property("wordCount").greater_than(1000),
    limit=5
)

for o in response.objects:
    print(o.properties)  # Inspect returned objects
client.close()
```

**Go (v5)**

```go
package main

import (
	"context"
	"fmt"

	"github.com/weaviate/weaviate-go-client/v5/weaviate"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/filters"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
	cfg := weaviate.Config{
		Host:   "localhost:8080",
		Scheme: "http",
	}
	client, err := weaviate.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	title := graphql.Field{Name: "title"}
	where := filters.Where().
		WithPath([]string{"wordCount"}).
		WithOperator(filters.GreaterThan).
		WithValueInt(1000)

	ctx := context.Background()

	result, err := client.GraphQL().Get().
		WithClassName("Article").
		WithFields(title).
		WithWhere(where).
		Do(ctx)

	if err != nil {
		panic(err)
	}
	fmt.Printf("%v", result)
}
```

**Curl**

```bash
echo '{
  "query": "{
    Get {
      Article(where: {
        path: [\"wordCount\"],
        operator: GreaterThan,
        valueInt: 1000
      }) {
        title
      }
    }
  }"
}' | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer learn-weaviate' \
    -d @- \
    https://edu-demo.weaviate.network/v1/graphql
```

**GraphQL**

```graphql
{
  Get {
    Article(where: {
      path: ["wordCount"],    # Path to the property that should be used
      operator: GreaterThan,  # operator
      valueInt: 1000          # value (which is always = to the type of the path property)
    }) {
      title
    }
  }
}
```

**Expected response**

```text
{
  "data": {
    "Get": {
      "Article": [
        {
          "title": "Anywhere but Washington: an eye-opening journey in a deeply divided nation"
        },
        {
          "title": "The world is still struggling to implement meaningful climate policy"
        },
        ...
      ]
    }
  }
}
```

## Filter structure

The `where` filter is an [algebraic object](https://en.wikipedia.org/wiki/Algebraic_structure), which takes the following arguments:

- `Operator` (which takes one of the following values)

  - `And`
  - `Or`
  - `Not`
  - `Equal`
  - `NotEqual`
  - `GreaterThan`
  - `GreaterThanEqual`
  - `LessThan`
  - `LessThanEqual`
  - `Like`
  - `WithinGeoRange`
  - `IsNull`
  - `ContainsAny` (\*For `text`/`string`, `int`, `number`, `boolean`, `date`, `uuid` properties and their array variants)
  - `ContainsAll` (\*For `text`/`string`, `int`, `number`, `boolean`, `date`, `uuid` properties and their array variants)
  - `ContainsNone` (\*For `text`/`string`, `int`, `number`, `boolean`, `date`, `uuid` properties and their array variants)

- `Path`: Is a list of strings in [XPath](https://en.wikipedia.org/wiki/XPath#Abbreviated_syntax) style, indicating the property name of the collection.
  - If the property is a cross-reference, the path should be followed as a list of strings. For a `inPublication` reference property that refers to `Publication` collection, the path selector for `name` will be `["inPublication", "Publication", "name"]`.

- `valueType`

  - `valueInt`: For `int` data type.
  - `valueBoolean`: For `boolean` data type.
  - `valueString`: For `string` data type (note: `string` has been deprecated).
  - `valueText`: For `text`, `uuid`, `geoCoordinates`, `phoneNumber` data types.
  - `valueNumber`: For `number` data type.
  - `valueDate`: For `date` (ISO 8601 timestamp, formatted as [RFC3339](https://datatracker.ietf.org/doc/rfc3339/)) data type.

If the operator is `And` or `Or`, the operands are a list of `where` filters.

**Example filter structure (GraphQL)**

```graphql
{
  Get {
    <Class>(where: {
        operator: <operator>,
        operands: [{
          path: [path],
          operator: <operator>
          <valueType>: <value>
        }, {
          path: [<matchPath>],
          operator: <operator>,
          <valueType>: <value>
        }]
      }) {
      <propertyWithBeacon> {
        <property>
        ... on <ClassOfWhereBeaconGoesTo> {
          <propertyOfClass>
        }
      }
    }
  }
}
```

**Example response**

```json
{
  "data": {
    "Get": {
      "Article": [
        {
          "title": "Opinion | John Lennon Told Them ‘Girls Don't Play Guitar.' He Was So Wrong."
        }
      ]
    }
  },
  "errors": null
}
```

### Filter behaviors

#### Multi-word queries in `Equal` filters

The behavior for the `Equal` operator on multi-word textual properties in `where` filters depends on the `tokenization` of the property.

See the [Schema property tokenization section](https://docs.weaviate.io/weaviate/config-refs/collections#tokenization) for the difference between the available tokenization types.

#### Stopwords in `text` filters

Starting with `v1.12.0` you can configure your own [stopword lists for the inverted index](https://docs.weaviate.io/weaviate/config-refs/indexing/inverted-index#stopwords).

## Multiple operands

You can set multiple operands or [combine conditions with `And` / `Or`](https://docs.weaviate.io/weaviate/search/filters#combine-filters-with-and-or-or).

> [!TIP]
>
> You can filter datetimes similarly to numbers, with the `valueDate` given as `string` in [RFC3339](https://datatracker.ietf.org/doc/rfc3339/) format.

**Python**

```py
import weaviate
from weaviate.classes.query import Filter, GeoCoordinate, MetadataQuery, QueryReference  # Import classes as needed
import os

client = weaviate.connect_to_local()

collection = client.collections.use("Article")
response = collection.query.fetch_objects(
    filters=(
        Filter.by_property("wordCount").greater_than(1000)
        & Filter.by_property("title").like("*economy*")
    ),
    limit=5,
)

for o in response.objects:
    print(o.properties)  # Inspect returned objects
client.close()
```

**Go (v5)**

```go
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/weaviate/weaviate-go-client/v5/weaviate"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/filters"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
	cfg := weaviate.Config{
		Host:   "localhost:8080",
		Scheme: "http",
	}
	client, err := weaviate.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	title := graphql.Field{Name: "title"}

	filterString := "*economy*"
	if err != nil {
		panic(err)
	}

	where := filters.Where().
		WithOperator(filters.And).
		WithOperands([]*filters.WhereBuilder{
			filters.Where().
				WithPath([]string{"wordCount"}).
				WithOperator(filters.GreaterThan).
				WithValueInt(1000),
			filters.Where().
				WithPath([]string{"title"}).
				WithOperator(filters.Like).
				WithValueText(filterString),
		})

	ctx := context.Background()

	result, err := client.GraphQL().Get().
		WithClassName("Article").
		WithFields(title).
		WithWhere(where).
		Do(ctx)

	if err != nil {
		panic(err)
	}
	fmt.Printf("%v", result)
}
```

**Curl**

```bash
echo '{
  "query": "{
    Get {
      Article(where: {
        operator: And,
        operands: [{
          path: [\"wordCount\"],
          operator: GreaterThan,
          valueInt: 1000
        }, {
          path: [\"title\"],
          operator: Like,
          valueText: \"*economy*\"
        }]
      }) {
        title
      }
    }
  }"
}' | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer learn-weaviate' \
    -d @- \
    https://edu-demo.weaviate.network/v1/graphql
```

**GraphQL**

```graphql
{
  Get {
    Article(where: {
      operator: And,
      operands: [{
          path: ["wordCount"],
          operator: GreaterThan,
          valueInt: 1000
        }, {
          path: ["title"],
          operator: Like,
          valueText:"*economy*"
        }]
      }) {
      title
    }
  }
}
```

**Expected response**

```json
{
  "data": {
    "Get": {
      "Article": [
        {
          "title": "China\u2019s long-distance lorry drivers are unsung heroes of its economy"
        },
        {
          "title": "\u2018It\u2019s as if there\u2019s no Covid\u2019: Nepal defies pandemic amid a broken economy"
        },
        {
          "title": "A tax hike threatens the health of Japan\u2019s economy"
        }
      ]
    }
  }
}
```

## Filter operators

### `Like`

The `Like` operator filters `text` data based on partial matches. It can be used with the following wildcard characters:

- `?` -> exactly one unknown character
  - `car?` matches `cart`, `care`, but not `car`

- `*` -> zero, one or more unknown characters

  - `car*` matches `car`, `care`, `carpet`, etc
  - `*car*` matches `car`, `healthcare`, etc.

**Python**

```py
import weaviate
from weaviate.classes.query import Filter, GeoCoordinate, MetadataQuery, QueryReference  # Import classes as needed
import os

client = weaviate.connect_to_local()

collection = client.collections.use("Article")
response = collection.query.fetch_objects(
    filters=Filter.by_property("title").like("New *"),
    limit=5
)

for o in response.objects:
    print(o.properties)  # Inspect returned objects
client.close()
```

**Go (v5)**

```go
package main

import (
	"context"
	"fmt"

	"github.com/weaviate/weaviate-go-client/v5/weaviate"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/filters"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
	cfg := weaviate.Config{
		Host:   "localhost:8080",
		Scheme: "http",
	}
	client, err := weaviate.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	name := graphql.Field{Name: "name"}
	where := filters.Where().
		WithPath([]string{"name"}).
		WithOperator(filters.Like).
		WithValueString("New *")

	ctx := context.Background()
	result, err := client.GraphQL().Get().
		WithClassName("Publication").
		WithFields(name).
		WithWhere(where).
		Do(ctx)

	if err != nil {
		panic(err)
	}
	fmt.Printf("%v", result)
}
```

**Curl**

```bash
echo '{
  "query": "{
    Get {
      Publication(where: {
        path: [\"name\"],
        operator: Like,
        valueText: \"New *\"
      }) {
        name
      }
    }
  }"
}' | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer learn-weaviate' \
    -d @- \
    https://edu-demo.weaviate.network/v1/graphql
```

**GraphQL**

```graphql
{
  Get {
    Publication(where: {
      path: ["name"],
      operator: Like,
      valueText: "New *"
    }) {
      name
    }
  }
}
```

**Expected response**

```json
{
  "data": {
    "Get": {
      "Publication": [
        {
          "name": "The New York Times Company"
        },
        {
          "name": "International New York Times"
        },
        {
          "name": "New York Times"
        },
        {
          "name": "New Yorker"
        }
      ]
    }
  }
}
```

#### Performance of `Like`

Each `Like` filter iterates over the entire inverted index for that property. The search time will go up linearly with the dataset size, and may become slow for large datasets.

#### Wildcard literal matches with `Like`

Currently, the `Like` filter is not able to match wildcard characters (`?` and `*`) as literal characters. For example, it is currently not possible to only match the string `car*` and not `car`, `care` or `carpet`. This is a known limitation and may be addressed in future versions of Weaviate.

### `ContainsAny` / `ContainsAll` / `ContainsNone`

The `ContainsAny`, `ContainsAll` and `ContainsNone` operators filter objects using values of an array as criteria.

These operators expect an array of values and return objects that match based on the input values.

They are not limited to text. They work on `text`/`string`, `int`, `number`, `boolean`, `date`, and `uuid` properties, and on the array variants of each (`int[]`, `number[]`, etc.). A scalar property is treated as a single-element set: the object matches if its value satisfies the operator against the candidate list.

Pass the candidate values using the argument that matches the property's data type: `valueText` for `text`/`string`, `valueInt` for `int`, `valueNumber` for `number`, `valueBoolean` for `boolean`, and `valueDate` for `date`. For `uuid`/`uuid[]` properties, pass the UUIDs as strings using `valueText` (there is no `valueUuid` argument). For example, a `ContainsAny` query on an `int` property with a value of `[10, 20, 30]` returns objects whose property holds at least one of those integers.

Geo-coordinate and phone-number properties are not supported by these operators; use `WithinGeoRange` for geo filtering.

> [!NOTE]
>
> **`ContainsAny`/`ContainsAll`/`ContainsNone` notes:**
>
> - The `ContainsAny`, `ContainsAll` and `ContainsNone` operators treat texts as an array. The text is split into an array of tokens based on the chosen tokenization scheme, and the search is performed on that array.
> - When using `ContainsAny`, `ContainsAll` and `ContainsNone` with the REST api for [batch deletion](https://docs.weaviate.io/weaviate/manage-objects/delete#delete-multiple-objects), the values must be specified with the array-suffixed argument that matches the property's data type, such as `valueTextArray` for `text` (and `uuid`) or `valueIntArray` for `int`. This is different from the usage in search, where the singular argument (e.g. `valueText`, `valueInt`) can be used.

#### `ContainsAny`

`ContainsAny` returns objects where at least one of the values from the input array is present.

Consider a dataset of `Person`, where each object represents a person with a `languages_spoken` property with a `text` datatype.

A `ContainsAny` query on a path of `["languages_spoken"]` with a value of `["Chinese", "French", "English"]` will return objects where at least one of those languages is present in the `languages_spoken` array.

#### `ContainsAll`

`ContainsAll` returns objects where all the values from the input array are present.

Using the same dataset of `Person` objects as above, a `ContainsAll` query on a path of `["languages_spoken"]` with a value of `["Chinese", "French", "English"]` will return objects where all three of those languages are present in the `languages_spoken` array.

#### `ContainsNone`

`ContainsNone` returns objects where none of the values from the input array are present.

Using the same dataset of `Person` objects as above, a `ContainsNone` query on a path of `["languages_spoken"]` with a value of `["Chinese", "French", "English"]` will return objects where **none** of those languages are present in the `languages_spoken` array. For example, a person who speaks only Spanish would be returned, but a person who speaks English would be excluded.

## Filter performance

In some edge cases, filter performance may be slow due to a mismatch between the filter architecture and the data structure. For example, if a property has very large cardinality (i.e. a large number of unique values), its range-based filter performance may be slow.

If you are experiencing slow filter performance, you have several options:

- Further restrict your query by adding more conditions to the `where` operator
- Add a `limit` parameter to your query
- Configure `indexRangeFilters` for properties that require range-based filtering. You can [set inverted index parameters](https://docs.weaviate.io/weaviate/manage-collections/inverted-index) when creating your collection. Learn more about [configuring the inverted index](https://docs.weaviate.io/weaviate/concepts/indexing/inverted-index#configure-inverted-indexes) to optimize filter performance for your specific use case.

## Special cases

### By id

You can filter object by their unique id or uuid, where you give the `id` as `valueText`.

**Python**

```py
import weaviate
from weaviate.classes.query import Filter, GeoCoordinate, MetadataQuery, QueryReference  # Import classes as needed
import os

client = weaviate.connect_to_local()

collection = client.collections.use("Article")
response = collection.query.fetch_objects(
    filters=Filter.by_id().equal("00037775-1432-35e5-bc59-443baaef7d80")
)

for o in response.objects:
    print(o.properties)  # Inspect returned objects
client.close()
```

**Go (v5)**

```go
package main

import (
	"context"
	"fmt"

	"github.com/weaviate/weaviate-go-client/v5/weaviate"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/filters"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
	cfg := weaviate.Config{
		Host:   "localhost:8080",
		Scheme: "http",
	}
	client, err := weaviate.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	title := graphql.Field{Name: "title"}
	where := filters.Where().
		WithPath([]string{"id"}).
		WithOperator(filters.Equal).
		WithValueText("00037775-1432-35e5-bc59-443baaef7d80")

	ctx := context.Background()

	result, err := client.GraphQL().Get().
		WithClassName("Article").
		WithFields(title).
		WithWhere(where).
		Do(ctx)

	if err != nil {
		panic(err)
	}
	fmt.Printf("%v", result)
}
```

**Curl**

```bash
echo '{
  "query": "{
    Get {
      Article(where: {
        path: [\"id\"],
        operator: Equal,
        valueText: \"00037775-1432-35e5-bc59-443baaef7d80\"
      }) {
        title
      }
    }
  }"
}' | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer learn-weaviate' \
    -d @- \
    https://edu-demo.weaviate.network/v1/graphql
```

**GraphQL**

```graphql
{
  Get {
    Article(where: {
      path: ["id"],
      operator: Equal,
      valueText: "00037775-1432-35e5-bc59-443baaef7d80"
    }) {
      title
    }
  }
}
```

**Expected response**

```json
{
  "data": {
    "Get": {
      "Article": [
        {
          "title": "Backs on the rack - Vast sums are wasted on treatments for back pain that make it worse"
        }
      ]
    }
  }
}
```

### By timestamps

Filtering can be performed with internal timestamps as well, such as `creationTimeUnix` and `lastUpdateTimeUnix`. These values can be represented either as Unix epoch milliseconds, or as [RFC3339](https://datatracker.ietf.org/doc/rfc3339/) formatted datetimes. Note that epoch milliseconds should be passed in as a `valueText`, and an RFC3339 datetime should be a `valueDate`.

> [!NOTE]
>
> Filtering by timestamp requires the target class to be configured to index timestamps. See [here](https://docs.weaviate.io/weaviate/config-refs/indexing/inverted-index#indextimestamps) for details.

**Python**

```py
import weaviate
from weaviate.classes.query import Filter, GeoCoordinate, MetadataQuery, QueryReference  # Import classes as needed
import os
from datetime import datetime

client = weaviate.connect_to_local()

collection = client.collections.use("Article")
year2k = datetime.strptime("2000-01-01T00:00:00Z", "%Y-%m-%dT%H:%M:%SZ")

response = collection.query.fetch_objects(
    filters=Filter.by_creation_time().greater_or_equal(year2k),
    return_metadata=MetadataQuery(creation_time=True),
    limit=2
)

for o in response.objects:
    print(o.properties)  # Inspect returned objects
    print(o.metadata)  # Inspect returned creation time
client.close()
```

**Go (v5)**

```go
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/weaviate/weaviate-go-client/v5/weaviate"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/filters"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
	cfg := weaviate.Config{
		Host:   "localhost:8080",
		Scheme: "http",
	}
	client, err := weaviate.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	title := graphql.Field{Name: "title"}
	where := filters.Where().
		WithPath([]string{"_creationTimeUnix"}).
		WithOperator(filters.LessThan).
		WithValueDate(time.Now())  // Can use either `valueDate` with a `RFC3339` datetime or `valueText` as Unix epoch milliseconds

	ctx := context.Background()

	result, err := client.GraphQL().Get().
		WithClassName("Article").
		WithFields(title).
		WithWhere(where).
		Do(ctx)

	if err != nil {
		panic(err)
	}
	fmt.Printf("%v", result)
}
```

**Curl**

```bash
echo '{
  "query": "{
    Get {
      Article(where: {
        path: [\"_creationTimeUnix\"],
        operator: GreaterThan,
        valueDate: \"2022-03-18T20:26:34.586-05:00\"
      }) {
        title
      }
    }
  }"
}' | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer learn-weaviate' \
    -d @- \
    https://edu-demo.weaviate.network/v1/graphql
```

**GraphQL**

```graphql
{
  Get {
    Article(where: {
      path: ["_creationTimeUnix"],
      operator: GreaterThan,
      valueText: "1647653359063"  # can also use valueDate: "2022-03-18T20:26:34.586-05:00"
    }) {
      title
    }
  }
}
```

**Expected response**

```json
{
  "data": {
    "Get": {
      "Article": [
        {
          "title": "Army builds new body armor 14-times stronger in the face of enemy fire"
        },
        ...
      ]
    }
  }
}
```

### By property length

Filtering can be performed with the length of properties.

The length of properties is calculated differently depending on the type:

- array types: the number of entries in the array is used, where null (property not present) and empty arrays both have the length 0.
- strings and texts: the number of characters (unicode characters such as 世 count as one character).
- numbers, booleans, geo-coordinates, phone-numbers and data-blobs are not supported.

```graphql
{
  Get {
    <Class>(
      where: {
        operator: <Operator>,
        valueInt: <value>,
        path: ["len(<property>)"]
      }
    )
  }
}
```

Supported operators are `(not) equal` and `greater/less than (equal)` and values need to be 0 or larger.

Note that the `path` value is a string, where the property name is wrapped in `len()`. For example, to filter for objects based on the length of the `title` property, you would use `path: ["len(title)"]`.

To filter for `Article` class objects with `title` length greater than 10, you would use:

```graphql
{
  Get {
    Article(
      where: {
        operator: GreaterThan,
        valueInt: 10,
        path: ["len(title)"]
      }
    )
  }
}
```

> [!NOTE]
>
> Filtering by property length requires the target class to be [configured to index the length](https://docs.weaviate.io/weaviate/config-refs/indexing/inverted-index#indexpropertylength).

### By cross-references

You can also search for the value of the property of a cross-references, also called beacons.

For example, these filters select based on the class Article but who have `inPublication` set to New Yorker.

**Python**

```py
import weaviate
from weaviate.classes.query import Filter, GeoCoordinate, MetadataQuery, QueryReference  # Import classes as needed
import os

client = weaviate.connect_to_local()

collection = client.collections.use("Article")

response = collection.query.fetch_objects(
    filters=Filter.by_ref(link_on="inPublication").by_property("name").like("*New*"),
    return_references=QueryReference(link_on="inPublication", return_properties=["name"]),
    limit=2
)

for o in response.objects:
    print(o.properties)  # Inspect returned objects
    for ref_o in o.references["inPublication"].objects:
        print(ref_o.properties)
client.close()
```

**Go (v5)**

```go
package main

import (
	"context"
	"fmt"

	"github.com/weaviate/weaviate-go-client/v5/weaviate"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/filters"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
	cfg := weaviate.Config{
		Host:   "localhost:8080",
		Scheme: "http",
	}
	client, err := weaviate.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	fields := []graphql.Field{
		{Name: "title"},
		{Name: "inPublication", Fields: []graphql.Field{
			{Name: "... on Publication", Fields: []graphql.Field{
				{Name: "name"}},
			},
		}},
	}
	where := filters.Where().
		WithPath([]string{"inPublication", "Publication", "name"}).
		WithOperator(filters.Equal).
		WithValueString("New Yorker")

	ctx := context.Background()

	result, err := client.GraphQL().Get().
		WithClassName("Article").
		WithFields(fields...).
		WithWhere(where).
		Do(ctx)

	if err != nil {
		panic(err)
	}
	fmt.Printf("%v", result)
}
```

**Curl**

```bash
echo '{
  "query": "{
    Get {
      Article(where: {
        path: [\"inPublication\", \"Publication\", \"name\"],
        operator: Equal,
        valueText: \"New Yorker\"
      }) {
        title
        inPublication{
          ... on Publication{
            name
          }
        }
      }
    }
  }"
}' | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer learn-weaviate' \
    -d @- \
    https://edu-demo.weaviate.network/v1/graphql
```

**GraphQL**

```graphql
{
  Get {
    Article(where: {
      path: ["inPublication", "Publication", "name"],
      operator: Equal,
      valueText: "New Yorker"
    }) {
      title
      inPublication{
        ... on Publication{
          name
        }
      }
    }
  }
}
```

**Expected response**

```json
{
  "data": {
    "Get": {
      "Article": [
        {
          "inPublication": [
            {
              "name": "New Yorker"
            }
          ],
          "title": "The Hidden Costs of Automated Thinking"
        },
        {
          "inPublication": [
            {
              "name": "New Yorker"
            }
          ],
          "title": "The Real Deal Behind the U.S.\u2013Iran Prisoner Swap"
        },
        ...
      ]
    }
  }
}
```

### By count of reference

Above example shows how filter by reference can solve straightforward questions like "Find all articles that are published by New Yorker". But questions like "Find all articles that are written by authors that wrote at least two articles", cannot be answered by the above query structure. It is however possible to filter by reference count. To do so, simply provide one of the existing compare operators (`Equal`, `LessThan`, `LessThanEqual`, `GreaterThan`, `GreaterThanEqual`) and use it directly on the reference element. For example:

**Python**

```py
import weaviate
from weaviate.classes.query import Filter, GeoCoordinate, MetadataQuery, QueryReference  # Import classes as needed
import os

client = weaviate.connect_to_local()

response = collection.query.fetch_objects(
    filters=Filter.by_ref_count(link_on="inPublication").greater_than(2),
    return_references=QueryReference(link_on="inPublication", return_properties=["name"]),
    limit=2
)

for o in response.objects:
    print(o.properties)  # Inspect returned objects
    for ref_o in o.references["inPublication"].objects:
        print(ref_o.properties)
client.close()
```

**Go (v5)**

```go
package main

import (
	"context"
	"fmt"

	"github.com/weaviate/weaviate-go-client/v5/weaviate"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/filters"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
	cfg := weaviate.Config{
		Host:   "localhost:8080",
		Scheme: "http",
	}
	client, err := weaviate.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	fields := []graphql.Field{
		{Name: "name"},
		{Name: "writesFor", Fields: []graphql.Field{
			{Name: "... on Publication", Fields: []graphql.Field{
				{Name: "name"},
			}},
		}},
	}

	where := filters.Where().
		WithPath([]string{"writesFor"}).
		WithOperator(filters.GreaterThanEqual).
		WithValueInt(2)

	ctx := context.Background()

	result, err := client.GraphQL().Get().
		WithClassName("Author").
		WithFields(fields...).
		WithWhere(where).
		Do(ctx)

	if err != nil {
		panic(err)
	}
	fmt.Printf("%v", result)
}
```

**Curl**

```bash
echo '{
  "query": "{
    Get {
      Author(
        where:{
          valueInt: 2
          operator: GreaterThanEqual
          path: [\"writesFor\"]
        }
      ) {
        name
        writesFor {
          ... on Publication {
            name
          }
        }
      }
    }
   }"
  }' | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer learn-weaviate' \
    -d @- \
    https://edu-demo.weaviate.network/v1/graphql
```

**GraphQL**

```graphql
{
  Get {
    Author(
      where: {
        valueInt: 2,
        operator: GreaterThanEqual,
        path: ["writesFor"]
      }
    ) {
      name
      writesFor {
        ... on Publication {
          name
        }
      }
    }
  }
 }
```

**Expected response**

```json
{
  "data": {
    "Get": {
      "Author": [
        {
          "name": "Agam Shah",
          "writesFor": [
            {
              "name": "Wall Street Journal"
            },
            {
              "name": "Wall Street Journal"
            }
          ]
        },
        {
          "name": "Costas Paris",
          "writesFor": [
            {
              "name": "Wall Street Journal"
            },
            {
              "name": "Wall Street Journal"
            }
          ]
        },
        ...
      ]
    }
  }
}
```

### By nested object property

> [!WARNING]
>
> **Preview feature**
>
> Available from Weaviate `v1.38` as a preview, gated by `WEAVIATE_PREVIEW_NESTED_FILTERING=on` on the server. See [Filter on nested object properties](https://docs.weaviate.io/weaviate/search/filters#filter-on-nested-object-properties) for the conceptual guide and worked examples.

A `where` filter can target a leaf inside an [`object` / `object[]` property](https://docs.weaviate.io/weaviate/config-refs/datatypes#object). The `path` is a **single-element array** containing a dotted path; `[N]` pins a segment to an array index.

```graphql
# Any car has make = "Toyota"
{
  Get {
    Document(
      where: {
        path: ["cars.make"]
        operator: Equal
        valueText: "Toyota"
      }
    ) { title }
  }
}

# The first car's third tire is a Bridgestone
{
  Get {
    Document(
      where: {
        path: ["cars[0].tires[2].brand"]
        operator: Equal
        valueText: "Bridgestone"
      }
    ) { title }
  }
}

# Same-element correlation: the SAME car is both Toyota AND red
{
  Get {
    Document(
      where: {
        operator: And
        operands: [
          { path: ["cars.make"],  operator: Equal, valueText: "Toyota" }
          { path: ["cars.color"], operator: Equal, valueText: "red" }
        ]
      }
    ) { title }
  }
}
```

Don't confuse this with a [reference-path filter](https://docs.weaviate.io/weaviate/api/graphql/filters#by-cross-references): a reference-path `path` has multiple elements traversing cross-references (`["inCity", "City", "name"]`), while a nested-path `path` is a **single element** with dots inside it (`["cars.make"]`).

### By geo coordinates

A special case of the `Where` filter is with geoCoordinates. This filter is only supported by the `Get{}` function. If you've set the `geoCoordinates` property type, you can search in an area based on kilometers.

For example, this curious returns all in a radius of 2KM around a specific geo-location:

**Python**

```py
import weaviate
from weaviate.classes.query import Filter, GeoCoordinate, MetadataQuery, QueryReference  # Import classes as needed
import os

client = weaviate.connect_to_local()

response = publications.query.fetch_objects(
    filters=(
        Filter
        .by_property("headquartersGeoLocation")
        .within_geo_range(
            coordinate=GeoCoordinate(
                latitude=33.7579,
                longitude=84.3948
            ),
            distance=10000  # In meters
        )
    ),
)

for o in response.objects:
    print(o.properties)  # Inspect returned objects
client.close()
```

**Go (v5)**

```go
package main

import (
	"context"
	"fmt"

	"github.com/weaviate/weaviate-go-client/v5/weaviate"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/filters"
	"github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
	cfg := weaviate.Config{
		Host:   "localhost:8080",
		Scheme: "http",
	}
	client, err := weaviate.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	fields := []graphql.Field{
		{Name: "name"},
		{Name: "headquartersGeoLocation", Fields: []graphql.Field{
			{Name: "latitude"},
			{Name: "longitude"},
		}},
	}
	where := filters.Where().
		WithOperator(filters.WithinGeoRange).
		WithPath([]string{"headquartersGeoLocation"}).
		WithValueGeoRange(&filters.GeoCoordinatesParameter{
			Latitude:    51.51,
			Longitude:   -0.09,
			MaxDistance: 2000,
		})

	ctx := context.Background()

	result, err := client.GraphQL().Get().
		WithClassName("Publication").
		WithFields(fields...).
		WithWhere(where).
		Do(ctx)

	if err != nil {
		panic(err)
	}
	fmt.Printf("%v", result)
}
```

**Curl**

```bash
echo '{
  "query": "{
    Get {
      Publication(where: {
        operator: WithinGeoRange,
        valueGeoRange: {
          geoCoordinates: {
            latitude: 51.51,
            longitude: -0.09
          },
          distance: {
            max: 2000
          }
        },
        path: [\"headquartersGeoLocation\"]
      }) {
        name
        headquartersGeoLocation {
          latitude
          longitude
        }
      }
    }
  }"
}' | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer learn-weaviate' \
    -d @- \
    https://edu-demo.weaviate.network/v1/graphql
```

**GraphQL**

```graphql
{
  Get {
    Publication(where: {
      operator: WithinGeoRange,
      valueGeoRange: {
        geoCoordinates: {
          latitude: 51.51,    # latitude
          longitude: -0.09    # longitude
        },
        distance: {
          max: 2000           # distance in meters
        }
      },
      path: ["headquartersGeoLocation"] # property needs to be of geoLocation type.
    }) {
      name
      headquartersGeoLocation {
        latitude
        longitude
      }
    }
  }
}
```

**Expected response**

```json
{
  "data": {
    "Get": {
      "Publication": [
        {
          "headquartersGeoLocation": {
            "latitude": 51.512737,
            "longitude": -0.0962234
          },
          "name": "Financial Times"
        },
        {
          "headquartersGeoLocation": {
            "latitude": 51.512737,
            "longitude": -0.0962234
          },
          "name": "International New York Times"
        }
      ]
    }
  }
}
```

Note that `geoCoordinates` uses a vector index under the hood.

> [!NOTE]
>
> **Limitations**
>
> Currently, geo-coordinate filtering is limited to the nearest 800 results from the source location, which will be further reduced by any other filter conditions and search parameters.
>
> If you plan on a densely populated dataset, consider using another strategy such as geo-hashing into a `text` datatype, and filtering further, such as with a `ContainsAny` filter.

### By null state

Using the `IsNull` operator allows you to do filter for objects where given properties are `null` or `not null`. Note that zero-length arrays and empty strings are equivalent to a null value.

```graphql
{
  Get {
    <Class>(where: {
        operator: IsNull,
        valueBoolean: <true/false>,
        path: [<property>]
      }) {
      <property>
    }
  }
}
```

> [!NOTE]
>
> Filtering by null-state requires the target class to be configured to index this. See [here](https://docs.weaviate.io/weaviate/config-refs/indexing/inverted-index#indexnullstate) for details.

## Related pages

- [How-to search: Filters](https://docs.weaviate.io/weaviate/search/filters)
