Firestore - 删除大量文档而没有并发问题
Firestore - Deleting lot of documents without concurrency issues
我使用 Firestore 开发了一款游戏,但我注意到我的预定云功能存在一些问题,该功能会删除 5 分钟前创建但未满的房间 或 完成.
为此,我运行下面的代码。
async function deleteExpiredRooms() {
// Delete all rooms that are expired and not full
deleteExpiredSingleRooms();
// Also, delete all rooms that are finished
deleteFinishedRooms();
}
删除已完成的房间似乎可以正常工作:
async function deleteFinishedRooms() {
const query = firestore
.collection("gameRooms")
.where("finished", "==", true);
const querySnapshot = await query.get();
console.log(`Deleting ${querySnapshot.size} expired rooms`);
// Delete the matched documents
querySnapshot.forEach((doc) => {
doc.ref.delete();
});
}
但是我在删除5分钟前创建的未满的房间时遇到并发问题(一个房间满了当2个用户在房间里,这样游戏才能开始)。
async function deleteExpiredSingleRooms() {
const currentDate = new Date();
// Calculate the target date
const targetDate = // ... 5 minutes ago
const query = firestore
.collection("gameRooms")
.where("full", "==", false)
.where("createdAt", "<=", targetDate);
const querySnapshot = await query.get();
console.log(`Deleting ${querySnapshot.size} expired rooms`);
// Delete the matched documents
querySnapshot.forEach((doc) => {
doc.ref.delete();
});
}
因为在删除房间的过程中,用户可以在房间完全删除之前进入。
有什么想法吗?
注意:搜索房间我使用的是交易
firestore.runTransaction(async (transaction) => {
...
const query = firestore
.collection("gameRooms")
.where("full", "==", false);
return transaction.get(query.limit(1));
});
您可以使用 BatchWrites:
const query = firestore
.collection("gameRooms")
.where("full", "==", false)
.where("createdAt", "<=", targetDate);
const querySnapshot = await query.get();
console.log(`Deleting ${querySnapshot.size} expired rooms`);
const batch = db.batch();
querySnapshot.forEach((doc) => {
batch.delete(doc.ref);
});
// Commit the batch
batch.commit().then(() => {
// ...
});
A batched write can contain up to 500 operations. Each operation in
the batch counts separately towards your Cloud Firestore usage.
这应该立即删除符合该条件的所有房间。使用循环删除它们可能需要一段时间,因为它会一个接一个地发生。
如果您担心批量写入中 500 个文档的限制,请考虑使用 Promise.all,如下所示:
const deleteOps = []
querySnapshot.forEach((doc) => {
deleteOps.push(doc.ref.delete());
});
await Promise.all(deleteOps)
现在为了防止用户加入正在删除的房间,在 Cloud Functions 中这样做有点困难,因为所有实例 运行 独立并且可能存在竞争条件。
为避免这种情况,您必须手动检查用户尝试加入的房间是否超过 5 分钟并且玩家数量是否较少。这只是一个检查,以确保房间正在被删除或将被立即删除。
function joinRoom() {
// isOlderThanMin()
// hasLessNumOfPlayers()
// return 'Room suspended'
}
因为过滤哪些房间应该被删除的逻辑是相同的,所以这应该不是问题。
也许您正在寻找 交易 请在此处查看文档:https://firebase.google.com/docs/firestore/manage-data/transactions
或观看解释并发问题以及 批量写入 和 事务 之间差异的 YouTube 视频:https://youtu.be/dOVSr0OsAoU
我使用 Firestore 开发了一款游戏,但我注意到我的预定云功能存在一些问题,该功能会删除 5 分钟前创建但未满的房间 或 完成.
为此,我运行下面的代码。
async function deleteExpiredRooms() {
// Delete all rooms that are expired and not full
deleteExpiredSingleRooms();
// Also, delete all rooms that are finished
deleteFinishedRooms();
}
删除已完成的房间似乎可以正常工作:
async function deleteFinishedRooms() {
const query = firestore
.collection("gameRooms")
.where("finished", "==", true);
const querySnapshot = await query.get();
console.log(`Deleting ${querySnapshot.size} expired rooms`);
// Delete the matched documents
querySnapshot.forEach((doc) => {
doc.ref.delete();
});
}
但是我在删除5分钟前创建的未满的房间时遇到并发问题(一个房间满了当2个用户在房间里,这样游戏才能开始)。
async function deleteExpiredSingleRooms() {
const currentDate = new Date();
// Calculate the target date
const targetDate = // ... 5 minutes ago
const query = firestore
.collection("gameRooms")
.where("full", "==", false)
.where("createdAt", "<=", targetDate);
const querySnapshot = await query.get();
console.log(`Deleting ${querySnapshot.size} expired rooms`);
// Delete the matched documents
querySnapshot.forEach((doc) => {
doc.ref.delete();
});
}
因为在删除房间的过程中,用户可以在房间完全删除之前进入。
有什么想法吗?
注意:搜索房间我使用的是交易
firestore.runTransaction(async (transaction) => {
...
const query = firestore
.collection("gameRooms")
.where("full", "==", false);
return transaction.get(query.limit(1));
});
您可以使用 BatchWrites:
const query = firestore
.collection("gameRooms")
.where("full", "==", false)
.where("createdAt", "<=", targetDate);
const querySnapshot = await query.get();
console.log(`Deleting ${querySnapshot.size} expired rooms`);
const batch = db.batch();
querySnapshot.forEach((doc) => {
batch.delete(doc.ref);
});
// Commit the batch
batch.commit().then(() => {
// ...
});
A batched write can contain up to 500 operations. Each operation in the batch counts separately towards your Cloud Firestore usage.
这应该立即删除符合该条件的所有房间。使用循环删除它们可能需要一段时间,因为它会一个接一个地发生。
如果您担心批量写入中 500 个文档的限制,请考虑使用 Promise.all,如下所示:
const deleteOps = []
querySnapshot.forEach((doc) => {
deleteOps.push(doc.ref.delete());
});
await Promise.all(deleteOps)
现在为了防止用户加入正在删除的房间,在 Cloud Functions 中这样做有点困难,因为所有实例 运行 独立并且可能存在竞争条件。
为避免这种情况,您必须手动检查用户尝试加入的房间是否超过 5 分钟并且玩家数量是否较少。这只是一个检查,以确保房间正在被删除或将被立即删除。
function joinRoom() {
// isOlderThanMin()
// hasLessNumOfPlayers()
// return 'Room suspended'
}
因为过滤哪些房间应该被删除的逻辑是相同的,所以这应该不是问题。
也许您正在寻找 交易 请在此处查看文档:https://firebase.google.com/docs/firestore/manage-data/transactions
或观看解释并发问题以及 批量写入 和 事务 之间差异的 YouTube 视频:https://youtu.be/dOVSr0OsAoU