Cloud Firestore:在多个 UTC 偏移量上存储和查询今天的日期?

sar*_*den 5 datetimeoffset google-cloud-firestore

我正在使用 Firestore 编写一个网络应用程序,需要能够显示“今日热门帖子”,但在考虑不同时区的用户时,我无法正确获取查询。

日期以 UTC 0 形式存储在数据库中,然后通过Moment.js调整为客户端中当前用户的 UTC 偏移量。这工作正常。

添加新帖子时,我使用firebase.firestore.FieldValue.serverTimestamp()将当前服务器时间戳存储在名为 的字段中timestamp,如下所示:

const collectionRef = db.collection('posts');
collectionRef.add({
  name: "Test Post",
  content: "Blah blah blah",
  timestamp: firebase.firestore.FieldValue.serverTimestamp(),
  likeCount: 0
});
Run Code Online (Sandbox Code Playgroud)

然后在服务器上,我有一个云函数,它在创建时运行,并向文档添加另一个字段,称为datestampUTC 0 时间戳,但进行了调整,以便时间是一天的开始。该函数如下所示:

exports.updatePostDate = functions.firestore
  .document('posts/{postID}')
  .onCreate((event) => {
    const db = admin.firestore();
    const postRef = db.doc('post/'+event.params.postID);
    const postData = event.data.data();

    const startOfDay = moment(postData.timestamp).startOf('day').toDate();

    return postRef.update({
      datestamp: startOfDay
    });
  });
Run Code Online (Sandbox Code Playgroud)

存储时间始终是一天开始的时间戳使我能够编写这样的查询来查找所有帖子并按给定日期的受欢迎程度排序:

const startOfDayUTC = moment.utc().startOf('day').toDate();
const postQuery = db.collection('posts')
                    .orderBy('likeCount', 'desc')
                    .orderBy('timestamp', 'desc')
                    .where('datestamp', '==', startOfDayUTC)
                    .limit(25);
Run Code Online (Sandbox Code Playgroud)

问题是,根据用户的 UTC 偏移量,在解析帖子timestamp字段时可能会显示具有两个不同日期的帖子。datestamp因此,即使查询正确地获取了2018-01-30T00:00:00Z 的所有帖子,timestamp解析后的日期也可能不相同。这是两个帖子的示例:

Post 2:
likeCount: 1
timestamp (UTC 0): 2018-01-30T06:41:58Z
timestamp (parsed to UTC-8): 2018-01-29T22:41:58-08:00
datestamp (UTC 0): 2018-01-30T00:00:00Z

Post 1:
likeCount: 0
timestamp (UTC 0): 2018-01-30T10:44:35Z
timestamp (parsed to UTC-8): 2018-01-30T02:44:35-08:00
datestamp (UTC 0): 2018-01-30T00:00:00Z
Run Code Online (Sandbox Code Playgroud)

因此您可以看到,虽然帖子具有相同的datestamp,但在调整timestamp为本地 UTC 后,这些timestamp字段最终可能位于不同的两天。

如果有人对此有解决方案,我将非常感激。

The*_*Ben 4

我认为在这种情况下最好避免使用函数,因为您现在可以执行复合查询。你可以简单地使用

query.where(date > lastMidnight).where(data < now).get().then(...)
Run Code Online (Sandbox Code Playgroud)

可以这么说,限制只属于一天的数据,并尝试将所有时间变量保留在 UTC 0 中,只需找到客户端的起点和当前时间,并将它们转换为 UTC0。

//get local time from midnight to now (local)
const now = new Date();
const lastMidnight = now.setHours(0,0,0,0);

//then convert those to UTC0 to pass on in your query to firestore
const lastMidNightUTC = new Date(lastMidnight + now.getTimezoneOffset() * 60000).toString();
const nowInUTC = new Date(now + now.getTimezoneOffset() * 60000).toString();
Run Code Online (Sandbox Code Playgroud)

然后你就可以获取你的数据(记住你需要创建一个索引或者只运行一次查询,Firebase SDK 会生成一个链接来为你在开发工具 -> 控制台中创建索引)

    query.where(date > lastMidNightUTC).where(data < now).get().then(...)
Run Code Online (Sandbox Code Playgroud)