J'ai une API REST simple qui est une librairie créée avec FastAPI et mongo db comme backend (j'ai utilisé Motor
comme bibliothèque au lieu de Pymongo
). J'ai un GET
point de terminaison pour obtenir tous les livres de la base de données qui prend également en charge les chaînes de requête (par exemple: un utilisateur peut rechercher des livres avec un seul auteur ou avec un type de genre, etc.).
Vous trouverez ci-dessous les codes correspondants pour ce point de terminaison :routers.py
@router.get("/books", response_model=List[models.AllBooksResponse])
async def get_the_list_of_all_books(
authors: Optional[str] = None,
genres: Optional[str] = None,
published_year: Optional[str] = None,
) -> List[Dict[str, Any]]:
if authors is None and genres is None and published_year is None:
all_books = [book for book in await mongo.BACKEND.get_all_books()]
else:
all_books = [
book
for book in await mongo.BACKEND.get_all_books(
authors=authors.strip('"').split(",") if authors is not None else None,
genres=genres.strip('"').split(",") if genres is not None else None,
published_year=datetime.strptime(published_year, "%Y")
if published_year is not None
else None,
)
]
return all_books
Le modèle correspondant:
class AllBooksResponse(BaseModel):
name: str
author: str
link: Optional[str] = None
def __init__(self, name, author, **data):
super().__init__(
name=name, author=author, link=f"{base_uri()}book/{data['book_id']}"
)
Et la fonction backend pour obtenir les données :
class MongoBackend:
def __init__(self, uri: str) -> None:
self._client = motor.motor_asyncio.AsyncIOMotorClient(uri)
async def get_all_books(
self,
authors: Optional[List[str]] = None,
genres: Optional[List[str]] = None,
published_year: Optional[datetime] = None,
) -> List[Dict[str, Any]]:
find_condition = {}
if authors is not None:
find_condition["author"] = {"$in": authors}
if genres is not None:
find_condition["genres"] = {"$in": genres}
if published_year is not None:
find_condition["published_year"] = published_year
cursor = self._client[DB][BOOKS_COLLECTION].find(find_condition, {"_id": 0})
return [doc async for doc in cursor]
Maintenant, je veux implémenter la pagination pour ce point de terminaison. Ici j'ai quelques questions:
limit
et skip
) fonctionnerait pour moi, car je veux également le faire fonctionner lorsque j'utilise d'autres paramètres de filtre (par exemple pour l'auteur et le genre) et il n'y a aucun moyen de connaître les ObjectId à moins que je fasse la première requête à obtenir les données et ensuite je veux faire la pagination.Mais le problème est partout où je vois utiliser limit
et skip
est découragé.
Quelqu'un peut-il me faire savoir quelles sont les meilleures pratiques ici et quelque chose peut-il s'appliquer à mes besoins et à mon cas d'utilisation ?
Merci d'avance.
Solution du problème
Il n'y a pas de bonne ou de mauvaise réponse à une telle question. Cela dépend beaucoup de la pile technologique que vous utilisez, ainsi que du contexte dont vous disposez, compte tenu également des orientations futures du logiciel que vous avez écrit ainsi que du logiciel que vous utilisez (mongo).
Répondre à vos questions:
Cela dépend de la charge que vous devez gérer et de la pile de développement que vous utilisez. Habituellement, cela se fait au niveau de la base de données, car récupérer les 110 premiers et supprimer les 100 premiers est assez stupide et consomme des ressources (la base de données le fera pour vous).
Pour moi, c'est assez simple sur la façon de le faire via fastapi
: il suffit d'ajouter à votre get
fonction les paramètres limit: int = 10
et skip: int = 0
de les utiliser dans la fonction de filtrage de votre base de données. Fastapi
vérifiera les types de données pour vous, tandis que vous pourrez vérifier que la limite n'est pas négative ou supérieure, par exemple, à 100.
Il dit qu'il n'y a pas de solution miracle et que puisque skip
la fonction de mongo ne fonctionne pas bien. Ainsi, il pense que la deuxième option est meilleure, juste pour les performances. Si vous avez des milliards et des milliards de documents (par exemple amazon), eh bien, il peut être judicieux d'utiliser quelque chose de différent, bien qu'au moment où votre site Web aura autant grandi, je suppose que vous aurez l'argent pour payer toute une équipe de des experts pour faire le tri et éventuellement développer votre propre base de données.
TL ; RD
En conclusion, l' approche limit
et skip
est la plus courante. Cela se fait généralement au niveau de la base de données, afin de réduire la quantité de travail de l'application et la bande passante.
Mongo n'est pas très efficace pour sauter et limiter les résultats. Si votre base de données contient, disons, un million de documents, je ne pense pas que vous le remarquerez même. Vous pouvez même utiliser une base de données relationnelle pour une telle charge de travail. Vous pouvez toujours comparer les options dont vous disposez et choisir la plus appropriée.
Je ne connais pas grand-chose à mongo, mais je sais qu'en général, les index peuvent aider à limiter et à ignorer les enregistrements (docs dans ce cas), mais je ne sais pas si c'est également le cas pour mongo.
Aucun commentaire:
Enregistrer un commentaire