Search code examples
pythonfirebasegoogle-cloud-platformgoogle-cloud-firestore

How to delete a key:value pair from Firebase map?


I have some code for managing a friend system using Firebase. The issue I am having is when a user accepts a friend request the request can be deleted. So this involves adding user1 to user2's friends and user2 to user1's friends then removing user2 from user1's 'ownRequests' and removing user1 from user2's 'friendRequests'. I am trying to use Firestore's DELETE_FIELD but it does not appear to work.

The schema is:

Firestore-root
  |
  --- users (collection)
  |    |
  |    --- $userOneUid (document)
  |    |     |
  |    |     --- //User data
  |    |
  |    --- $userTwoUid (document)
  |    |     |
  |    |     --- //User data
  |    |
  |    --- $userThreeUid (document)
  |          |
  |          --- //User data
  |
  --- requests (collection)
       |
       --- $userOneUid (document)
       |     |
       |     --- ownRequests (map)
       |     |      |
       |     |      --- $userTwoUid
       |     |             |
       |     |             --- displayName: "User Two"
       |     |             |
       |     |             --- photoUrl: "https://"
       |     |             |
       |     |             --- status: "requested"
       |     |
       |     --- friendRequests (map)
       |     |      |
       |     |      --- $userThreeUid
       |     |             |
       |     |             --- displayName: "User Three"
       |     |             |
       |     |             --- photoUrl: "https://"
       |     |             |
       |     |             --- status: "requested"
       |     |
       |     --- allFriends (map)
       |            |
       |            --- //All friends
       |
       --- $userTwoUid (document)
       |     |
       |     --- friendRequests (map)
       |            |
       |            --- $userOneUid
       |                   |
       |                   --- displayName: "User One"
       |                   |
       |                   --- photoUrl: "https://"
       |                   |
       |                   --- status: "requested"
       |
       --- $userThreeUid (document)
             |
             --- ownRequests (map)
                    |
                    --- $userOneUid
                           |
                           --- displayName: "User One"
                           |
                           --- photoUrl: "https://"
                           |
                           --- status: "requested"

enter image description here

# accept/reject friend request
@router.post("/accept_friend_request")
def accept_friend_request(friend_req: FriendRequest): # pass req uid and accept uid
    requester_ref = db.collection('Requests').document(friend_req.requester)
    recipient_ref = db.collection('Requests').document(friend_req.recipient)
    transaction = db.transaction()
    try:
        transaction = db.transaction()
        accept_friend_request_transaction(transaction, requester_ref, recipient_ref, friend_req)
        transaction.commit()
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@firestore.transactional
def accept_friend_request_transaction(transaction: Transaction, requester_ref, recipient_ref, friend_req: FriendRequest):
    requester_doc = requester_ref.get(transaction=transaction)
    recipient_doc = recipient_ref.get(transaction=transaction)

    if requester_doc.exists and recipient_doc.exists:
        transaction.update(recipient_ref, {
            f'allFriends.{friend_req.requester}': 'true' 
        })
        transaction.update(requester_ref, {
            f'allFriends.{friend_req.recipient}': 'true'
        })
        transaction.update(requester_ref, {
            f'ownRequests.{friend_req.recipient}': firestore.DELETE_FIELD 
        })
        transaction.update(recipient_ref, {
            f'friendRequests.{friend_req.requester}': firestore.DELETE_FIELD
        })

The updating of the appropriate friends lists works but deleting the requests from the respective maps does not delete them. I tried using firestore.DELETE_FIELD but that does not appear to work correctly and I am not sure why.


Solution

  • If you want to delete the key-value pair status: "accepted" that exists inside the nested Map in the Firestore document, then you have to create a reference that points to that document:

    doc_ref = db.collection('Requests').document('2Bxq...RFv2')
    

    Localize the key-value pair inside the document and call update like below:

    doc_ref.update({'allFriends.XaTx...Yn72.status': firestore.DELETE_FIELD})
    //                        👆          👆
    

    The key to solving this problem is to use the . (dot) to dig inside the Map field.