Firestore 分页:当使用 orderBy() 降序时,startAfter() 不返回任何数据,但适用于升序

Tra*_*dol 8 html javascript sorting firebase google-cloud-firestore

语境

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

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

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

我正在关注本教程:https://youtu.be/vYBc7Le5G6s? t=797(时间戳记到 orderBy、限制和创建“加载更多”按钮的部分)。

不确定它是否相关,但我最终打算使其成为无限滚动,最好使用相同的教程。

问题

我有一个工作解决方案(与教程完全相同),用于按升序排序(见下文))。它为浏览次数最少的文档创建卡片,当您向下滚动页面时,浏览次数会增加。加载更多按钮会创建接下来的 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());
Run Code Online (Sandbox Code Playgroud)

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

当按降序时间戳排序时,Firestore startAfter() 在无限滚动中返回相同的数据- 无法根据我的情况重构解决方案

如何将 Firestore orderBy desc 与 startAfter 游标结合起来- 无法根据我的情况重构解决方案(这使用 Firebase v8)

Firestore 如何将 orderBy desc 与 startAfter(null) 结合起来- 这建议使用 endBefore 这就是我遇到加载更多加载相同 5 个数据点的问题的方式

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

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

latestDoc =  data.docs[data.docs.length-1]
Run Code Online (Sandbox Code Playgroud)

感谢大家 :)

RJC*_*RJC 2

重新检查有关如何对查询进行分页的Firebase 文档,并遵循此相关帖子中的给定选项:

  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();
Run Code Online (Sandbox Code Playgroud)

结果:

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
Run Code Online (Sandbox Code Playgroud)