{
  "id": "queryjson",
  "title": "Index and query documents",
  "url": "https://redis.io/docs/latest/develop/clients/ruby/queryjson/",
  "summary": "Learn how to use Redis Search with JSON and hash documents.",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-07-31T16:56:30+01:00",
  "page_type": "content",
  "content_hash": "93071fe4256c94ac3f92d26837f2fc14464ed37b24ea4d75810e6f52888be253",
  "sections": [
    {
      "id": "initialize",
      "title": "Initialize",
      "role": "content",
      "text": "Make sure that you have [Redis Open Source](https://redis.io/docs/latest/operate/oss_and_stack/)\nor another Redis server available. Also install the\n[`redis-rb`](https://redis.io/docs/latest/develop/clients/ruby) client library if you\nhaven't already done so.\n\nRequire the `redis` gem. The Query Engine classes live under the\n`Redis::Commands::Search` namespace, so the example below aliases it to\n`Search` to keep the code concise.\n\nFoundational: Require the redis gem and alias the Query Engine namespace\n\n**Difficulty:** Beginner\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]"
    },
    {
      "id": "create-data",
      "title": "Create data",
      "role": "content",
      "text": "Create some test data to add to the database:\n\nFoundational: Define sample user data structures for indexing and querying\n\n**Difficulty:** Beginner\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]"
    },
    {
      "id": "add-the-index",
      "title": "Add the index",
      "role": "content",
      "text": "Connect to your Redis database. The code below shows the most\nbasic connection but see the\n[`redis-rb` guide](https://redis.io/docs/latest/develop/clients/ruby)\nto learn more about the available connection options.\n\nFoundational: Establish a connection to a Redis server for query operations\n\n**Difficulty:** Beginner\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]\n\n\n\nDelete any existing index called `idx:users` and any keys that start with `user:`.\n\nFoundational: Clean up existing indexes and data before creating new indexes\n\n**Difficulty:** Beginner\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]\n\n\n\nCreate an index. In this example, only JSON documents with the key prefix `user:` are indexed. For more information, see [Query syntax](https://redis.io/docs/latest/develop/ai/search-and-query/query/).\n\nBuild the schema with the field type helpers (`text_field`, `tag_field`,\n`numeric_field`) inside a `Search::Schema.build` block. Each field's first\nargument is the [JSON path](https://redis.io/docs/latest/develop/data-types/json/path) to\nthe value, and the `as:` option gives the field an alias you can refer to in\nqueries.\n\nFoundational: Create a search index for JSON documents with field definitions and key prefix filtering\n\n**Difficulty:** Intermediate\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]"
    },
    {
      "id": "add-the-data",
      "title": "Add the data",
      "role": "content",
      "text": "Add the three sets of user data to the database as\n[JSON](https://redis.io/docs/latest/develop/data-types/json) objects.\nIf you use keys with the `user:` prefix then Redis will index the\nobjects automatically as you add them:\n\nFoundational: Store JSON documents in Redis with automatic indexing based on key prefix\n\n**Difficulty:** Beginner\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]"
    },
    {
      "id": "query-the-data",
      "title": "Query the data",
      "role": "content",
      "text": "You can now use the index to search the JSON objects. The\n[query](https://redis.io/docs/latest/develop/ai/search-and-query/query)\nbelow searches for objects that have the text \"Paul\" in any field\nand have an `age` value in the range 30 to 40:\n\nQuery with filters: Search JSON documents using text matching and numeric range filters to find specific records\n\n**Difficulty:** Intermediate\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]\n\n\n\nBecause the index has the key prefix `user:`, the client strips that prefix\nfrom the returned document IDs and reports the logical ID (for example, `3`\nrather than `user:3`).\n\nUse a `Search::Query` object to specify query options, such as returning only\nthe `city` field:\n\nQuery with field projection: Retrieve only specific fields from search results to reduce data transfer\n\n**Difficulty:** Intermediate\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]\n\n\n\nUse an\n[aggregation query](https://redis.io/docs/latest/develop/ai/search-and-query/query/aggregation)\nto count all users in each city.\n\nAggregation query: Group and count results by field values to analyze data patterns\n\n**Difficulty:** Intermediate\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]"
    },
    {
      "id": "differences-with-hash-documents",
      "title": "Differences with hash documents",
      "role": "content",
      "text": "Indexing for hash documents is very similar to JSON indexing but you\nneed to specify some slightly different options.\n\nWhen you create the schema for a hash index, you don't need to\nadd aliases for the fields, since you use the basic names to access\nthe fields anyway. Also, you must use `Search::IndexType::HASH` for the\n`index_type:` option of the `IndexDefinition` when you create the index. The code\nbelow shows these changes with a new index called `hash-idx:users`, which is\notherwise the same as the `idx:users` index used for JSON documents in the\nprevious examples.\n\nFirst, delete any existing index called `hash-idx:users` and any keys that start with `huser:`.\n\nFoundational: Clean up existing hash indexes and data before creating new indexes\n\n**Difficulty:** Beginner\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]\n\n\n\nNow create the new index:\n\nFoundational: Create a search index for hash documents with field definitions and key prefix filtering\n\n**Difficulty:** Intermediate\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]\n\n\n\nUse [`hset()`](https://redis.io/docs/latest/commands/hset) to add the hash\ndocuments instead of [`json_set()`](https://redis.io/docs/latest/commands/json.set).\n\nFoundational: Store hash documents in Redis with automatic indexing based on key prefix\n\n**Difficulty:** Beginner\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]\n\n\n\nThe query commands work the same here for hash as they do for JSON (but\nthe name of the hash index is different). The results are returned as\n`Document` objects, as with JSON:\n\nQuery with filters: Search hash documents using text matching and numeric range filters (same as JSON queries)\n\n**Difficulty:** Intermediate\n\n**Available in:** Ruby\n\n##### Ruby\n\n[code example]"
    },
    {
      "id": "more-information",
      "title": "More information",
      "role": "content",
      "text": "See the [Redis Search](https://redis.io/docs/latest/develop/ai/search-and-query) docs\nfor a full description of all query features with examples."
    }
  ],
  "examples": [
    {
      "id": "initialize-ex0",
      "language": "ruby",
      "code": "require 'redis'\n\n# A short alias for the Query Engine namespace to keep the code below readable.\nSearch = Redis::Commands::Search",
      "section_id": "initialize"
    },
    {
      "id": "create-data-ex0",
      "language": "ruby",
      "code": "user1 = {\n  'name' => 'Paul John',\n  'email' => 'paul.john@example.com',\n  'age' => 42,\n  'city' => 'London'\n}\n\nuser2 = {\n  'name' => 'Eden Zamir',\n  'email' => 'eden.zamir@example.com',\n  'age' => 29,\n  'city' => 'Tel Aviv'\n}\n\nuser3 = {\n  'name' => 'Paul Zamir',\n  'email' => 'paul.zamir@example.com',\n  'age' => 35,\n  'city' => 'Tel Aviv'\n}",
      "section_id": "create-data"
    },
    {
      "id": "add-the-index-ex0",
      "language": "ruby",
      "code": "r = Redis.new",
      "section_id": "add-the-index"
    },
    {
      "id": "add-the-index-ex1",
      "language": "ruby",
      "code": "begin\n  r.ft_dropindex('idx:users', delete_documents: true)\nrescue Redis::CommandError\n  # Index doesn't exist, so there is nothing to drop.\nend\n\nr.del('user:1', 'user:2', 'user:3')",
      "section_id": "add-the-index"
    },
    {
      "id": "add-the-index-ex2",
      "language": "ruby",
      "code": "schema = Search::Schema.build do\n  text_field '$.name', as: 'name'\n  tag_field '$.city', as: 'city'\n  numeric_field '$.age', as: 'age'\nend\n\ndefinition = Search::IndexDefinition.new(\n  prefix: ['user:'],\n  index_type: Search::IndexType::JSON\n)\n\nindex = r.create_index('idx:users', schema, definition: definition)\nputs index.name # >>> idx:users",
      "section_id": "add-the-index"
    },
    {
      "id": "add-the-data-ex0",
      "language": "ruby",
      "code": "user1_set = r.json_set('user:1', '$', user1)\nuser2_set = r.json_set('user:2', '$', user2)\nuser3_set = r.json_set('user:3', '$', user3)\nputs [user1_set, user2_set, user3_set].inspect # >>> [\"OK\", \"OK\", \"OK\"]",
      "section_id": "add-the-data"
    },
    {
      "id": "query-the-data-ex0",
      "language": "ruby",
      "code": "find_paul_result = index.search('Paul @age:[30 40]')\n\nputs find_paul_result.total # >>> 1\n# The index has the key prefix `user:`, so the client returns the\n# logical document id with that prefix removed.\nfind_paul_result.each { |doc| puts doc.id } # >>> 3",
      "section_id": "query-the-data"
    },
    {
      "id": "query-the-data-ex1",
      "language": "ruby",
      "code": "cities_query = Search::Query.new('Paul').return_field('$.city', as_field: 'city')\ncities_result = index.search(cities_query)\n\ncities_result.documents.sort_by(&:id).each do |doc|\n  puts \"#{doc.id}: #{doc['city']}\"\nend\n# >>> 1: London\n# >>> 3: Tel Aviv",
      "section_id": "query-the-data"
    },
    {
      "id": "query-the-data-ex2",
      "language": "ruby",
      "code": "request = Search::AggregateRequest.new('*')\n                                  .group_by('@city', Search::Reducers.count.as('count'))\n\nagg_result = index.aggregate(request)\n\nagg_result.rows.sort_by { |row| row['city'] }.each do |row|\n  puts \"#{row['city']} - #{row['count']}\"\nend\n# >>> London - 1\n# >>> Tel Aviv - 2",
      "section_id": "query-the-data"
    },
    {
      "id": "differences-with-hash-documents-ex0",
      "language": "ruby",
      "code": "begin\n  r.ft_dropindex('hash-idx:users', delete_documents: true)\nrescue Redis::CommandError\n  # Index doesn't exist, so there is nothing to drop.\nend\n\nr.del('huser:1', 'huser:2', 'huser:3')",
      "section_id": "differences-with-hash-documents"
    },
    {
      "id": "differences-with-hash-documents-ex1",
      "language": "ruby",
      "code": "hash_schema = Search::Schema.build do\n  text_field 'name'\n  tag_field 'city'\n  numeric_field 'age'\nend\n\nhash_definition = Search::IndexDefinition.new(\n  prefix: ['huser:'],\n  index_type: Search::IndexType::HASH\n)\n\nhash_index = r.create_index('hash-idx:users', hash_schema, definition: hash_definition)\nputs hash_index.name # >>> hash-idx:users",
      "section_id": "differences-with-hash-documents"
    },
    {
      "id": "differences-with-hash-documents-ex2",
      "language": "ruby",
      "code": "huser1_set = r.hset('huser:1', user1)\nhuser2_set = r.hset('huser:2', user2)\nhuser3_set = r.hset('huser:3', user3)\nputs [huser1_set, huser2_set, huser3_set].inspect # >>> [4, 4, 4]",
      "section_id": "differences-with-hash-documents"
    },
    {
      "id": "differences-with-hash-documents-ex3",
      "language": "ruby",
      "code": "find_paul_hash_result = hash_index.search('Paul @age:[30 40]')\n\nputs find_paul_hash_result.total # >>> 1\nfind_paul_hash_result.each do |doc|\n  puts \"#{doc.id}: #{doc['name']}, #{doc['city']}\"\nend\n# >>> 3: Paul Zamir, Tel Aviv",
      "section_id": "differences-with-hash-documents"
    }
  ]
}
