【问题标题】:Returning a QuerySnapshot from a callable Cloud Function从可调用的云函数返回 QuerySnapshot
【发布时间】:2019-01-17 15:51:30
【问题描述】:

我正在尝试从可调用的 Google Cloud 函数返回 QuerySnapshot

以下是详细信息,但我的核心问题是,我应该期望能够做到这一点还是这是一个错误?

import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
import * as firestore from '@google-cloud/firestore';

export const callableTest = functions.https.onCall(
    async (data: Map<string, any>, context: functions.https.CallableContext):
        Promise<firestore.QuerySnapshot> => {
        const db = admin.firestore();
        return db.collection('test')
            .get();

        // I also tried this
        //return db.collection('test').get().then(querySnapshot => {
        //    return querySnapshot;
        //});
    });

test 集合可以包含任意数量的文档。在这种情况下,有两个文档。

这是我的客户端 HTML 页面,但我也在 Flutter 和 Node 中尝试过,结果相同。

<!DOCTYPE html>
<html>
    <head>
      <script src="https://www.gstatic.com/firebasejs/5.7.3/firebase.js"></script>
      <script>
        // Initialize Firebase
        var config = {
          apiKey: "### API KEY ###",
          authDomain: "<project-id>.firebaseapp.com",
          databaseURL: "https://<project-id>.firebaseio.com",
          projectId: "<project-id>",
          storageBucket: "<project-id>.appspot.com",
          messagingSenderId: "<sender-id>"
        };
        firebase.initializeApp(config);

        var testClientCall = firebase.functions().httpsCallable('callableTest');
        testClientCall ({}).then(function(result) {
          // Read result of the Cloud Function.
          console.log("Cloud Function result:");
          console.log(result);
        });
      </script>
    </head>
    <body></body>
</html>

这是返回的结果,看起来类似于QuerySnapshot,但不包含任何DocumentSnapshots_docs 属性),即使_size 属性表明应该有两份文件。

{"data":{"_query":{"_firestore":{"_clientPool":{"concurrentOperationLimit":100,"clientFactory":{},"activeClients":{}},"_settings":{"projectId":"<project-id>","firebaseVersion":"6.4.0","libName":"gccl","libVersion":"0.19.0 fire/6.4.0"},"_settingsFrozen":false,"_clientInitialized":{"domain":{"domain":null,"_events":{"error":{}},"_eventsCount":1,"_maxListeners":null,"members":[]}},"_serializer":{"createReference":{},"timestampsInSnapshots":false},"_referencePath":{"segments":[],"projectId":"project-id","databaseId":"(default)"},"_lastSuccessfulRequest":1547738645649,"_validator":{"isFunction":{},"isOptionalFunction":{},"isInteger":{},"isOptionalInteger":{},"isNumber":{},"isOptionalNumber":{},"isObject":{},"isOptionalObject":{},"isString":{},"isOptionalString":{},"isBoolean":{},"isOptionalBoolean":{},"isArrayElement":{},"isOptionalArrayElement":{},"isDeletePrecondition":{},"isOptionalDeletePrecondition":{},"isDocument":{},"isOptionalDocument":{},"isDocumentReference":{},"isOptionalDocumentReference":{},"isFieldPath":{},"isOptionalFieldPath":{},"isFieldValue":{},"isOptionalFieldValue":{},"isFieldOrder":{},"isOptionalFieldOrder":{},"isQueryComparison":{},"isOptionalQueryComparison":{},"isQueryValue":{},"isOptionalQueryValue":{},"isResourcePath":{},"isOptionalResourcePath":{},"isSetOptions":{},"isOptionalSetOptions":{},"isReadOptions":{},"isOptionalReadOptions":{},"isUpdateMap":{},"isOptionalUpdateMap":{},"isUpdatePrecondition":{},"isOptionalUpdatePrecondition":{}},"_preferTransactions":true},"_path":{"segments":["test"],"projectId":"project-id","databaseId":"(default)"},"_fieldFilters":[],"_fieldOrders":[],"_queryOptions":{},"_validator":{"isFunction":{},"isOptionalFunction":{},"isInteger":{},"isOptionalInteger":{},"isNumber":{},"isOptionalNumber":{},"isObject":{},"isOptionalObject":{},"isString":{},"isOptionalString":{},"isBoolean":{},"isOptionalBoolean":{},"isArrayElement":{},"isOptionalArrayElement":{},"isDeletePrecondition":{},"isOptionalDeletePrecondition":{},"isDocument":{},"isOptionalDocument":{},"isDocumentReference":{},"isOptionalDocumentReference":{},"isFieldPath":{},"isOptionalFieldPath":{},"isFieldValue":{},"isOptionalFieldValue":{},"isFieldOrder":{},"isOptionalFieldOrder":{},"isQueryComparison":{},"isOptionalQueryComparison":{},"isQueryValue":{},"isOptionalQueryValue":{},"isResourcePath":{},"isOptionalResourcePath":{},"isSetOptions":{},"isOptionalSetOptions":{},"isReadOptions":{},"isOptionalReadOptions":{},"isUpdateMap":{},"isOptionalUpdateMap":{},"isUpdatePrecondition":{},"isOptionalUpdatePrecondition":{}},"_serializer":{"createReference":{},"timestampsInSnapshots":false}},"_readTime":{"_seconds":1547738645,"_nanoseconds":638303000},"_size":2,"_materializedDocs":null,"_materializedChanges":null,"_docs":{},"_changes":{},"_validator":{"isFunction":{},"isOptionalFunction":{},"isInteger":{},"isOptionalInteger":{},"isNumber":{},"isOptionalNumber":{},"isObject":{},"isOptionalObject":{},"isString":{},"isOptionalString":{},"isBoolean":{},"isOptionalBoolean":{},"isArrayElement":{},"isOptionalArrayElement":{},"isDeletePrecondition":{},"isOptionalDeletePrecondition":{},"isDocument":{},"isOptionalDocument":{},"isDocumentReference":{},"isOptionalDocumentReference":{},"isFieldPath":{},"isOptionalFieldPath":{},"isFieldValue":{},"isOptionalFieldValue":{},"isFieldOrder":{},"isOptionalFieldOrder":{},"isQueryComparison":{},"isOptionalQueryComparison":{},"isQueryValue":{},"isOptionalQueryValue":{},"isResourcePath":{},"isOptionalResourcePath":{},"isSetOptions":{},"isOptionalSetOptions":{},"isReadOptions":{},"isOptionalReadOptions":{},"isUpdateMap":{},"isOptionalUpdateMap":{},"isUpdatePrecondition":{},"isOptionalUpdatePrecondition":{}}}}

起初我认为这可能是序列化的问题,但如果我修改我的云函数以仅返回一个 DocumentSnapshot,它会返回预期的数据。

【问题讨论】:

    标签: firebase google-cloud-firestore google-cloud-functions


    【解决方案1】:

    这是序列化的问题。您正在尝试返回一个不打算直接序列化的复杂对象。相反,您应该迭代查询快照中的文档,构建您想要返回的任何对象(一个数组?)并返回它。像这样的:

    const querySnapshot = await db.collection('test').get();
    return querySnapshot.docs.map(doc => doc.data());
    

    【讨论】:

    • 感谢您快速彻底的回复。我将使用这种方法。但是,我正在尝试做一个计划用于未来支持的方案吗?我更大的目标是能够在云功能中执行一些业务规则,然后代表客户构造并返回一个QuerySnapshot,它可以直接使用。 (我知道我可以想象返回相关数据然后在客户端上构造QuerySnapshot,但我试图避免多个客户端实现。)
    • 我认为您将始终必须在服务器中自定义对客户端的响应。它应该始终是一个普通的 JSON 对象。
    • @DougStevenson 这似乎也适用于客户端在发送自定义对象构建函数端时未正确接收的“时间戳”。它既不是正确的时间戳,也不能从中读取 secondsnanoseconds,尽管有 { _nanoseconds: "...", _seconds: "..." }。我需要如何正确处理该对象?我可以将其转换为适当的时间戳客户端吗?
    • @AlexeiS。有很多关于堆栈溢出的问题都在讨论 Timestamp 类型对象的序列化。
    • 我收到“数据无法以 JSON 编码”作为错误消息。可能是什么问题?
    猜你喜欢
    • 2021-06-03
    • 2020-02-04
    • 1970-01-01
    • 2019-11-25
    • 2021-01-24
    • 2019-01-18
    • 2019-08-12
    • 2021-09-13
    • 2019-12-17
    相关资源
    最近更新 更多