【问题标题】:Prevent overwriting createdAt and updatedAt in Cloud Function when object set includes them防止在对象集包含时覆盖 Cloud Function 中的 createdAt 和 updatedAt
【发布时间】:2020-08-23 09:46:21
【问题描述】:

我正在编写一些 Node.js 代码,以将现有数据库中的数据导入 Firebase Cloud Firestore。我们已经创建了我希望在过渡中保留的日期和更新日期。问题是我们创建了 Cloud Functions 来自动设置对象创建时的设置,因此它总是用当前时间戳覆盖对象的值。如果我再次运行我们的导入脚本,因此 set 正在更新现有文档,则保留对象中的 createdAt 和 updatedAt 值。

我怎样才能让它使用指定的值而不用创建时的当前时间戳覆盖它们?

const oldNote = {
  id: "someid",
  text: "sometext",
  createdAt: new Date(2018, 11, 24, 10, 33, 30, 0),
  updatedAt: new Date(2018, 11, 24, 10, 33, 30, 0)
}

const note = {
  text: oldNote.text,
  createdAt: firebase.firestore.Timestamp.fromDate(oldNote.createdAt),
  updatedAt: firebase.firestore.Timestamp.fromDate(oldNote.updatedAt)
};
firestoredb.collection("notes").doc(oldNote.id).set(note).then((docRef) => {
    //FIXME: createdAt and updatedAt aren't preserved, always today
}).catch((error) => {
    console.error("Error setting user: ", error);
});

这里是云函数:

exports.updateCreatedAt = functions.firestore
.document("{collectionName}/{id}")
.onCreate((snap, context) => {
    const now = admin.firestore.FieldValue.serverTimestamp();

    return snap.ref.set(
        {
            createdAt: now,
            updatedAt: now
        },
        { merge: true }
    );
});

exports.updateUpdatedAt = functions.firestore
.document("{collectionName}/{id}")
.onUpdate((change, context) => {
    const newValue = change.after.data();
    const previousValue = change.before.data();

    if (
        Boolean(newValue.updatedAt) &&
        Boolean(previousValue.updatedAt) &&
        newValue.updatedAt.isEqual(previousValue.updatedAt)
    ) {
        const now = admin.firestore.FieldValue.serverTimestamp();

        return change.after.ref.set({ updatedAt: now }, { merge: true });
    } else {
        return false;
    }
});

【问题讨论】:

  • dateobj 到底是什么?请不遗余力。我们应该能够获取您的代码并自己运行它。
  • @DougStevenson 这是一个 JavaScript 日期对象。这只是一个例子,旧笔记是从不同的数据库中查询的。
  • 确切的值很重要。

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


【解决方案1】:

我继续在 Google Cloud Console 中部署了对 onCreate 触发器的更新。它现在检查对象是否已经包含 createdAt 和/或 updatedAt 并使用它们而不是覆盖它们。

exports.updateCreatedAt = functions.firestore
.document("{collectionName}/{id}")
.onCreate((snap, context) => {
    const now = admin.firestore.FieldValue.serverTimestamp();
    const createdAt = snap.data().createdAt != undefined ? snap.data().createdAt : now;
    const updatedAt = snap.data().updatedAt != undefined ? snap.data().updatedAt : now;

    return snap.ref.set(
        {
            createdAt: createdAt,
            updatedAt: updatedAt
        },
        { merge: true }
    );
});

【讨论】:

    【解决方案2】:

    正如您从Timestamp.fromDate() 的 API 文档中看到的那样,采用 Date 对象并将其转换为 Timestamp 对象。但是,您将向它传递一个 Timestamp 对象(除非您的编辑是伪造的值不是来自 Cloud Functions 中写入的数据库)。这是不必要的转换,它可能只是返回当前时间而不是您期望的时间。只需使用适当的时间戳值:

    const note = {
      text: oldNote.text,
      createdAt: oldNote.createdAt,
      updatedAt: oldNote.updatedAt
    };
    

    请记住,当您将日期写入 Firestore 时,它​​会在内部存储一个时间戳。它不会以日期的形式出现。

    【讨论】:

    • oldNote 的 created/updatedAt 是 JavaScript 日期对象,而不是 firebase.firestore.Timestamp。
    • 嗯,你在云函数中写的内容将存储一个时间戳。
    • 这是所希望的。新笔记应该有时间戳。
    • 是的,所以,正如我在这里所说,如果您使用 oldNote 从文档中提取时间戳,则无需转换。
    • 文档以与我在这里相同的方式显示它:dateExample: admin.firestore.Timestamp.fromDate(new Date('December 10, 1815')),
    猜你喜欢
    • 2019-07-19
    • 2015-10-11
    • 1970-01-01
    • 2018-07-24
    • 1970-01-01
    • 2018-10-08
    • 2019-08-11
    • 2015-12-29
    • 1970-01-01
    相关资源
    最近更新 更多