how to check if nested docs and collection in firebase exist and if don't how to create, in react native

116 views Asked by At

I am new to Firebase and I have to create a chat system. I found that the doc structure should be nested e.g if a person sends a message, a new doc with its id will be created in the main collection and then a new collection will be added to the doc. now each doc in that nested collection will be considered as a message obj.

a rough sketch of how the new message in the nested document will be added but the problem is when there is no doc with UI exist or no collection in that doc exist

firestore().collection("chatBox").doc(uid).collection("message").add( { text: "this is my first message", user: {_id:356}, avatar: "link of avatar", name: "john", createdAt: new Date().getTime() } )

  const sendMessage = async (messages = []) => {
  const msg = messages[0];

    const id = msg.user?._id?.toString();
    const collectionRef = firestore().collection(CHATBOX);
    const doc = collectionRef.doc(id);
    const docExists = await doc.get().then(function (doc) {
      return doc.exists;
    });
    if (docExists) {
      const collection = doc.collection(MESSAGES);
     const isCollectionEmpty = collection.get().then(col => {
        return col.empty;
      });
      if (isCollectionEmpty) doc.set({id: MESSAGES});//creating new collection
      else collection.add({...msg, createdAt: new Date().getTime()});//inserting doc if collection exist
    } else {
      collectionRef.add(id);// creating doc in main collection
    }
};
1

There are 1 answers

0
samthecodingman On

The ability to create a document only if it does not exist can be done using the following Transaction. Here, the createDocIfNotExist method creates the document with the given data, only if it does not already exist. It returns a Promise<boolean> indicating whether the document was freshly created or not.

async createDocIfNotExist(docRef, initData) {
  return docRef
    .firestore
    .runTransaction((transaction) => {
      const docSnap = await transaction.get(docRef);
      if (docSnap.exists)
        return false; // exists already

      transaction.set(docRef, initData);
      return true; // was created
    });
}

Applying this to your code then gives:

const sendMessage = async (messages = []) => {
  const msg = messages[0];

  const msgUserId = msg.user!._id!.toString(); // id renamed, consider using senderId/recipientId instead

  const chatboxColRef = firestore().collection(CHATBOX); // collectionRef renamed
  const userChatboxDocRef = chatboxColRef.doc(msgUserId); // doc renamed

  const isNewChatbox = await createDocIfNotExist(
    userChatboxDocRef,
    { id: msgUserId }
  );

  const userChatboxMessagesColRef = userChatboxDocRef.collection(MESSAGES); // collection renamed

  return userChatboxMessagesColRef
    .add({
      ...msg,
      createdAt: new Date().getTime() // consider using firebase.firestore.FieldValue.serverTimestamp() instead
    });
};

This can be further reduced to:

const sendMessage = async (messages = []) => {
  const msg = messages[0];

  const msgUserId = msg.user!._id!.toString();

  const userChatboxDocRef = firestore()
    .collection(CHATBOX);
    .doc(msgUserId);

  await createDocIfNotExist(
    userChatboxDocRef,
    { id: msgUserId }
  );

  return userChatboxDocRef
    .collection(MESSAGES)
    .add({
      ...msg,
      createdAt: new Date().getTime()
    });
};

Note: Avoid using the variable name doc as it is ambiguous and could be an instance of DocumentData, DocumentReference, or DocumentSnapshot (at minimum, use docData, docRef and docSnap/docSnapshot respectively). Similarly, use colRef for a CollectionReference and qSnap/querySnap for QuerySnapshot objects.