【问题标题】:Firestore pagination: startAfter() returning no data when when using orderBy() descending, but working for ascendingFirestore 分页:startAfter() 使用 orderBy() 降序时不返回数据,但适用于升序
【发布时间】:2022-01-31 12:05:26
【问题描述】:

上下文

这里是第一个问题,所以提前谢谢大家,如果您需要其他任何东西来帮助回答我的问题,请告诉我!

我正在创建 HTML 卡片的排序列表。这些卡片从 Firestore 文档中提取数据,每个文档都有元数据:numViews 和 summary。

我一次加载 5 张卡片的分页数据,并且想要一个“加载更多”按钮来显示接下来的 5 张卡片。

我正在关注本教程:https://youtu.be/vYBc7Le5G6s?t=797(在 orderBy、limit 和创建 Load More 按钮上加盖时间戳)。

不确定它是否相关,但我最终打算制作一个无限滚动,最好使用相同的教程。

问题

我有一个按升序排序的工作解决方案(与教程完全相同)(见下文)。它为查看次数最少的文档创建卡片,当您向下滚动页面时,查看次数会增加。加载更多按钮会创建接下来的 5 张卡片。

当我更改为 orderBy() 降序时,不会加载任何卡片。 当我将分页从 startAfter() 更改为 endBefore() 和 orderBy(descending) 时,它会通过正确降序(从最高视图开始,向下滚动页面时降序)对前 5 个进行排序,但加载更多按钮只是重新加载相同的 5 张卡片,而不是接下来的 5 张卡片。

这是我的代码

// References an empty container where my cards go
const container = document.querySelector('.containerload');

// Store last document
let latestDoc = null;

const getNextReviews = async () => {
  // WORKING ascending
  var load = query(colRef, orderBy('numViews', 'asc'), startAfter(latestDoc || 0), limit(5))

  // BROKEN descending - returns nothing
  // var load = query(colRef, orderBy('numViews', 'desc'), startAfter( latestDoc || 0), limit(5))

  // HALF-BROKEN descending - returns 5 cards with highest views, but load more returns the same 5
  // var load = query(colRef, orderBy('numViews', 'desc'), endBefore(latestDoc || 0), limit(5))

  const data = await getDocs(load);

  // Output docs
  let template = '';
  data.docs.forEach(doc => {
    const grabData = doc.data();
    template += `
    <div class="card">
      <h2>${grabData.summary}</h2>
      <p>Views ${grabData.numViews}</p>
    </div>
    `
  });
  container.innerHTML += template; 

  // Update latestDoc
  latestDoc =  data.docs[data.docs.length-1]

  // Unattach event listeners if no more documents
  if (data.empty) {
    loadMore.removeEventListener('click',handleClick)
  }

}

// Load more docs (button)
const loadMore = document.querySelector('.load-more button');

const handleClick = () => {
  getNextReviews();
  console.log(latestDoc);
}

loadMore.addEventListener('click', handleClick);

// wait for DOM content to load
window.addEventListener('DOMContentLoaded', () => getNextReviews());

我查看了许多类似的问题,但无法找到有效的解决方案:

Firestore startAfter() returning the same data in infinite scrolling when ordered by descending timestamp - 无法根据我的情况重构解决方案

How to combine Firestore orderBy desc with startAfter cursor - 无法根据我的情况重构解决方案(这使用 Firebase v8)

Firestore how to combine orderBy desc with startAfter(null) - 这建议使用 endBefore,这就是我遇到 Load More 加载相同 5 个数据点的问题

我不确定为什么 orderBy('numViews', 'desc') 和 startAfter() 什么都不返回。

我认为 orderBy('numViews', 'desc') 和 endBefore() 返回相同的 5,因为它只是获取在 latestDoc 之前结束的 5 个文档,这不会更改为光标向下的 5 个文档。我尝试过使用这一行,但无法加载接下来的 5 个文档:

latestDoc =  data.docs[data.docs.length-1]

谢谢大家:)

【问题讨论】:

  • 您是否在 paginating a query 上查看过此 Firebase 文档?
  • 感谢您的评论!我浏览了文档的这一部分,这帮助我获得了一个按升序排序的工作解决方案。看起来文档没有 orderBy 降序和分页的解决方案。

标签: javascript html firebase sorting google-cloud-firestore


【解决方案1】:

在重新检查有关如何paginate a query 的 Firebase 文档并遵循此相关post 中的给定选项后:

  1. 使用 Firebase 查询获取正确的数据,然后在客户端重新排序
  2. 向数据中添加一个具有降序值的字段

如果你只添加像timestamp这样的字段会更容易,例如:

Firestore 集合:

代码:

import { initializeApp } from "firebase/app";
import { getFirestore, collection, query, getDocs, orderBy, startAfter, limit } from "firebase/firestore";

const firebaseConfig = {
    projectId: "PROJECT-ID"
};

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const q = query(collection(db, "users"));

const getNextReviews = async () => {
    // For this example, there's only 6 data
    // Query the first 5 data
    var load = query(q, 
        orderBy("timestamp", "desc"), 
        limit(5))
    
    // Retrieve the first 5 data
    const data = await getDocs(load);

    // Update latestDoc reference 
    const latestDoc =  data.docs[data.docs.length-1]

    // To output the retrieved first 5 data
    data.forEach((doc) => {
        // doc.data() is never undefined for query doc snapshots
        console.log("First: ", doc.data().first_name , " => ", doc.data().timestamp.toDate());
    });

    // Query the next data or remaining data 
    var next = query(q,
        orderBy("timestamp", "desc"),
        startAfter(latestDoc),
        limit(5));
        
    // Automatically pulls the remaining data in the collection
    const data_next = await getDocs(next);
        
    // Outputs the remaining data in the collection
    data_next.forEach((doc) => {
        // doc.data() is never undefined for query doc snapshots
        console.log("Second: ", doc.data().first_name , " => ", doc.data().timestamp.toDate());
    });
}

// You can add the other conditions for 'load-more button' in here
getNextReviews();

结果:

First:  bob  =>  2022-01-30T16:00:00.000Z
First:  mike  =>  2022-01-29T16:00:00.000Z
First:  teddy  =>  2022-01-26T16:00:00.000Z
First:  grace  =>  2022-01-25T16:00:00.000Z
First:  john  =>  2022-01-23T16:00:00.000Z
Second:  lory  =>  2022-01-19T16:00:00.000Z

【讨论】:

  • 请问您如何在客户端重新排序?
  • 我已经更新了我的答案并提供了一个你可以检查的代码。
  • 这行得通!我现在有 2 个工作选项:[1]。为每个文档创建了一个新字段,即 -1*numViews。这很 hacky,不确定它是否适合我的扩展需求,但它适用于我的 MVP!它还具有仅调用数组中的 6 个项目的好处,而不是所有 db 条目 - 因此更具成本效益。 [2]。我按照您的建议修改了将函数分成两部分(getFirstReviews 和 getNextReviews)。您的解决方案适用于前 6 条评论,接下来的 6 条评论有效,但无法获得第三条 6 条评论。非常感谢!
猜你喜欢
  • 2021-02-20
  • 1970-01-01
  • 1970-01-01
  • 2019-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多