Firestore 时间戳被保存为地图

问题描述 投票:0回答:2

以下片段

const start = new Date(this.date + 'T' + this.time);
console.log(start); // Thu Sep 12 2019 04:00:00 GMT+0200

const tournament:Tournament = {
      start: firebase.firestore.Timestamp.fromDate(start)
}

将此锦标赛对象传递给可调用云函数,其唯一目的是保存作为文档传递的

tournament
会将
start
字段保存为具有属性
seconds
miliseconds
的地图,而不是 Firestore 中的时间戳.

我也尝试只做

start: start
但这也没有带来在 Firestore 中保存时间戳的预期结果。

仅供参考,这是功能代码精简后的样子:

firestore.collection('tournaments').doc(slugUrl).set(tournamentData)

(tournamentData 是从前端传递过来的对象)

javascript node.js firebase google-cloud-firestore
2个回答
5
投票

您的 Timestamp 对象必须先序列化为 JSON,然后才能将其发送到函数。默认序列化将时间戳分成自然秒和纳秒值生成的对象。所有类型信息都丢失了。

在您的函数中,您将不得不从传递给函数的数据中读取这些单独的值,使用其双参数构造函数将它们转换回适当的时间戳对象,然后将该对象写入 Cloud Firestore。才会保存为时间戳类型的字段。


0
投票

我能够通过使用 msgpack 而不是 JSON 进行序列化来解决这个问题,因为它支持 时间对象的转换。转换 Firestore Timestamp 对象很简单,因为它们基于 Temporal Instant.

我的用例是通过 PubSub 将

Timestamp
对象从一个 Cloud Function 发送到另一个 Cloud Function。下面的示例是围绕该概念构建的,但足够通用,可以扩展到其他流程。 (例如,将数据从 Web 应用程序发送到 Cloud Functions,反之亦然)


首先定义一个可以编码和解码

ExtensionCodec
类型的自定义msgpack
Timestamp
,然后用
Encoder
Decoder
对象注册扩展,这样当它们用于序列化数据时,它们知道如何处理这些类型.

下面的代码片段在变成一个包时效果最好,这样它就可以在多个函数/应用程序之间共享,否则必须将它复制并粘贴到它后面的每个示例中才能工作。我从下面的每个示例中省略了这个片段以保持它们干燥。

import {
  Decoder,
  Encoder,
  ExtensionCodec,
  decodeTimestampToTimeSpec,
  encodeTimeSpecToTimestamp,
} from '@msgpack/msgpack'
import { Timestamp } from 'firebase-admin/firestore'

const firestoreTimestampType = 0
const extensionCodec: ExtensionCodec = new ExtensionCodec()

extensionCodec.register({
  type: firestoreTimestampType,
  encode(input: unknown): Uint8Array | null {
    if (input instanceof Timestamp) {
      const sec = input.seconds
      const nsec = input.nanoseconds

      return encodeTimeSpecToTimestamp({ sec, nsec })
    } else {
      return null
    }
  },
  decode(data: Uint8Array): Timestamp {
    const timeSpec = decodeTimestampToTimeSpec(data)
    const sec = timeSpec.sec
    const nsec = timeSpec.nsec

    return new Timestamp(sec, nsec)
  },
})

// Always use these instances to encode/decode objects that are or
// contain Timestamp type objects or else they will decode as Map
// objects the same way they do with JSON serialization
export const encoder = new Encoder({ extensionCodec })
export const decoder = new Decoder({ extensionCodec })

接下来配置发送数据的功能,使用自定义编码器对其进行编码:

import { type ClientConfig, PubSub } from '@google-cloud/pubsub'
import { Timestamp } from 'firebase-admin/firestore'

// Replace with your actual projectId and topic name
const pubSub = new PubSub('some-project-id' as ClientConfig).topic('some-topic-name')

interface CustomObject {
  timestamp: Timestamp
}

export const sendingCloudFunction = async (): Promise<void> => {
  const seconds = Math.floor(Date.now() / 1000)
  const nanoseconds = 0
  const timestamp: Timestamp = new Timestamp(seconds, nanoseconds)
  const customObject: CustomObject = { timestamp }

  // Encode the custom object with msgpack
  const encodedObject: Uint8Array = encoder.encode(customObject)

  // Pass this data on to the next function by publishing to PubSub
  const data: Buffer = Buffer.from(
    encodedObject.buffer,
    encodedObject.byteOffset,
    encodedObject.byteLength
  )
  await pubSub.publishMessage({ data })
}

最后,配置接收数据的函数以使用自定义解码器对其进行解码:

import { type PubsubMessage } from '@google-cloud/pubsub/build/src/publisher'
import { Timestamp } from 'firebase-admin/firestore'

interface CustomObject {
  timestamp: Timestamp
}

export const receivingCloudFunction = async (
  message: PubsubMessage,
): Promise<void> => {
  if (message.data === null || message.data === undefined) {
    throw new Error('PubSub message must be defined')
  }

  // Decode the PubSub data back into a msgpack-encoded object
  const encodedObject: Buffer = Buffer.from(message.data.toString(), 'base64')

  // Decode the msgpack-encoded object back into CustomObject
  const decodedObject = decoder.decode(encodedObject) as CustomObject

  if (decodedObject.timestamp instanceof Timestamp) {
    console.log(`Successfully decoded ${decodedObject.timestamp.toDate().toString()} as type Timestamp`)
  }
}

receivingCloudFunction
被调用时,它会记录类似于:

成功解码 2023 年 3 月 28 日星期二 12:02:11 GMT-0700(太平洋夏令时)类型时间戳

© www.soinside.com 2019 - 2024. All rights reserved.