{
  "schema_version": 2,
  "id": "develop/ai/search-and-query/query/geo-spatial",
  "title": "Geospatial queries",
  "url": "https://redis.io/docs/latest/develop/ai/search-and-query/query/geo-spatial/",
  "summary": "Query based on geographic data",
  "aliases": [
    "/develop/interact/search-and-query/query/geo-spatial"
  ],
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-09-11T15:33:04+01:00",
  "page_type": "content",
  "content_hash": "1576e0fe2560229e152d8fc67ad30c89863f3332196c0ac59357e7f5b7f88c5e",
  "sections": [
    {
      "id": "radius",
      "title": "Radius",
      "role": "content",
      "text": "You can construct a radius query by passing the center coordinates (longitude, latitude), the radius, and the distance unit to the [FT.SEARCH](https://redis.io/docs/latest/commands/ft.search) command.\n\n[code example]\n\nAllowed units are `m`, `km`, `mi`, and `ft`.\n\nThe following query finds all bicycle stores within a radius of 20 miles around London:\n\nFoundational: Query geographic locations within a radius using center coordinates and distance when you need to find nearby points of interest\n\n**Difficulty:** Beginner\n\n**Available in:** Redis CLI, Go, Java (Synchronous - Jedis), JavaScript (Node.js), Python\n\n##### Redis CLI\n\n[code example]\n\n##### Go\n\n[code example]\n\n##### Java (Synchronous - Jedis)\n\n[code example]\n\n##### JavaScript (Node.js)\n\n[code example]\n\n##### Python\n\n[code example]"
    },
    {
      "id": "shape",
      "title": "Shape",
      "role": "content",
      "text": "The only supported shapes are points and polygons. You can query for polygons or points that either contain or are within a given geometric shape.\n\n[code example]\n\nHere is a more detailed explanation of this query:\n\n1. **Field name**: you need to replace `geo_shape_field` with the `GEOSHAPE` field's name on which you want to query.\n2. **Spatial operator**: spatial operators define the relationship between the shapes in the database and the shape you are searching for. You can either use `WITHIN`, `CONTAINS`, `INTERSECTS`, or `DISJOINT`. `WITHIN` finds any shape in the database that is inside the given shape. `CONTAINS` queries for any shape that surrounds the given shape. `INTERSECTS` finds any shape that has coordinates in common with the provided shape. `DISJOINT` finds any shapes that have nothing in common with the provided shape. `INTERSECTS` and `DISJOINT` were introduced in v2.10.\n3. **Parameter**: the query refers to a parameter named `shape`. You can use any parameter name here. You need to use the `PARAMS` clause to set the parameter value. The value follows the [well-known text representation of a geometry](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry). Supported types are `POINT(x y)` and `POLYGON((x1 y1, x2 y2, ...))`.\n4. **Dialect**: Shape-based queries are not supported in `DIALECT 1`.\n\nThe following example query verifies if a bicycle is within a pickup zone:\n\nSpatial operators: Query geometric shapes using CONTAINS to test which shapes enclose another shape when you need to find bounding regions\n\n**Difficulty:** Intermediate\n\n**Available in:** Redis CLI, Go, Java (Synchronous - Jedis), JavaScript (Node.js), Python\n\n##### Redis CLI\n\n[code example]\n\n##### Go\n\n[code example]\n\n##### Java (Synchronous - Jedis)\n\n[code example]\n\n##### JavaScript (Node.js)\n\n[code example]\n\n##### Python\n\n[code example]\n\n\n\nIf you want to find all pickup zones that are approximately within Europe, then you can use the following query:\n\nSpatial operators: Query geometric shapes using the WITHIN operator to find shapes contained in a region when you need to identify items within geographic boundaries\n\n**Difficulty:** Intermediate\n\n**Available in:** Redis CLI, Go, Java (Synchronous - Jedis), JavaScript (Node.js), Python\n\n##### Redis CLI\n\n[code example]\n\n##### Go\n\n[code example]\n\n##### Java (Synchronous - Jedis)\n\n[code example]\n\n##### JavaScript (Node.js)\n\n[code example]\n\n##### Python\n\n[code example]"
    }
  ],
  "examples": [
    {
      "id": "radius-ex0",
      "language": "plaintext",
      "code": "FT.SEARCH index \"@geo_field:[lon lat radius unit]\"",
      "section_id": "radius"
    },
    {
      "id": "radius-ex1",
      "language": "plaintext",
      "code": "FT.SEARCH idx:bicycle \"@store_location:[-0.1778 51.5524 20 mi]\"",
      "section_id": "radius"
    },
    {
      "id": "radius-ex2",
      "language": "go",
      "code": "res1, err := rdb.FTSearchWithArgs(ctx,\n\t\t\"idx:bicycle\", \"@store_location:[$lon $lat $radius $units]\",\n\t\t&redis.FTSearchOptions{\n\t\t\tParams: map[string]interface{}{\n\t\t\t\t\"lon\":    -0.1778,\n\t\t\t\t\"lat\":    51.5524,\n\t\t\t\t\"radius\": 20,\n\t\t\t\t\"units\":  \"mi\",\n\t\t\t},\n\t\t\tDialectVersion: 2,\n\t\t},\n\t).Result()\n\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Println(res1.Total) // >>> 1\n\n\tfor _, doc := range res1.Docs {\n\t\tfmt.Println(doc.ID)\n\t}\n\t// >>> bicycle:5",
      "section_id": "radius"
    },
    {
      "id": "radius-ex3",
      "language": "java",
      "code": "SearchResult res1 = jedis.ftSearch(\"idx:bicycle\",\n            \"@store_location:[$lon $lat $radius $units]\",\n            FTSearchParams.searchParams()\n                    .addParam(\"lon\", -0.1778)\n                    .addParam(\"lat\", 51.5524)\n                    .addParam(\"radius\", 20)\n                    .addParam(\"units\", \"mi\")\n                    .dialect(2)\n        );\n        System.out.println(res1.getTotalResults()); // >>> 1\n\n        List<Document> docs1 = res1.getDocuments();\n\n        for (Document document : docs1) {\n            System.out.println(document.getId());\n        }\n        // >>> bicycle:5",
      "section_id": "radius"
    },
    {
      "id": "radius-ex4",
      "language": "javascript",
      "code": "const res1= await client.ft.search('idx:bicycle', '@store_location:[-0.1778 51.5524 20 mi]');\nconsole.log(res1.total); // >>> 1\nconsole.log(res1); // >>> {total: 1, documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]}",
      "section_id": "radius"
    },
    {
      "id": "radius-ex5",
      "language": "python",
      "code": "params_dict = {\"lon\": -0.1778, \"lat\": 51.5524, \"radius\": 20, \"units\": \"mi\"}\nq = Query(\"@store_location:[$lon $lat $radius $units]\").dialect(2)\nres = index.search(q, query_params=params_dict)\nprint(res)\n# >>> Result{1 total, docs: [Document {'id': 'bicycle:5', ...",
      "section_id": "radius"
    },
    {
      "id": "shape-ex0",
      "language": "plaintext",
      "code": "FT.SEARCH index \"@geo_shape_field:[{WITHIN|CONTAINS|INTERSECTS|DISJOINT} $shape] PARAMS 2 shape \"shape_as_wkt\" DIALECT 3",
      "section_id": "shape"
    },
    {
      "id": "shape-ex1",
      "language": "plaintext",
      "code": "FT.SEARCH idx:bicycle \"@pickup_zone:[CONTAINS $bike]\" PARAMS 2 bike \"POINT(-0.1278 51.5074)\" DIALECT 2",
      "section_id": "shape"
    },
    {
      "id": "shape-ex2",
      "language": "go",
      "code": "res2, err := rdb.FTSearchWithArgs(ctx,\n\t\t\"idx:bicycle\",\n\t\t\"@pickup_zone:[CONTAINS $bike]\",\n\t\t&redis.FTSearchOptions{\n\t\t\tParams: map[string]interface{}{\n\t\t\t\t\"bike\": \"POINT(-0.1278 51.5074)\",\n\t\t\t},\n\t\t\tDialectVersion: 3,\n\t\t},\n\t).Result()\n\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Println(res2.Total) // >>> 1\n\n\tfor _, doc := range res2.Docs {\n\t\tfmt.Println(doc.ID)\n\t}\n\t// >>> bicycle:5",
      "section_id": "shape"
    },
    {
      "id": "shape-ex3",
      "language": "java",
      "code": "SearchResult res2 = jedis.ftSearch(\"idx:bicycle\",\n            \"@pickup_zone:[CONTAINS $bike]\",\n            FTSearchParams.searchParams()\n                    .addParam(\"bike\", \"POINT(-0.1278 51.5074)\")\n                    .dialect(3)\n        );\n        System.out.println(res2.getTotalResults());   // >>> 1\n\n        List<Document> docs2 = res2.getDocuments();\n\n        for (Document document : docs2) {\n            System.out.println(document.getId());\n        }\n        // >>> bicycle:5",
      "section_id": "shape"
    },
    {
      "id": "shape-ex4",
      "language": "javascript",
      "code": "const params_dict_geo2 = { bike: 'POINT(-0.1278 51.5074)' };\nconst q_geo2 = '@pickup_zone:[CONTAINS $bike]';\nconst res2 = await client.ft.search('idx:bicycle', q_geo2, { PARAMS: params_dict_geo2, DIALECT: 3 });\nconsole.log(res2.total); // >>> 1\nconsole.log(res2); // >>> {total: 1, documents: [ { id: 'bicycle:5', value: [Object: null prototype] } ]}",
      "section_id": "shape"
    },
    {
      "id": "shape-ex5",
      "language": "python",
      "code": "params_dict = {\"bike\": \"POINT(-0.1278 51.5074)\"}\nq = Query(\"@pickup_zone:[CONTAINS $bike]\").dialect(3)\nres = index.search(q, query_params=params_dict)\nprint(res.total) # >>> 1",
      "section_id": "shape"
    },
    {
      "id": "shape-ex6",
      "language": "plaintext",
      "code": "FT.SEARCH idx:bicycle \"@pickup_zone:[WITHIN $europe]\" PARAMS 2 europe \"POLYGON((-25 35, 40 35, 40 70, -25 70, -25 35))\" DIALECT 2",
      "section_id": "shape"
    },
    {
      "id": "shape-ex7",
      "language": "go",
      "code": "res3, err := rdb.FTSearchWithArgs(ctx,\n\t\t\"idx:bicycle\",\n\t\t\"@pickup_zone:[WITHIN $europe]\",\n\t\t&redis.FTSearchOptions{\n\t\t\tParams: map[string]interface{}{\n\t\t\t\t\"europe\": \"POLYGON((-25 35, 40 35, 40 70, -25 70, -25 35))\",\n\t\t\t},\n\t\t\tDialectVersion: 3,\n\t\t},\n\t).Result()\n\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Println(res3.Total) // >>> 5\n\n\tsort.Slice(res3.Docs, func(i, j int) bool {\n\t\treturn res3.Docs[i].ID < res3.Docs[j].ID\n\t})\n\n\tfor _, doc := range res3.Docs {\n\t\tfmt.Println(doc.ID)\n\t}\n\t// >>> bicycle:5\n\t// >>> bicycle:6\n\t// >>> bicycle:7\n\t// >>> bicycle:8\n\t// >>> bicycle:9",
      "section_id": "shape"
    },
    {
      "id": "shape-ex8",
      "language": "java",
      "code": "SearchResult res3 = jedis.ftSearch(\"idx:bicycle\",\n            \"@pickup_zone:[WITHIN $europe]\",\n            FTSearchParams.searchParams()\n                    .addParam(\"europe\", \"POLYGON((-25 35, 40 35, 40 70, -25 70, -25 35))\")\n                    .dialect(3)\n        );\n        System.out.println(res3.getTotalResults()); // >>> 5\n\n        List<Document> docs3 = res3.getDocuments();\n\n        for (Document document : docs3) {\n            System.out.println(document.getId());\n        }\n        // >>> bicycle:5\n        // >>> bicycle:6\n        // >>> bicycle:7\n        // >>> bicycle:8\n        // >>> bicycle:9",
      "section_id": "shape"
    },
    {
      "id": "shape-ex9",
      "language": "javascript",
      "code": "const params_dict_geo3 = { europe: 'POLYGON((-25 35, 40 35, 40 70, -25 70, -25 35))' };\nconst q_geo3 = '@pickup_zone:[WITHIN $europe]';\nconst res3 = await client.ft.search('idx:bicycle', q_geo3, { PARAMS: params_dict_geo3, DIALECT: 3 });\nconsole.log(res3.total); // >>> 5\nconsole.log(res3); // >>>\n// {\n//   total: 5,\n//   documents: [\n//     { id: 'bicycle:5', value: [Object: null prototype] },\n//     { id: 'bicycle:6', value: [Object: null prototype] },\n//     { id: 'bicycle:7', value: [Object: null prototype] },\n//     { id: 'bicycle:8', value: [Object: null prototype] },\n//     { id: 'bicycle:9', value: [Object: null prototype] }\n//   ]\n// }",
      "section_id": "shape"
    },
    {
      "id": "shape-ex10",
      "language": "python",
      "code": "params_dict = {\"europe\": \"POLYGON((-25 35, 40 35, 40 70, -25 70, -25 35))\"}\nq = Query(\"@pickup_zone:[WITHIN $europe]\").dialect(3)\nres = index.search(q, query_params=params_dict)\nprint(res.total) # >>> 5",
      "section_id": "shape"
    }
  ]
}
