I'm trying to add a new document to a non-existing sub-collection in a document(solutionsCollection/docID/commentsSubCollection). But I'm getting this error message when I add a document to the sub-collection:
TypeError: doc is not a function at addSubCollectionDocument
Code to add a new document to a comments
sub-collection:
const addSubCollectionDocument = async (docID, doc) => {
dispatch({ type: "IS_PENDING" })
try {
const docRef = doc(db, c, docID)
const colRef = collection(docRef, "comments")
const addedDocument = await addDoc(colRef, doc)
dispatchIfNotCancelled({ type: "ADDED_DOCUMENT", payload: addedDocument })
return addedDocument
} catch (error) {
console.log(error)
dispatchIfNotCancelled({ type: "ERROR", payload: error })
return null
}
}
handleSubmit function:
const handleSubmit = async (e) => {
e.preventDefault()
try {
const commentToAdd = {
id: Math.floor(Math.random() * 10000),
content: newComment.trim(),
reactions: [],
user: {
userID: user.uid,
avatarURL: user.photoURL,
displayName: user.displayName,
username: user.reloadUserInfo.screenName,
},
replies: [],
createdAt: new Date(),
}
await addSubCollectionDocument(id, commentToAdd)
setNewComment("")
if (response) {
console.log(response.error)
}
} catch (error) {
console.log(error)
}
}
useFirestore hook code:
import { useEffect, useReducer, useState } from "react"
import {
addDoc,
collection,
deleteDoc,
doc,
serverTimestamp,
updateDoc,
} from "firebase/firestore"
import { db } from "../firebase/config"
export const useFirestore = (c) => {
const [response, dispatch] = useReducer(firestoreReducer, initialState)
const [isCancelled, setIsCancelled] = useState(false)
// only dispatch is not cancelled
const dispatchIfNotCancelled = (action) => {
if (!isCancelled) {
dispatch(action)
}
}
// add a document
const addDocument = async (doc) => {
dispatch({ type: "IS_PENDING" })
try {
const createdAt = serverTimestamp()
const addedDocument = await addDoc(collection(db, c), {
...doc,
createdAt,
})
dispatchIfNotCancelled({ type: "ADDED_DOCUMENT", payload: addedDocument })
} catch (err) {
dispatchIfNotCancelled({ type: "ERROR", payload: err.message })
}
}
// Add document to sub collection
const addSubCollectionDocument = async (docID, doc) => {
dispatch({ type: "IS_PENDING" })
try {
const docRef = doc(db, c, docID)
const colRef = collection(docRef, "comments")
const addedDocument = await addDoc(colRef, doc)
dispatchIfNotCancelled({ type: "ADDED_DOCUMENT", payload: addedDocument })
return addedDocument
} catch (error) {
console.log(error)
dispatchIfNotCancelled({ type: "ERROR", payload: error })
return null
}
}
useEffect(() => {
return () => setIsCancelled(true)
}, [])
return {
addDocument,
addSubCollectionDocument,
response,
}
}
File where I'm importing addSubCollectionDocument
hook:
import { useFirestore } from "../../hooks/useFirestore"
import { useAuthContext } from "../../hooks/useAuthContext"
const SolutionComments = ({ solution }) => {
const [newComment, setNewComment] = useState("")
const { user } = useAuthContext()
const { id } = useParams()
const { addSubCollectionDocument, response } = useFirestore("solutions")
const handleSubmit = async (e) => {
e.preventDefault()
try {
const commentToAdd = {
id: Math.floor(Math.random() * 10000),
content: newComment.trim(),
reactions: [],
user: {
userID: user.uid,
avatarURL: user.photoURL,
displayName: user.displayName,
username: user.reloadUserInfo.screenName,
},
replies: [],
createdAt: new Date(),
}
await addSubCollectionDocument(id, commentToAdd)
setNewComment("")
if (response) {
console.log(response.error)
}
} catch (error) {
console.log(error)
}
}
return (...)}
Package.json gist: https://gist.github.com/rishipurwar1/57fbf348cd9755a940e7e3f218de570f
Firebase rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /challenges/{challenge}{
allow read: if true
}
match /resources/{resource}{
allow read: if true
}
match /solutions/{solution}{
allow read: if true
allow create: if request.auth.uid != null;
allow update, delete: if request.auth.uid == resource.data.userID;
}
match /users/{userId}{
allow create: if true
allow read: if true
}
}
}
CodePudding user response:
const addSubCollectionDocument = async (docID, doc) => { ... })
// That "doc" parameter is not a function ^^^
That parameter seems to be an object that you are passing to addSubCollectionDocument()
. Try renaming that to something else like:
const addSubCollectionDocument = async (docID, docData) => {
const colRef = collection(db, c, docID, "comments")
const addedDocument = await addDoc(colRef, doc)
})
You haven't specified security rules for your comments sub-collection. Try adding the following rules:
match /c/{docId}/comments/{commentId} {
allow read, write: if true;
}
Do update the if true
to required rules as per your use case.