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-player
collection。 current-live-player
仅由一份文件组成,每天在伦敦时间 00:00 更新。我只希望 Firestore select 来自 available-players
的 player
文档满足我的上述条件: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);
我需要使用 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-player
collection。 current-live-player
仅由一份文件组成,每天在伦敦时间 00:00 更新。我只希望 Firestore select 来自 available-players
的 player
文档满足我的上述条件: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);