{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Indexing / querying JSON documents\n",
    "## Adding a JSON document to an index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'OK'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import valkey\n",
    "from valkey.commands.json.path import Path\n",
    "import valkey.commands.search.aggregation as aggregations\n",
    "import valkey.commands.search.reducers as reducers\n",
    "from valkey.commands.search.field import TextField, NumericField, TagField\n",
    "from valkey.commands.search.indexDefinition import IndexDefinition, IndexType\n",
    "from valkey.commands.search.query import NumericFilter, Query\n",
    "\n",
    "\n",
    "r = valkey.Valkey(host='localhost', port=6379)\n",
    "user1 = {\n",
    "    \"user\":{\n",
    "        \"name\": \"Paul John\",\n",
    "        \"email\": \"paul.john@example.com\",\n",
    "        \"age\": 42,\n",
    "        \"city\": \"London\"\n",
    "    }\n",
    "}\n",
    "user2 = {\n",
    "    \"user\":{\n",
    "        \"name\": \"Eden Zamir\",\n",
    "        \"email\": \"eden.zamir@example.com\",\n",
    "        \"age\": 29,\n",
    "        \"city\": \"Tel Aviv\"\n",
    "    }\n",
    "}\n",
    "user3 = {\n",
    "    \"user\":{\n",
    "        \"name\": \"Paul Zamir\",\n",
    "        \"email\": \"paul.zamir@example.com\",\n",
    "        \"age\": 35,\n",
    "        \"city\": \"Tel Aviv\"\n",
    "    }\n",
    "}\n",
    "\n",
    "user4 = {\n",
    "    \"user\":{\n",
    "        \"name\": \"Sarah Zamir\",\n",
    "        \"email\": \"sarah.zamir@example.com\",\n",
    "        \"age\": 30,\n",
    "        \"city\": \"Paris\"\n",
    "    }\n",
    "}\n",
    "r.json().set(\"user:1\", Path.root_path(), user1)\n",
    "r.json().set(\"user:2\", Path.root_path(), user2)\n",
    "r.json().set(\"user:3\", Path.root_path(), user3)\n",
    "r.json().set(\"user:4\", Path.root_path(), user4)\n",
    "\n",
    "schema = (TextField(\"$.user.name\", as_name=\"name\"),TagField(\"$.user.city\", as_name=\"city\"), NumericField(\"$.user.age\", as_name=\"age\"))\n",
    "r.ft().create_index(schema, definition=IndexDefinition(prefix=[\"user:\"], index_type=IndexType.JSON))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Searching"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Simple search"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Result{2 total, docs: [Document {'id': 'user:1', 'payload': None, 'json': '{\"user\":{\"name\":\"Paul John\",\"email\":\"paul.john@example.com\",\"age\":42,\"city\":\"London\"}}'}, Document {'id': 'user:3', 'payload': None, 'json': '{\"user\":{\"name\":\"Paul Zamir\",\"email\":\"paul.zamir@example.com\",\"age\":35,\"city\":\"Tel Aviv\"}}'}]}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r.ft().search(\"Paul\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Filtering search results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Result{1 total, docs: [Document {'id': 'user:3', 'payload': None, 'json': '{\"user\":{\"name\":\"Paul Zamir\",\"email\":\"paul.zamir@example.com\",\"age\":35,\"city\":\"Tel Aviv\"}}'}]}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q1 = Query(\"Paul\").add_filter(NumericFilter(\"age\", 30, 40))\n",
    "r.ft().search(q1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Paginating and Ordering search Results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Result{4 total, docs: [Document {'id': 'user:1', 'payload': None, 'age': '42', 'json': '{\"user\":{\"name\":\"Paul John\",\"email\":\"paul.john@example.com\",\"age\":42,\"city\":\"London\"}}'}, Document {'id': 'user:3', 'payload': None, 'age': '35', 'json': '{\"user\":{\"name\":\"Paul Zamir\",\"email\":\"paul.zamir@example.com\",\"age\":35,\"city\":\"Tel Aviv\"}}'}]}"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Search for all users, returning 2 users at a time and sorting by age in descending order\n",
    "offset = 0\n",
    "num = 2\n",
    "q = Query(\"*\").paging(offset, num).sort_by(\"age\", asc=False) # pass asc=True to sort in ascending order\n",
    "r.ft().search(q)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Counting the total number of Items"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q = Query(\"*\").paging(0, 0)\n",
    "r.ft().search(q).total"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Projecting using JSON Path expressions "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Document {'id': 'user:1', 'payload': None, 'city': 'London'},\n",
       " Document {'id': 'user:3', 'payload': None, 'city': 'Tel Aviv'}]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r.ft().search(Query(\"Paul\").return_field(\"$.user.city\", as_field=\"city\")).docs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Aggregation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[b'age', b'35'], [b'age', b'42']]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "req = aggregations.AggregateRequest(\"Paul\").sort_by(\"@age\")\n",
    "r.ft().aggregate(req).rows"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Count the total number of Items"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[b'total', b'4']]"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# The group_by expects a string or list of strings to group the results before applying the aggregation function to\n",
    "# each group. Passing an empty list here acts as `GROUPBY 0` which applies the aggregation function to the whole results\n",
    "req = aggregations.AggregateRequest(\"*\").group_by([], reducers.count().alias(\"total\"))\n",
    "r.ft().aggregate(req).rows"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "d45c99ba0feda92868abafa8257cbb4709c97f1a0b5dc62bbeebdf89d4fad7fe"
  },
  "kernelspec": {
   "display_name": "valkey-py",
   "language": "python",
   "name": "valkey-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
