redis-om-python
redis-om-python copied to clipboard
Unable to index a `HashModel` field in a `JsonModel`.
Storing works, but querying doesn't work. Take the following as an example:
from typing import Optional, Any
from fastapi import FastAPI
from pydantic import BaseModel, Field as PydanticField, EmailStr
import datetime
from aredis_om import (
Field,
HashModel,
JsonModel,
Migrator,
get_redis_connection
)
redis_conn = get_redis_connection(
url=f"redis://localhost:6379",
decode_responses=True
)
class User(HashModel):
first_name: Optional[str] = Field(index=True)
last_name: Optional[str] = Field(index=True)
email: EmailStr = Field(index=True)
password: str = Field(index=True)
created_on: Optional[datetime.datetime] = Field(default_factory=datetime.datetime.now)
class Meta:
database = redis_conn
class Contact(JsonModel):
user: User = Field(index=True)
contact: User = Field(index=True)
favourite: Optional[str] = Field(index=True, default=False)
created_on: Optional[datetime.datetime] = Field(default_factory=datetime.datetime.now)
class Meta:
database = redis_conn
router = FastAPI(title=__name__)
@router.on_event("startup")
async def startup():
await Migrator().run()
user1 = await User(email="[email protected]", password="S3C11R3P@ssW0rD").save()
user2 = await User(email="[email protected]", password="P@ssW0rD").save()
contact = await Contact(user=user1, contact=user2).save()
contact = await Contact.find(Contact.user == user1).all() # <------------------- This query will fail
Running the above code uvicorn your_file_name:router --reload
will generate the following exception:
return self.escaped_chars_re.sub(escape_symbol, value)
TypeError: expected string or bytes-like object
Is there any way to index such a field?
Edit
Another question related to a field that contains a list of HashModel
instances like the following:
class Contact(JsonModel):
user: User = Field(index=True)
contacts: list[User] = Field(index=True)
favourite: Optional[str] = Field(index=True, default=False)
created_on: Optional[datetime.datetime] = Field(default_factory=datetime.datetime.now)
class Meta:
database = redis_conn
Quoting from the docs:
Redis Hashes can’t store nested containers like Lists, Sets, or other Hashes, so this doesn’t work.
So, it seems like it is not possible to store lists of HashModel
. However, i built some custom logic to dynamically build a list from all the records. Another workaround would be to store the emails of users in the contact rather than a user reference:
class Contact(JsonModel):
user: EmailStr = Field(index=True)
contacts: list[EmailStr] = Field(index=True)
favourite: Optional[str] = Field(index=True, default=False)
created_on: Optional[datetime.datetime] = Field(default_factory=datetime.datetime.now)
class Meta:
database = redis_conn
I think this would work, however it stores redundant information. The efficient way, i believe, is to store a reference for each user, a HashModel
instance.