如何从 VueFire 查询中获取最后一个文档

Posted

技术标签:

【中文标题】如何从 VueFire 查询中获取最后一个文档【英文标题】:How to get the last document from a VueFire query 【发布时间】:2020-03-13 00:43:16 【问题描述】:

因为我不是 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),以便将其传递给下一个查询。

任何帮助将不胜感激。 ??????????

【问题讨论】:

【参考方案1】:

假设我有一个客户记录的集合,我正在显示最后更新的前 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 个结果。我究竟做错了什么? :(

【讨论】:

【参考方案2】:

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

默认的serializer 由函数createSnapshot 实现,它是vuefire-core 库的一部分:

/**
 * @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 对象。但是,当通过 query.startAfter(doc) 实现 Firestore 分页时,我们需要原始的 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;

我们可以通过plugin options 全局配置我们的新VuexFire 序列化程序,或者通过binding options 进行每个绑定。

// 全局定义 Vue.use(firestorePlugin, 序列化 );

// 或每个绑定 bindFirebaseRef('todos', db.ref('todos'), 序列化 )

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

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

【讨论】:

我遇到了同样的问题。这几乎让我到了那里,但我仍然不清楚如何让分页查询结果绑定到原始状态数据。我之前无法添加评论,所以我在这里创建了一个新问题***.com/questions/62639778/… 我添加了一些可能的解决方案来扩展它以实现分页。 ***.com/a/62650214/365261【参考方案3】:

从binding data and using it 的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];
)

【讨论】:

谢谢。但它似乎不起作用。实际上将最后一个文档数据传递给 firestore 不能用作查询游标。我应该传递一个文档引用,它是 $bind 返回的文档的父级:( 你能告诉我使用文档引用来初始化光标的方法的文档吗?在我经常使用的客户端(javascript、ReactNative、android、Swift、Flutter)中,它是一个文档 snapshot,因为它包含光标所需的实际数据。 firebase.google.com/docs/firestore/query-data/query-cursors 它在 Paginate a Query 部分下 文档快照是光标所需要的,但是,正如我原来的问题一样,VuexFire 中来自 $bind 的文档会返回文档的实际数据,而不是文档快照。 您还可以传递值数组,而不是文档快照。

以上是关于如何从 VueFire 查询中获取最后一个文档的主要内容,如果未能解决你的问题,请参考以下文章

在 vuefire 的 firestore 内的“this”中获取“undefined”

在 Vuejs 中渲染 DOM 之前,使用路由器中的参数获取 firebase 数据(使用或不使用 vuefire)?

如何从整个集合中获取最后添加的文档。 OnSnapshot

Django - 如何从模板中的查询集中获取最后一项

如何从 sql 查询中获取第一条和最后一条记录?

如何从 C# 中的数据库中获取最后一个 id