Firebase实时数据库无法删除指定条目及数据结构异常问题
问题概述
我需要在Firebase Realtime Database中创建如下数据结构:
"users": { "JkaThVRqp1cBbKxLBk0UzUtu1tJ3": { "email": "fwwfw@mail.de", "username": "efwfw", "favorite teams": [ "team1", "team2", "team3" ] } }
但目前遇到三个问题:
- 无法删除
"favorite teams"数组:通过控制台或终端删除后,内容会自动重新出现 - 实际生成的数据结构不符合预期:
实际结构:
预期结构:"UID":{"favoriteTeams":{"favoriteTeam":"team","team"}}"UID":{"favoriteTeams":["team","team"]} - 控制台抛出警告:
[Warning] [2024-04-27T11:18:37.683Z] @firebase/database: (firebase-database.js, line 1)
"FIREBASE WARNING: Exception was thrown by user callback. @http://127.0.0.1:5500/resource/javascript/index.js:139:45
onValue@https://www.gstatic.com/firebasejs/10.11.0/firebase-database.js:1:157844
exceptionGuard@https://www.gstatic.com/firebasejs/10.11.0/firebase-database.js:1:19287
eventListRaise@https://www.gstatic.com/firebasejs/10.11.0/firebase-database.js:1:142783
eventQueueRaiseQueuedEventsMatchingPredicate@https://www.gstatic.com/firebasejs/10.11.0/firebase-database.js:1:142509
eventQueueRaiseEventsAtPath@https://www.gstatic.com/firebasejs/10.11.0/firebase-database.js:1:142131
repoAddEventCallbackForQuery@https://www.gstatic.com/firebasejs/10.11.0/firebase-database.js:1:169823
addEventListener@https://www.gstatic.com/firebasejs/10.11.0/firebase-database.js:1:169849
@http://127.0.0.1:5500/resource/javascript/index.js:136:12 "
相关代码
HTML部分
<div> <select id="region" name="Bundesland Auswahl" title="Bundesland"> <option value="" disabled selected>Select a Region</option> <option value="rg1">Region 1</option> </select> <select name="club" id="team" title="team"> <option value="" disabled selected>Select a team</option> </select> <button id="submit" name="newEntry" value="newEntry">Submit</button> </div>
JavaScript部分
document.getElementById("submit").addEventListener("click", function (e) { e.preventDefault(); const teamSelect = document.getElementById("team"); const newFavoriteTeams = Array.from( teamSelect.selectedOptions, (option) => option.value ); const auth = getAuth(); const user = auth.currentUser; if (user) { const userId = user.uid; const favoriteTeamsRef = ref(database, `users/${userId}/favoriteTeams`); onValue(favoriteTeamsRef, (snapshot) => { const existingFavoriteTeams = snapshot.val() || []; const updatedFavoriteTeams = [ ...new Set([...existingFavoriteTeams, ...newFavoriteTeams]), ]; update(favoriteTeamsRef, { favoriteTeams: updatedFavoriteTeams }) .then(() => { alert("Favorite teams updated successfully."); }) .catch((error) => { alert("Error"); }); }); } else { alert("No user is signed in."); } });
Firebase安全规则
{ "rules": { ".read": false, ".write": false, "users": { "$uid": { ".read": "auth.uid === $uid", ".write": "auth.uid === $uid || !data.exists()" } }, "vereine": { ".read": true, ".write": true }, "spiele": { ".read": true, ".write": true } } }
解决方案
1. 修复数据结构异常与控制台警告
原JS代码存在两个核心问题:
- 使用
onValue持续监听数据变化,导致每次更新后触发回调,形成循环写入,这也是删除后数据自动恢复的原因 update的目标路径与参数不匹配:favoriteTeamsRef已经指向users/${userId}/favoriteTeams,却传入{favoriteTeams: updatedFavoriteTeams},导致嵌套结构
修改后的JS代码:
document.getElementById("submit").addEventListener("click", async function (e) { e.preventDefault(); const teamSelect = document.getElementById("team"); const newFavoriteTeams = Array.from( teamSelect.selectedOptions, (option) => option.value ); const auth = getAuth(); const user = auth.currentUser; if (user) { const userId = user.uid; const userRef = ref(database, `users/${userId}`); try { // 仅获取一次用户数据,避免持续监听 const snapshot = await get(userRef); const existingData = snapshot.val() || {}; // 确保现有数据是数组类型,避免非数组导致的扩展运算符报错 const existingFavoriteTeams = Array.isArray(existingData.favoriteTeams) ? existingData.favoriteTeams : []; // 合并并去重 const updatedFavoriteTeams = [...new Set([...existingFavoriteTeams, ...newFavoriteTeams])]; // 直接更新用户节点下的favoriteTeams字段为数组 await update(userRef, { favoriteTeams: updatedFavoriteTeams }); alert("Favorite teams updated successfully."); } catch (error) { alert(`Error: ${error.message}`); } } else { alert("No user is signed in."); } });
2. 解决无法删除数组的问题
修复代码后,停止了不必要的持续监听,此时删除操作不会被代码自动恢复。删除favoriteTeams的方式有两种:
- 清空数组:
await update(userRef, { favoriteTeams: [] }) - 删除整个字段:
await remove(ref(database,users/${userId}/favoriteTeams))
3. 安全规则验证
当前安全规则中,users/$uid的写入权限为auth.uid === $uid || !data.exists(),允许用户创建自己的节点,且仅本人可更新,规则无问题。确保操作时用户已登录,否则会触发权限错误。
内容的提问来源于stack exchange,提问作者Wyral 468B

