繁体   English   中英

dynamoDB / aws-amplify - 使用“limit”+“filter”进行查询 - 返回一半为空或完全为空的页面,并且不包含数量为“limit”的项目

[英]dynamoDB / aws-amplify - Query with 'limit' + 'filter' - returns half empty or completely empty pages and not full with items with 'limit' amount

代码示例:

import { API, graphqlOperation } from "aws-amplify"

const fetchInitialAds = () => {
  const { filterAttributes } = useContext(FilterContext)

  const {
    query: { slug },
  } = useRouter()

  const fetchAds = async ({ pageParam = null }) => {

  const {
    deal_type,
    priceFrom,
    priceTo,
  } = filterAttributes

  const currTimeInSeconds = Math.ceil(Date.now() / 1000)

  const options = {
    subcategoryID: `SUBCATEGORY#${slug}`,
    sortDirection: "DESC",
    limit: 24,
    nextToken: pageParam,

    filter: {
      and: [
        {
          or: [
            {
              list_price: {
                between: [
                  Number(priceFrom) || 0,
                  Number(priceTo) || 100000000,
                ],
              },
            },
            {
              new_price: {
                between: [
                  Number(priceFrom) || 0,
                  Number(priceTo) || 100000000,
                ],
              },
            },
          ],
        },
      ],
    },
  }

  const adsResult = await API.graphql(
    graphqlOperation(adsBySubcategoryByExpdate, options)
  )

  const data = await adsResult.data.adsBySubcategoryByExpdate

  return data
}

  return useInfiniteQuery(["ads", slug], fetchAds, {
    getNextPageParam: (currentPage, allPages) => currentPage.nextToken,
  })
}

在大数据库上使用“限制”+“过滤器”的“查询”问题,例如其中有 5000 个项目。 如果您限制一次显示 24 个项目(用于分页),“过滤器”表达式将仅过滤表格中的前 24 个项目并返回匹配的项目。 如果您对 24 个第一个项目中的 5 个进行过滤器匹配,它将仅返回这 5 个项目... <- 这意味着您要为客户显示的第一页将不包含 24 个项目,而只有 5 个项目.. .然后您需要使用“nextToken”再次过滤接下来的 24 个项目。 这次你可能会得到 10 个匹配的项目。 所以现在您只为客户显示 16 个项目(仍然不是 24 个项目的整页......)。 假设第三次运行接下来的 24 个项目,你得到 0 个匹配的项目 <-- 你不会得到任何新项目来展示你的客户。 这会让人感觉很奇怪——你点击按钮来获取接下来的 24 个项目,但得到了 0 个项目,你必须继续点击那个按钮,直到它点击一些新的匹配项目,直到你浏览了整个表格……

所以我的问题是:是否有一个解决方案,如果你限制 24 个项目,以便 dynamo db 收集 24 个匹配项目的完整列表,然后才返回整页? 我不想得到半满的页面并向我的“获取更多”按钮发送垃圾邮件,看看我是否没有错过任何其他过滤器匹配的项目......

Query操作首先读取一页数据(1MB 数据,如果您指定了该参数,则为Limit rows),然后才对其进行过滤,这一事实是经过深思熟虑并记录在案的:

单个Query操作将读取最多设置的项目数(如果使用Limit参数)或最多 1 MB 的数据,然后使用FilterExpression对结果应用任何过滤。 ...如果为结果页面读取的所有项目都被过滤掉,则Query操作可以返回空结果集和LastEvaluatedKey

这种设计的原因是它限制了每个请求的延迟成本:想象一下这样一种情况,在一个 1 TB 的数据库中,您运行一个带有仅匹配 5 个项目的过滤器的查询。 如果查询要继续直到它可以返回 5 个项目,它可能会在返回任何内容之前读取 1 TB 的数据 - 这将导致巨大的延迟(客户端很可能会假设连接断开并在获得响应之前断开连接...... ),以及巨大的成本。 通过每次数据库读取 1 MB 数据时返回一个空页,客户端可以知道查询正在进行并且不会超时 - 并且还可以知道此查询的成本并有机会停止它。

可以想象一个更好的 API,它包括要阅读的项目数量的限制和对要返回的项目的限制,只要达到其中一个限制,页面就会结束。 不幸的是,DynamoDB 没有这样的 API。正如您所注意到的,如果没有返回足够的结果,您将被迫使用Limit并重试。

如果您认为匹配结果均匀分布在项目之间,您可以尝试“猜测”Limit 应该有多大才能大致产生正确数量的结果 - 您可以在 go 的过程中改进这个猜测。 猜测太低的 Limit 只意味着你需要发出第二个查询,而猜测太高的 Limit 只意味着你会阅读太多(并且付出太多),但无论哪种情况都是(通常)不是灾难。 在任何情况下,您都不需要用户点击来获得更多结果——您可以在代码内部完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM