如何用mongo db(Motor)实现fastapi分页

mongodb pagination pymongo restapi fastapi

我有一个简单的restapi,它是一个以FastAPI和mongodb为后端创建的书店(我使用了Motor作为库,而不是Pymongo)。我有一个GET端点来获取数据库中的所有书籍,它还支持查询字符串(例如:用户可以搜索具有单个作者或流派类型的书籍等)。

下面是这个端点的对应代码: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

对应型号:

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']}"
        )

以及获取数据的后端函数:

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]

现在我要实现这个端点的分页。这里我有几个问题:

  1. 在数据库级或应用程序级进行分页是好的吗?
  2. 我们有一些现成的库可以帮助我在fastapi中做到这一点吗?我查看了文档中的https://pypi.org/project/fastapi-pagination/,但这似乎更针对SQL数据库
  3. 我还查看了这个链接:https://www.codementor.io/@arpitbhayani/fast-and-efficient-pagination-in-mongodb-9095flbqr,它讨论了在mongodb中执行此操作的不同方法,但我认为只有第一个选项(使用limitskip)对我有效,因为当我使用其他过滤器参数(例如author和genre)时,我也想让它工作,除非我进行第一次查询以获取数据,然后我想进行分页,否则我不可能知道ObjectId。

但是这个问题在我看到的任何地方都存在,使用limitskip都是不鼓励的。

这样的问题没有对错之分。很大程度上取决于您所使用的技术堆栈,以及您所拥有的上下文,同时考虑到您所编写的软件以及您所使用的软件(mongo)的未来发展方向。

回答您的问题:

  1. 这取决于您必须管理的负载和您使用的dev堆栈。通常它是在数据库级别完成的,因为检索前110并删除前100是非常愚蠢和消耗资源的(数据库将为您完成)。
  2. 在我看来,如何通过fastapi实现这一点似乎很简单:只需将参数limit: int = 10skip: int = 0添加到get函数中,并在数据库的过滤函数中使用它们Fastapi将为您检查数据类型,而您可以检查限制是否为负或大于100。
  3. 它说没有银弹,因为mongo的skip函数没有很好的执行。因此,他认为第二种选择更好,只是为了表现。如果你有成百上千万的文档(比如amazon),那么,可能会使用一些不同的东西,尽管当你的网站发展到这样的程度时,我猜你会有足够的钱支付整个专家团队来整理这些东西,并可能开发你自己的数据库。

最后,最常见的方法是limitskip。它通常在数据库级别完成,以减少应用程序的工作量和带宽。

Mongo在跳过和限制结果方面效率不高。如果你的数据库有,比如说一百万个文档,那么我想你根本不会注意到。对于这样的工作负载,您甚至可以使用关系数据库。您可以随时对现有的选项进行基准测试,并选择最合适的选项。

我对mongo了解不多,但我知道,一般来说,索引可以帮助限制和跳过记录(本例中是文档),但我不确定mongo是否也是这样。

 

MongoRepository 是 Spring Data MongoDB 提供的一种 Repository 接口,用于简化 MongoDB 数据库的操作。 要实现分页查询,可以使用 MongoRepository 接口提供的一些分页查询方法,例如: ```java public interface UserRepository extends MongoRepository<User, String> { Page<User> findAll(Pageable pageable); Page<User> findByAgeGreaterThan(int age, Pageable pageable); // 其他自定义查询方法 } ``` 其中,`Pageable` 是 Spring Data 提供的一个分页请求参数接口,包含了分页查询的页码、每页数据量、排序方式等信息。 使用时,可以将 `Pageable` 对象作为参数传入分页查询方法中: ```java Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by("age").descending()); Page<User> users = userRepository.findByAgeGreaterThan(18, pageable); ``` 上述代码中,`PageRequest.of()` 方法用于创建 `Pageable` 对象,包含了当前页码、每页数据量和按年龄倒序排序的排序方式,然后调用 `findByAgeGreaterThan()` 方法进行分页查询。 查询结果为 `Page<User>` 类型,包含了当前页的数据和总页数等信息。可以通过 `Page` 对象的方法获取分页信息: ```java users.getContent(); // 当前页的数据列表 users.getTotalElements(); // 总数据量 users.getTotalPages(); // 总页数 users.getNumber(); // 当前页码 users.getSize(); // 每页数据量 users.hasNext(); // 是否有下一页 users.hasPrevious(); // 是否有上一页 ``` 以上就是使用 MongoRepository 实现分页查询的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值