You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase数据库Guest状态节点删除失败问题求助

Firebase数据库删除Guest的status字段未生效问题

我希望点击Check In按钮时删除Firebase数据库中Guest的status字段,但该操作未生效。相关代码如下:

ShareViewModel代码

class ShareViewModel: ViewModel() {
    var firstName : MutableState<String?> = mutableStateOf(null)

    private val _selectedGuest = MutableLiveData<Guest>()
    val selectedGuest: LiveData<Guest> get() = _selectedGuest

    fun setSelectedGuest(guest: Guest) {
        _selectedGuest.value = guest
    }

    // 更新Firebase中访客状态
    fun updateGuestStatus(status: String) {
        val currentGuest = _selectedGuest.value
        currentGuest?.let {
            it.status = status
            updateStatusInFirebase(it)
            _selectedGuest.value = it
        }
    }

    // 删除Firebase中访客的status字段
    fun deleteGuestStatus() {
        val currentGuest = _selectedGuest.value
        currentGuest?.let {
            it.status = ""// 原计划通过设空标记删除
            Log.d("DeleteGuestStatus", "Deleting status for guest: ${it.id}")
            updateStatusInFirebase(it)
            _selectedGuest.value = it
        }
    }

    // 获取访客当前状态
    fun getGuestStatus(): String? {
        return _selectedGuest.value?.status
    }

    private fun updateStatusInFirebase(guest: Guest) {
        val user = FirebaseAuth.getInstance().currentUser
        val userUid = user?.uid

        if (userUid != null) {
            val database = FirebaseDatabase.getInstance()
            val guestsRef = database.getReference("users/$userUid/guests")

            // 假设guest.id是访客的唯一标识
            val guestId = guest.id

            // 使用setValue(null)删除status字段
            guestsRef.child(guestId).child("status").setValue(null)
        }
    }
}

SecurityScreen代码

@Composable
fun SecurityScreen(navController: NavController, shareViewModel: ShareViewModel) {

    var guests by remember {
        mutableStateOf<List<Guest>>(emptyList())
    }
    var selectedGuest by remember { mutableStateOf<Guest?>(null) }
    val database = FirebaseDatabase.getInstance()
    val usersRef = database.getReference("users")

    LaunchedEffect(usersRef) {
        // 添加所有用户数据的监听
        usersRef.addValueEventListener(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                val allGuests = mutableListOf<Guest>()

                // 遍历每个用户的访客列表
                for (userSnapshot in snapshot.children) {
                    val guestsSnapshot = userSnapshot.child("guests")
                    for (guestSnapshot in guestsSnapshot.children) {
                        val guest = guestSnapshot.getValue(Guest::class.java)
                        guest?.let { allGuests.add(it) }
                    }
                }

                // 更新访客列表
                guests = allGuests
            }

            override fun onCancelled(error: DatabaseError) {
                // 处理错误
            }
        })
    }

    fun deleteGuestStatus(guest: Guest) {
        shareViewModel.setSelectedGuest(guest)
        shareViewModel.deleteGuestStatus()
    }

    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Security Department",
            modifier = Modifier
                .padding(bottom = 16.dp)
                .fillMaxWidth(),
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            textAlign = TextAlign.Center
        )

        LazyColumn(
            content = {
                items(
                    items = guests.chunked(4), // 每一行显示4个访客
                    itemContent = { rowItems ->
                        Row(modifier = Modifier.fillMaxWidth(),
                            horizontalArrangement = Arrangement.SpaceEvenly) {
                            rowItems.forEach { guest ->
                                GridItem(
                                    guest = guest,
                                    onClick = { selectedGuest = guest },
                                    onCheckInClick =  { deleteGuestStatus(guest) }
                                )
                            }
                        }
                    }
                )
            }
        )
        // 点击访客卡片后显示详情弹窗
        selectedGuest?.let { guest ->
            Dialog(
                onDismissRequest = { selectedGuest = null },
                properties = DialogProperties(
                    dismissOnBackPress = true,
                    dismissOnClickOutside = true
                )
            ) {

                Column(
                    modifier = Modifier
                        .padding(16.dp)
                        .clip(RoundedCornerShape(10.dp))
                        .background(MaterialTheme.colorScheme.background)
                        .fillMaxWidth()
                ) {
                    Text(
                        text = "Name: ${guest.name}",
                        fontSize = 18.sp,
                        fontWeight = FontWeight.Bold,
                        modifier = Modifier.padding(8.dp)
                    )
                    Text(
                        text = "Contact: ${guest.phoneNumber}",
                        fontSize = 18.sp,
                        modifier = Modifier.padding(
                            start = 8.dp,
                            end = 8.dp,
                            bottom = 16.dp
                        )
                    )
                    Row(
                        verticalAlignment = Alignment.CenterVertically,
                        modifier = Modifier,
                    ) {
                        TextButton(onClick = {
                            // 点击Check In时删除status字段
                            deleteGuestStatus(guest)
                        }) {
                            Text(text = "Check In",
                                fontSize = 20.sp,
                                fontWeight = FontWeight.Bold,)
                        }
                        Spacer(modifier = Modifier.weight(1f))
                        TextButton(onClick = { /*TODO*/ }) {
                            Text(text = "Check Out",
                                fontSize = 20.sp,
                                fontWeight = FontWeight.Bold,)
                        }
                    }

                }
            }
        }
    }
}

@Composable
fun GridItem(guest: Guest, onClick: () -> Unit, onCheckInClick: () -> Unit) {

    Card(
        shape = CircleShape,
        colors = CardDefaults.cardColors(
            containerColor = MaterialTheme.colorScheme.primary
        ),
        modifier = Modifier
            .size(75.dp)
            .padding(8.dp)
            .clickable(onClick = onClick)
    ) {
        Text(
            text = guest.randomNumbers.joinToString(","),
            modifier = Modifier
                .fillMaxSize()
                .wrapContentSize(Alignment.Center),
            fontSize = 18.sp,
            fontWeight = FontWeight.Bold,
            textAlign = TextAlign.Center,
            color = MaterialTheme.colorScheme.onPrimary
        )
    }
}

数据库截图

数据库截图


问题分析与解决方法

核心问题

当前updateStatusInFirebase方法用当前登录用户的uid构建数据库路径,但SecurityScreen的逻辑是遍历所有用户的访客数据,点击的访客可能属于其他用户,导致路径错误,无法定位到目标访客的status字段,删除操作自然无效。

解决步骤

  1. 给Guest类添加userId字段
    在Guest数据类中新增userId: String?字段,存储该访客所属用户的uid,可添加@PropertyName("userId")注解保证和数据库字段名一致。

  2. 修改监听逻辑,保存访客所属的userId
    在SecurityScreen的onDataChange方法中,获取每个访客对应的用户uid并赋值:

    override fun onDataChange(snapshot: DataSnapshot) {
        val allGuests = mutableListOf<Guest>()
        for (userSnapshot in snapshot.children) {
            val userId = userSnapshot.key // 获取当前用户节点的uid
            val guestsSnapshot = userSnapshot.child("guests")
            for (guestSnapshot in guestsSnapshot.children) {
                val guest = guestSnapshot.getValue(Guest::class.java)
                guest?.let {
                    it.userId = userId // 给访客绑定所属用户uid
                    allGuests.add(it)
                }
            }
        }
        guests = allGuests
    }
    
  3. 修正数据库路径,使用访客所属的userId
    修改ShareViewModel中的updateStatusInFirebase方法,基于访客的userId构建正确路径,并添加操作结果监听便于排查问题:

    private fun updateStatusInFirebase(guest: Guest) {
        val guestUserId = guest.userId
        if (!guestUserId.isNullOrEmpty() && !guest.id.isNullOrEmpty()) {
            val database = FirebaseDatabase.getInstance()
            val guestsRef = database.getReference("users/$guestUserId/guests")
            guestsRef.child(guest.id).child("status").setValue(null)
                .addOnCompleteListener { task ->
                    if (task.isSuccessful) {
                        Log.d("DeleteGuestStatus", "Status deleted successfully for guest: ${guest.id}")
                    } else {
                        Log.e("DeleteGuestStatus", "Failed to delete status", task.exception)
                    }
                }
        } else {
            Log.e("DeleteGuestStatus", "Guest's userId or id is null/empty")
        }
    }
    
  4. 清理冗余代码
    deleteGuestStatus方法中it.status = ""是冗余操作,Firebase通过setValue(null)删除字段,若Guest的status是可空类型,可改为it.status = null同步ViewModel数据,否则直接删除该行即可。


内容的提问来源于stack exchange,提问作者Dox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:10:57