Firebase Firestore 云功能:按 node.js 中的日期条件过滤文档

Firebase Firestore cloud functions: filtering documents by date conditions in node.js

我需要使用 node.js 在云函数中按日期过滤 Firestore 中的文档。我只想 return 那些在名为 last_used 的字段中的时间戳(或日期字符串)距当前日期超过 30 天的文档。目前,并非所有文档都有此字段。我考虑采用的一种方法是编写一个触发函数,为每个文档提供一个 last_used 字段并将时间戳设置为 01/01/2022,运行 这一次,然后计划函数可以更新该字段当需要当前日期时。预定功能目前 select 每天随机生成一个 player 文档,将必填字段移至 current-live-player collection 并更新 last_used 字段 selected player 文档 available-players.

上下文:我正在构建一个游戏,其中 player 文档每天从 available-players 中随机 selected collection并放入current-live-playercollection。 current-live-player 仅由一份文件组成,每天在伦敦时间 00:00 更新。我只希望 Firestore select 来自 available-playersplayer 文档满足我的上述条件:last_used 内的日期比当前日期早 30 天以上。

这是我目前所拥有的:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { firestore } = require("firebase-admin");
admin.initializeApp();

const db = admin.firestore();
// Potential trigger function to give all player objects a last_used field
exports.addLastUsedToAll = functions.https.onRequest((request, response) => {
  // Logic to add a last_used field with a date of 01/01/2022
});

// Select a player function that runs every day at 00:00 London time
exports.pickCurrentLivePlayer = functions.pubsub.schedule("0 0 * * *")
    .timeZone("Europe/London")
    .onRun(async () => {

      // select a random player from available players (uses the auto-generated IDs)
      // ifelse catches rare cases that could cause an error
      const availablePlayers = db.collection("available-players");
      const key = availablePlayers.doc().id;
      
      availablePlayers.where(admin.firestore.FieldPath.documentId(), '>=', key).limit(1).get()
      .then(snapshot => {
          if(snapshot.size > 0) {
              snapshot.forEach(doc => {
                console.log(doc.id, '=>', doc.data());
                console.log('snapshot.size > 0 ', doc.id, '=>', doc.data());
                // replace live player
                const newPlayerData = doc.data();
                const app_first_name = newPlayerData.app_first_name;
                const uid = newPlayerData.uid;
                db.collection("live-player").doc("current-live-player").set({app_first_name: app_first_name, uid: uid});
                // set selected player's last_used value to current time
                db.collection("available-players").doc(uid).update({
                    last_used: admin.firestore.Timestamp.now()          
                })
              });
          }
          else {
              const player = availablePlayers.where(admin.firestore.FieldPath.documentId(), '<', key).limit(1).get()
              .then(snapshot => {
                  snapshot.forEach(doc => {
                      console.log(doc.id, '=>', doc.data());
                      console.log('snapshot.size > 0 ', doc.id, '=>', doc.data().name);
               // replace live player
                const newPlayerData = doc.data();
                const app_first_name = newPlayerData.app_first_name;
                const uid = newPlayerData.uid;
                db.collection("live-player").doc("current-live-player").set({app_first_name: app_first_name, uid: uid});
                // set selected player's last_used value to current time
                db.collection("available-players").doc(uid).update({
                    last_used: admin.firestore.Timestamp.now()
                })
                  });
              })
              .catch(err => {
                  console.log('Error getting documents', err);
              });
          }
      })
      .catch(err => {
          console.log('Error getting documents', err);
      });
      return null;
    });

我希望一切都有意义,任何帮助将不胜感激。我知道转换时间戳然后按 javascript 中的日期过滤可能很棘手,但我想使用 Firestore 时间戳来确保函数始终 运行 关闭服务器时间。

编辑:

作为对 Frank van Puffelen 的回答的回应,时间戳计算现在可以正常工作,available players 中的每个文档现在都有一个 last_used 字段,其中填充了时间戳。我现在需要查询 available_players 以显示时间戳超过 30 天前的那些文档。现在的问题是我无法在 运行 随机 selection 之前查询 collection。顺序应该是:1)计算今天的日期减去30天; 2)查询available_players所有在last_used字段中时间戳超过30天的文档; 3) 从这个过滤后的 selection 生成一个密钥; 4) 查询过滤后的 selection 给我一个随机文档并处理其余的更新逻辑等。它落在过滤数据现在是查询快照的地方,而不是比 collection 参考和我不再有的代码 运行s (至少我认为这是问题所在!)。在尝试添加此 'filter by date' 功能之前,代码运行良好。我在这里提供了一个最小的复制:

// calculate time interval
const now = admin.firestore.Timestamp.now();
const intervalInMillis = 30 * 24 * 60 * 60 * 1000;
const cutoffTime = admin.firestore.Timestamp.fromMillis(now.toMillis() - intervalInMillis);

// get collectionReference and filter to those more than 30 days ago
const allPlayers = db.collection("available-players");
const availablePlayers = await allPlayers.where('last_used', '<=', cutoffTime).get();

// generate key
const key = availablePlayers.doc().id;

// select a random player from the filtered selection
availablePlayers.where(admin.firestore.FieldPath.documentId(), '>=', key).limit(1).get()
      .then(snapshot => {
..etc etc

我不知何故需要能够查询数据以按日期过滤数据,然后 运行 随机 selection 代码块。

要获取 30 多天前最后使用的播放器,将如下所示:

const availablePlayers = db.collection("available-players");
const now = admin.firestore.Timestamp.now();
const intervalInMillis = 30 * 24 * 60 * 60 * 1000;
const cutoffTime = admin.firestore.Timestamp.fromMillis(now.toMillis() - intervalInMillis);

const query = availablePlayers.where(last_used, "<=", cutoffTime);