javascript - 无法通过 API 调用发送 Firebase QueryDocumentSnapshot
问题描述
我目前正在服务器端的一系列分页呼叫中进行我的第一个网络呼叫。在执行此操作之前,我在客户端进行所有调用,并将集合调用中的最后一个文档存储为偏移量。
然后将偏移量作为 .startAfter 调用发送给同一个集合。抵消文件如下所示:
exists: (...)
id: (...)
metadata: (...)
ref: (...)
_document: Document {key: DocumentKey, version: SnapshotVersion, data: ObjectValue, proto: {…}, hasLocalMutations: false, …}
_firestore: Firestore {_queue: AsyncQueue, INTERNAL: {…}, _config: FirestoreConfig, _databaseId: DatabaseId, _dataConverter: UserDataConverter, …}
_fromCache: false
_hasPendingWrites: false
_key: DocumentKey {path: ResourcePath}
__proto__: DocumentSnapshot
当我在服务器上进行调用时,我目前能够看到文档看起来相同,但是当我通过网络发送它时,它似乎被剥离了,或者至少在通过 JSON 发送并解析回来时看起来非常不同.
像这样发送:
res.json(offset)
然后像这样解析:
feedData = await dataWithOffset.json();
解析后是这样的:
{ _ref:
{ _firestore:
{ _settings: [Object],
_settingsFrozen: true,
_serializer: [Object],
_projectId: '***-prod',
_lastSuccessfulRequest: 1566308918946,
_preferTransactions: false,
_clientPool: [Object] },
_path:
{ segments: [Array],
projectId: '***-prod',
databaseId: '(default)' } },
_fieldsProto:
{ lastModified: { timestampValue: [Object], valueType: 'timestampValue' },
...,
_serializer: { timestampsInSnapshots: true },
_readTime: { _seconds: 1566308918, _nanoseconds: 909566000 },
_createTime: { _seconds: 1565994031, _nanoseconds: 304997000 },
_updateTime: { _seconds: 1565994031, _nanoseconds: 304997000 } }
知道为什么它会失去形状以及我能做些什么来修复它,以便它恢复正常偏移的工作吗?我是否应该不转换为 JSON 并返回,因为这可能会剥夺一些重要的东西?
解决方案
解决方案(已测试)
所以我继续制作了一个沙箱来测试实现,就像我在评论中提到的那样,.startAfter
期望DocumentSnapshot
不是DocumentReference
鉴于我创建了一个以cars
4 条记录命名的集合,如下所示:
[
{
"name": "car 1",
"hp": 5
},
{
"name": "car 2",
"hp": 10
},
{
"name": "car 2.5",
"hp": 10
},
{
"name": "car 3",
"hp": 15
}
]
然后我配置了一个快速端点:
router.get('/cars/:lastDocId', (req, res) => {
const query = db.collection('cars')
.orderBy('hp')
.limit(2);
const handleQueryRes = (snap) => {
return res.send({
docs: snap.docs.map(doc => doc.data()),
last: snap.docs.length > 0 ? snap.docs[snap.docs.length - 1].id : null
});
}
if(req.params.lastDocId != -1) {
// this makes an "auxiliar" read from the DB to transform the given ID in a DocumentSnapshot needed for startAfter
return db.collection('cars').doc(req.params.lastDocId).get().then(snap => {
return query.startAfter(snap).get();
}).then(handleQueryRes).catch(console.log);
} else {
return query.get().then(handleQueryRes).catch(console.log);
}
});
path 参数lastDocId
用于-1
第一页或上一页中获取的最后一个文档
当我向它发出 GET 请求时,/cars/-1
它会返回:
{
"docs": [
{
"hp": 5,
"name": "car 1"
},
{
"name": "car 2",
"hp": 10
}
],
"last": "9sRdLOvV8REwEpHDjEw7"
}
现在,如果我last
在响应中获取道具并在下一次 GET 中使用它,那么/cars/9sRdLOvV8REwEpHDjEw7
我将获得接下来的 2 辆车:
{
"docs": [
{
"name": "car 2.5",
"hp": 10
},
{
"name": "car 3",
"hp": 15
}
],
"last": "tZPF7Wav7jZuchoCp6zM"
}
即使我只有 4 条记录,并且第二个请求应该是最后一个,该函数不知道集合的长度,因此它返回另一个last
ID
如果您发出最后一个请求/cars/tZPF7Wav7jZuchoCp6zM
,它会返回:
{
"docs": [],
"last": null
}
从而给出最后一页的指示。
我不太喜欢必须再次阅读文档才能将其转换为 aDocumentSnapshot
但我想这是 firebase 限制
希望它有所帮助
用步骤回答
转换为 JSON 并返回时,您会丢失 DocumentReference 原型
通过网络请求传递此类数据的解决方案是:
ref
客户端向您的端点发送纯文本(或第一页不发送)- 让服务器端代码使用收到的重新创建 DocumentReference
ref
- 使用重新创建的 DocumentReference 对查询进行分页
- 从服务器返回请求页面的文档以及纯文本
ref
以获取下一页
初始答案(已过时)但供将来参考
您需要发送offset.data()
而不是一起offset
发送
一个是文档的数据(可能是您所追求的),另一个是 DocumentReference,它具有无法用 JSON 表示的方法。
如果您需要文档中的其他任何内容(例如它的 id 或引用),您最好构建一个新对象:
res.json({
data: offset.data(),
ref: offset.ref,
id: offset.id
});
推荐阅读
- laravel - 使用 Laravel 在同一个索引 Elasticsearch 中保存多个属性
- java - ConcurrentSkipListMap 在descendingMap 中使用自定义比较进入无限循环,这是一个java 错误吗?
- css - 缩放百分比时如何更改文本?
- excel - VBA/Userform - 将值从文本框传输到带有书签的 Word 不起作用
- reactjs - 如何使用 React Hook useState 更新 2 个对象
- c++ - 将参数转发到可变参数模板函数时如何添加参数值?
- flutter - Flutter CustomPainter - 从弧形刮边
- anylogic - 抓住块中动作的含义
- angular - 在fabricjs中将背景图像设置为iText
- android - 如何从文件夹中获取所有文件的文件创建日期并在 TextView 中显示 gridview android holder.creationdate.settext() 类似的东西?