1

由于我不是 JS 专家,因此对解决这个问题感到沮丧。

我使用 Firestore 作为数据库,使用 VuexFire 将数据绑定到 VueX 状态,就像这样。

 getLeads: firestoreAction(async ({
        bindFirestoreRef
    }) => {
        // return the promise returned by `bindFirestoreRef`
        return bindFirestoreRef('leads', db.collection('leads').orderBy('updated.date', 'desc').limit(30))
    }),
它获得前 30 个结果,然后我想实现一个无限滚动功能,以在每次滚动到达底部时运行一个函数并获取更多数据并绑定到相同的状态。在 Firestore 中,分页需要将最后获取的文档的查询游标作为参考传递

下面来自 firebase 文档,带有 vanilla JS

var first = db.collection("cities")
        .orderBy("population")
        .limit(25);

return first.get().then(function (documentSnapshots) {
  // Get the last visible document
  var lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
  console.log("last", lastVisible);

  // Construct a new query starting at this document,
  // get the next 25 cities.
  var next = db.collection("cities")
          .orderBy("population")
          .startAfter(lastVisible)
          .limit(25);
});
因为我使用 VuexFire 将数据绑定到状态,所以我没有看到一个选项来获取 VuexFire 获取的最后一个文档的快照(来自上述代码的 lastVisible),以便将其传递给下一个查询。

任何帮助将不胜感激。

4

3 回答 3

4

假设我有一组客户记录,我正在显示最后更新的前 5 条记录。

查询是

getLeads: firestoreAction(({ commit, bindFirestoreRef
}) => {
    bindFirestoreRef('Leads', db.collection('leads')
   .orderBy('updated.date', 'desc').limit(5)).then(documents => {
        commit('POPULATE_TESTLEADS', documents);
        commit('LAST_DOC', documents[documents.length - 1]);
    });

}),

我将结果和 lastdoc 都保存在状态中,循环显示名称,如下所示:

Nakheel
Emaar Group
Yapi Kredi Inc
Cairo Amman Bank
Arab Jordan Investment Bank LLC

然后我再次调用最后一个文档作为查询光标,并期望接下来的 5 个文档从 firebase 返回,就像这样

moreLeadLeads: firestoreAction(({ state, bindFirestoreRef
}) => {
    bindFirestoreRef('testLeads', db.collection('leads')
    .orderBy('updated.date', 'desc')
   .startAfter(state.lastDoc).limit(5))
}),

但是我从 firestore 得到了与上面相同的 5 个结果。我究竟做错了什么?:(

于 2019-11-21T16:16:41.710 回答
3

在内部,VueFire 和 VuexFire 使用一个serializer函数将 RTDB 或 Firestore 返回的每个 Document 映射到绑定到最终组件或 Vuex 存储状态的数据对象中。

默认serializer由vuefire-core 库中的 createSnapshot 函数实现:

/**
 * @param {firebase.firestore.DocumentSnapshot} doc
 * @return {DocumentData}
 */
export function createSnapshot (doc) {
  // defaults everything to false, so no need to set
  return Object.defineProperty(doc.data(), 'id', {
    value: doc.id
  })
}

如您所见,它仅返回doc.data()id添加)并丢弃doc对象。但是,当通过我们实现 Firestore 分页时,query.startAfter(doc)我们需要原始doc对象。好消息是 VueFire 和 VuexFire API 允许我们serializer用我们自己的来替换 ,这样可以保留 doc 对象,如下所示:

const serialize = (doc: firestore.DocumentSnapshot) => {
  const data = doc.data();
  Object.defineProperty(data, 'id', { value: doc.id });
  Object.defineProperty(data, '_doc', { value: doc });
  return data;
}

我们可以通过插件选项全局配置我们新的 VuexFire 序列化程序,也可以通过绑定选项按绑定配置。

// 全局定义的 Vue.use(firestorePlugin, { serialize });

// 或者每个绑定 bindFirebaseRef('todos', db.ref('todos'), { serialize } )

对于 VuexFire,我们现在可以访问第一个文档state.todos[0]._doc或最后一个文档state.todos[state.todos.length-1]._doc,并使用它们来实现集合的分页查询或绑定单个文档的“获取下一个”和“获取上一个”查询(当您的基本查询具有多字段时必不可少排序)。

注意:因为_docid是不可枚举的属性,它们不会出现在组件上或在Vue DevTools中存储对象。

于 2020-06-25T12:59:56.027 回答
1

从关于绑定数据和使用它的 VueFire 文档中,该$bind方法(我假设你的bindFirestoreRef包装)返回一个带有结果的承诺(以及将其绑定到this)。从该文档中:

this.$bind('documents', documents.where('creator', '==', this.id)).then(documents => {
  // documents will point to the same property declared in data:
  // this.documents === documents
})

所以你应该能够做同样的事情,然后从数组中获取文档,如下所示:

bindFirestoreRef('leads', db.collection('leads').orderBy('updated.date', 'desc').limit(30)).then(documents => {
  this.lastDoc = documents[documents.length - 1];
})
于 2019-11-17T15:17:32.560 回答