javascript - 无法通过 API 调用发送 Firebase QueryDocumentSnapshot

标签 javascript node.js firebase

我目前正在服务器端的一系列分页调用中进行第一个网络调用。在此之前,我在客户端进行所有调用,并将最后一个文档作为偏移量存储在集合调用中。

然后将偏移量作为同一集合的 .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);
    }

});

路径参数 lastDocId 是首页的 -1 或上一页中获取的最后一个文档

当我向 /cars/-1 发出 GET 请求时,它返回:

{
    "docs": [
        {
            "hp": 5,
            "name": "car 1"
        },
        {
            "name": "car 2",
            "hp": 10
        }
    ],
    "last": "9sRdLOvV8REwEpHDjEw7"
}

现在,如果我捕获响应中的 last 属性并在下一个 GET 中使用它,就像 /cars/9sRdLOvV8REwEpHDjEw7 我会得到我的下两辆车:

{
    "docs": [
        {
            "name": "car 2.5",
            "hp": 10
        },
        {
            "name": "car 3",
            "hp": 15
        }
    ],
    "last": "tZPF7Wav7jZuchoCp6zM"
}

尽管我只有 4 条记录,并且第二个请求应该是最后一个请求,但该函数不知道集合的长度,因此它返回另一个 last ID

如果您发出最后一个请求/cars/tZPF7Wav7jZuchoCp6zM,它将返回:

{
    "docs": [],
    "last": null
}

因此表明这是最后一页。

我不太喜欢再次阅读文档才能将其转换为 DocumentSnapshot 但我想这是 firebase 的限制

希望对你有帮助

<小时/>

回答步骤

当转换为 JSON 并返回时,您会丢失 DocumentReference 原型(prototype)

通过网络请求传递该类型数据的解决方案是:

  • 客户端向您的端点发送纯文本 ref(或者不向首页发送)
  • 有服务器端代码 re-create the DocumentReference with the received ref
  • 使用重新创建的 DocumentReference 对查询进行分页
  • 从服务器返回所请求页面的文档以及纯文本ref以获取下一页
<小时/>

初始答案(已过时)但供将来引用

您需要发送 offset.data() 而不是一起发送 offset

一个是文档的数据(可能是您想要的数据),另一个是 DocumentReference,它具有无法用 JSON 表示的方法。

如果您需要文档中的任何其他内容(例如 id 或引用),您最好构建一个新对象:

res.json({
   data: offset.data(),
   ref: offset.ref,
   id: offset.id
});

关于javascript - 无法通过 API 调用发送 Firebase QueryDocumentSnapshot,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57575336/

相关文章:

node.js - 是否可以在 "keen"对象中添加除标准属性之外的其他用户定义属性?

ios - Firebase Crash pod 破坏了 iOS 上的设备旋转

android - dataSnapShot.getKey() 不返回实际的按键

swift - 如何在 firebase 中隔离用户数据?

javascript - 从 JS 中的不可变数组中删除元素的最干净方法是什么?

javascript - 当以特定方式单击图标时,为什么我的网页的一部分会消失?

javascript - Node js/js : Text not appended in file in sequence

javascript - 客户端和服务器端编程有什么区别?

javascript - 传单在悬停时显示 map - map 加载不正确

node.js - 使用 express 在 axios post 请求后进行重定向