Google cloud firestore Cloud Firestore:通过多个UTC偏移量存储和查询今天的日期?

Google cloud firestore Cloud Firestore:通过多个UTC偏移量存储和查询今天的日期?,google-cloud-firestore,datetimeoffset,Google Cloud Firestore,Datetimeoffset,我正在使用Firestore编写一个web应用程序,它需要能够显示今天流行的帖子,而且在考虑不同时区的用户时,我很难正确地查询 日期以UTC 0的形式存储在数据库中,然后通过调整客户端中当前用户的UTC偏移量。这是正确的 添加新帖子时,我使用firebase.firestore.FieldValue.serverTimestamp将当前服务器时间戳存储在名为timestamp的字段中,如下所示: const collectionRef = db.collection('posts'); coll

我正在使用Firestore编写一个web应用程序,它需要能够显示今天流行的帖子,而且在考虑不同时区的用户时,我很难正确地查询

日期以UTC 0的形式存储在数据库中,然后通过调整客户端中当前用户的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
});
然后在服务器上,我有一个在create上运行的Cloud函数,它向文档中添加了另一个名为datestamp的字段,该字段是UTC 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
    });
  });
posts/{somepostid}
{
  name: "Test Post",
  content: "Blah blah blah",
  timestamp: Mon Jan 29 2018 21:37:21 GMT-0800 (PST),
  likeCount: 0,
  utcDatemap: {
    0: "2018-01-30,
    ...
    -480: "2018-01-29",
    ...
  }
}
存储一个时间戳,其中时间始终是一天的开始,这使我能够编写一个类似这样的查询,用于查找给定日期的所有帖子并按人气排序:

const startOfDayUTC = moment.utc().startOf('day').toDate();
const postQuery = db.collection('posts')
                    .orderBy('likeCount', 'desc')
                    .orderBy('timestamp', 'desc')
                    .where('datestamp', '==', startOfDayUTC)
                    .limit(25);
问题是,根据用户的UTC偏移量,在解析帖子的时间戳字段时,这可能会显示具有两个不同日期的帖子。因此,即使查询正确地获取了日期戳为2018-01-30T00:00:00Z的所有帖子,时间戳的日期在解析后也可能不同。以下是两篇文章的示例:

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
因此,您可以看到,虽然帖子具有相同的日期戳,但在将时间戳调整为本地UTC后,时间戳字段可能会在两个不同的日期结束


如果有人能解决这个问题,我将不胜感激。

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

query.where(date > lastMidnight).where(data < now).get().then(...)
你可以得到你的数据,记住你需要建立一个索引或者只运行一次查询,firebase SDK将为你生成一个链接,在dev tools->console中创建索引

    query.where(date > lastMidNightUTC).where(data < now).get().then(...)

我想出了一个我真的不满意的解决方案。。。但它是有效的

问题在于,根据用户的位置,一篇帖子可以在多个日期发布。因为在这种情况下,我们还希望按时间戳以外的字段排序,所以我们不能使用范围查询来选择给定日期的帖子,因为您的第一个.orderBy必须位于使用范围查询的字段上

我的解决方案是将本地化的邮戳映射到相应的UTC偏移量。对象包含每个UTC偏移量作为一个键,以及该偏移量时间内的邮政日期戳

示例帖子如下所示:

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
    });
  });
posts/{somepostid}
{
  name: "Test Post",
  content: "Blah blah blah",
  timestamp: Mon Jan 29 2018 21:37:21 GMT-0800 (PST),
  likeCount: 0,
  utcDatemap: {
    0: "2018-01-30,
    ...
    -480: "2018-01-29",
    ...
  }
}
utcDatemap字段是我们现在在查询中使用的字段:

const now = moment();
const datestamp = now.format("YYYY-MM-DD");
const utcOffset = now.utcOffset();
const utcDatemapField = 'utcDatemap.'+utcOffset;

const postQuery = db.collection('posts')
                    .orderBy('likeCount', 'desc')
                    .orderBy('timestamp', 'desc')
                    .where(utcDatemapField, '==', datestamp)
                    .limit(25);
现在,帖子可以在两个不同的日期显示,这取决于用户从何处查询。我们仍然可以在客户端将常规的旧时间戳转换为用户的本地时间

这绝对不是一个理想的解决方案。对于上面的查询,我需要为utcDatemap中的每个键创建复合索引。我不确定复合索引的经验法则是什么,但我认为像这样简单的东西有39个索引可能不太好


此外,我还使用thomas peter的答案中的roughSizeOfoObject函数和utcDatemap对象检查了它,它的所有字符串日期戳大约为780字节,而0.78kb不是很多,但是,您确实需要注意,使用Firestore 0.78kb这样的服务传输的数据量对于一个日期来说太多了。

我有点不明白您所说的一天的开始是什么意思?你是说实际日期,比如1月29日吗?您希望能够在当天为每个用户本地查询帖子吗?我认为您在计算中遗漏了从UTC到本地的时间转换。如果我理解您的要求,我很乐意提供帮助。@TheeBen我的意思是我正在存储UTC 0时间戳,但因为我关心的是查询日期,而不是时间,所以我将时间设置为一天开始的00:00:00。因为如果我也像在timestamp字段中那样存储时间,我将无法在.where.“==”中使用它。。因为每篇文章都有不同的时间。除了第一个.orderBy必须与正在使用范围筛选器的字段位于同一字段之外,这将非常有效。因此,对于我的具体情况,我需要查询的第一个.orderBy位于'likeCount'上,而不是'timestamp',因为我想显示给定日期的帖子,按它们的'likeCount'排序。看你是对的,我完全忘了。我稍后会给你回电我想出了一个解决方案,虽然还远远不够完美。用天数代替时间戳怎么样?一些需要思考的问题。因此,我一直在挖掘我自己的问题,并认为这可能对您也有帮助,如果您还没有阅读,请阅读有关如何使用数组的解决方案。简而言之,在您的情况下,实现对一个参数的查询并能够使用范围的一种解决方法是保存一个类似startOfDayUTC:likeCount的字段,这样您就可以查询where startofDay>。。。例如。你最好还是坚持UTC 并将用户的本地日期转换为UTC时间范围。日边界对旋转地球上的数据库来说意义不大。