Fetch posts for users with a given ID in Firebase & Reactjs - javascript

I have been trying to fetch posts from Firestore for users with a given ID in Reactjs but no success.
I keep getting this error from console;
App.js:64 Uncaught (in promise) TypeError: (0 , firebase_firestore__WEBPACK_IMPORTED_MODULE_12__.getDocs)(...).where is not a function
at getPost (App.js:64:1)
at App.js:69:1
at invokePassiveEffectCreate (react-dom.development.js:23487:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:3945:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:1)
at invokeGuardedCallback (react-dom.development.js:4056:1)
at flushPassiveEffectsImpl (react-dom.development.js:23574:1)
at unstable_runWithPriority (scheduler.development.js:468:1)
at runWithPriority$1 (react-dom.development.js:11276:1)
at flushPassiveEffects (react-dom.development.js:23447:1)
Here is my code;
import React, { useEffect, useState } from 'react'
import { collection, getDocs } from "firebase/firestore";
import { db } from '../firebase-config'
const [posts, setPosts] = useState([])
const postRef = collection(db, "posts")
useEffect(() => {
const getPost = async () => {
const data = await getDocs(postRef)
.where('userId', '==', '12345').orderBy("createdAt").get()
setPosts(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
getPost();
}, []);
My firebase-config.js looks like this;
import { initializeApp } from "firebase/app";
import { getFirestore } from "#firebase/firestore"
const firebaseConfig = {
apiKey: "xzy",
authDomain: "xzy",
databaseURL: "xzy",
projectId: "xzy",
storageBucket: "xzy",
messagingSenderId: "xzy",
appId: "xzy",
};
const app = initializeApp(firebaseConfig)
export const db = getFirestore(app)
If I remove this statement, .where('userId', '==', '12345').orderBy("createdAt").get()
It fetches all the posts from the database which is not what I want. I want to be able to fetch only posts that matches a specific ID.
Any help will be highly appreciated.

You are using the new Firebase Modular SDK that uses a functional syntax instead of the older namespaced one. You now need to use the top-level function query() to build a Query and other QueryConstraints like where, orderBy, limit are also functions. Try refactoring the code as shown below:
import { collection, getDocs, query, where } from "firebase/firestore"
useEffect(() => {
const getPost = async () => {
const q = query(postRef, where("userId", "==", "12345"));
const data = await getDocs(q)
setPosts(data.docs.map((doc) => ({
...doc.data(),
id: doc.id
})));
};
getPost();
}, []);
Also checkout: Firestore: What's the pattern for adding new data in Web v9? and the documentation that includes examples with both the syntaxes.

Related

Can't get all document from collection firebase firestore

I don't understand why I can't get data from firebase firestore database.
my error :
[FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore]
My config file with firebase config is correctly set, I can add Data with this model :
{ item: { ...event, date } }
My files structures : picture of my structure
I have correctly declared my state, I have async await with try catch.
I have used this from firebase documentation
EventList.js
import { FlatList, View, Text, StyleSheet } from "react-native";
import React, { useState, useEffect } from "react";
import { EVENTS_COLLECTION } from "../commons/constants";
import db from "../commons/services/firebase";
const EventList = () => {
const [events, setEvents] = useState([]);
return (
<View>
<FlatList
data={events}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={styles.eventContainer}>
<Text style={styles.eventName}>{item.name}</Text>
<Text style={styles.eventDate}>{item.date.toString()}</Text>
</View>
)}
/>
</View>
);
};
firebase.Js
const firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL:
"",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: "",
};
const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
I try to get all documents from my events collection.
My goal is to make an Calendar with event manager with firebase firestore database
In firebase.js you export db like this:
export const db = getFirestore(app);
This is a named export, therefore you will need a named import:
import { db } from '../commons/services/firebase'
// or
// import * as config from '../commons/services/firebase'
// const db = config.db
The way you import is for default exports and results in your case with undefined. Therefore firebase complains that the first argument to collection is not correct (it's undefined).
You can read more about imports here.
Try this one if EVENTS_COLLECTION returns the name of the collection correctly then you will get all documents otherwise use "Collection Name" where you write EVENTS_COLLECTION.
const fetchEvents= async () => {
await db.collection(EVENTS_COLLECTION).onSnapshot({
error: e => console.error(e),
next: (querySnapshot) => {
var data = [];
var i = 0;
querySnapshot.forEach(doc => {
data.push(doc.data());
console.log(doc.id, " => ", doc.data());
});
setEvents(data)
},
})
};

Data not pulling in from Firestore Collection

I'm working on connecting a Firestore database collection to a Next.js app. The app is very simple, as I am just fetching data and displaying it on the screen. I have a collection with two items in Firestore right now, and I'm trying to get it to console.log() to verify that it is connecting. However, when I do, the console shows me two Arrays, but they don't seem to hold any of the data from my database.
I am currently using this code to log the data to the console:
import React, { useEffect, useState } from 'react'
import {collection, getDocs} from 'firebase/firestore';
import db from '../firebase/config'
import { Box } from '#chakra-ui/react'
import ProductCard from './ProductCard'
const Products = () => {
const [products, setProducts] = useState([])
useEffect(() => {
;(async () => {
const colRef = collection(db, 'products')
const snapshots = await getDocs(colRef)
const docs = snapshots.docs.map((doc) => {
const data = doc.data()
data.id = doc.id
return data
})
setProducts(docs)
console.log(docs)
})()
}, [])
I can provide the rest of the code, if necessary.
My firebase config file looks like this:
import { initializeApp } from "firebase/app";
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = {
apiKey: "---",
authDomain: "---",
projectId: "---",
storageBucket: "---",
messagingSenderId: "---",
appId: "---",
measurementId: "---",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app)
export default db
The Arrays I get look like this:
The database currently looks like this:
Does anybody have an idea, or can point me in the right direction?
Thanks in advance!
From your database screenshot we can deduce that products is not a root collection but a subcollection of a document (which actually does not exist). (See last note at the bottom)
So you need to declare the CollectionReference with the entire path of the (sub)collection. We don't know the name of the root collection and we just see a part of the ID of the parent document (cocoworksco...) but you should declare the subcollection CollectionReference as follows:
let colRef = collection(db, 'rootCollection/cocoworksco.../products');
let querySnapshot = await getDocs(colRef);
// ...
Note that they are many different possibilities to declare the subcollection: For example, collection(db, 'rootCollection', 'cocoworksco...', 'products') or collection(db, 'rootCollection', 'cocoworksco.../products'); are also valid.
Note also that we are actually not sure that the path of the subcollection is composed of three parts since we don't see the full path on the screenshot. It is possible that it is deeper, e.g. rootCollection/doc1/subCol1/cocoworksco.../products.

Problem with onSnapshot Firebase - Uncaught FirebaseError: Expected type 'Ea', but it was: a custom pn object [duplicate]

I am trying to set up Firebase with next.js. I am getting this error in the console.
FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore
This is one of my custom hook
import { onAuthStateChanged, User } from '#firebase/auth'
import { doc, onSnapshot, Unsubscribe } from 'firebase/firestore'
import { useEffect, useState } from 'react'
import { auth, fireStore } from './firebase'
export const useUserData = () => {
const [username, setUsername] = useState<string | null>(null)
const [currentUser, setCurrentUser] = useState<User | null>(null)
useEffect(() => {
let unsubscribe: void | Unsubscribe
onAuthStateChanged(auth, (user) => {
if (user) {
setCurrentUser(user)
// The Problem is inside this try blog
try {
// the onsnapshot function is causing the problem
console.log('firestore: ', fireStore)
unsubscribe = onSnapshot(doc(fireStore, 'users', user.uid), (doc) => {
setUsername(doc.data()?.username)
})
} catch (e) {
console.log(e.message)
}
} else {
setCurrentUser(null)
setUsername(null)
}
})
return unsubscribe
}, [currentUser])
return { currentUser, username }
}
I also have this firebase.ts file where I initialized my firebase app
import { FirebaseApp, getApps, initializeApp } from 'firebase/app'
import { getAuth } from 'firebase/auth'
import { getFirestore } from 'firebase/firestore/lite'
import { getStorage } from 'firebase/storage'
const firebaseConfig = {
apiKey: 'some-api',
authDomain: 'some-auth-domain',
projectId: 'some-project-id',
storageBucket: 'some-storage-bucket',
messagingSenderId: 'some-id',
appId: 'some-app-id',
measurementId: 'some-measurement-id',
}
let firebaseApp: FirebaseApp
if (!getApps.length) {
firebaseApp = initializeApp(firebaseConfig)
}
const fireStore = getFirestore(firebaseApp)
const auth = getAuth(firebaseApp)
const storage = getStorage(firebaseApp)
export { fireStore, auth, storage }
I don't know whether the problem is in the project initialization. I am pretty sure the error is generated from my custom hook file. I also found out that there must be something wrong with onSnapshot function. Am I passing the docRef wrong or something? What am I doing wrong here?
The console.log(firestore) log:
type: "firestore-lite"
_app: FirebaseAppImpl
_automaticDataCollectionEnabled: false
_config: {name: "[DEFAULT]", automaticDataCollectionEnabled: false}
_container: ComponentContainer {name: "[DEFAULT]", providers: Map(15)}
_isDeleted: false
_name: "[DEFAULT]"
_options:
apiKey: 'some-api'
authDomain: 'some-auth-domain'
projectId: 'some-project-id'
storageBucket: 'some-storage-bucket'
messagingSenderId: 'some-id'
appId: 'some-app-id'
measurementId: 'some-measurement-id'
[[Prototype]]: Object
automaticDataCollectionEnabled: (...)
config: (...)
container: (...)
isDeleted: (...)
name: (...)
options: (...)
[[Prototype]]: Object
_credentials: Q {auth: AuthInterop}
_databaseId: H {projectId: "next-firebase-fireship", database: "(default)"}
_persistenceKey: "(lite)"
_settings: ee {host: "firestore.googleapis.com", ssl: true, credentials: undefined, ignoreUndefinedProperties: false, cacheSizeBytes: 41943040, …}
_settingsFrozen: false
app: (...)
_initialized: (...)
_terminated: (...)
Using getFirestore from lite library will not work with onSnapshot. You are importing getFirestore from lite version:
import { getFirestore } from 'firebase/firestore/lite'
Change the import to:
import { getFirestore } from 'firebase/firestore'
From the documentation,
The onSnapshot method and DocumentChange, SnapshotListenerOptions, SnapshotMetadata, SnapshotOptions and Unsubscribe objects are not included in lite version.
Another reason for this error to show up could be passing invalid first argument to collection() or doc() functions. They both take a Firestore instance as first argument.
// Ensure that "db" is defined and initialized
const db = getFirestore();
// console.log(db);
const colRef = collection(db, "collection_name");
Don't mix usage of firestore/lite with firestore
You need to use in your imports either:
'firebase/firestore'
OR
'firebase/firestore/lite'
Not both in the same project.
In your case, the firebase.ts file is using:
import { getFirestore } from 'firebase/firestore/lite'
And in your hook:
import { doc, onSnapshot, Unsubscribe } from 'firebase/firestore'
So you're initialising the lite but using the full version afterwards.
Keep in mind that both has it's benefits, but I would suggest in your case to pick one and just use it. Then the error will be gone.
Adding to #Dharmaraj, if you are using firebase react hooks, use the reverse.
Instead of
import { getFirestore } from 'firebase/firestore'
Use
import { getFirestore } from 'firebase/firestore/lite'
If you are using firebase lite then collection is not used.
Firebase lite example:
import {
getFirestore,
getDoc,
updateDoc,
doc
} from '#firebase/firestore/lite';
const firestore = getFirestore(app);
const docRef = doc(firestore, 'collection/doc');
const docSnap = await getDoc(docRef);
await updateDoc(docRef, "field", 'value');
When to use Firestore Lite
It can be tricky to decide when to let go of the standard Firestore SDK's offline persistence and caching features. You should understand these features before deciding to trade them away for the lower overhead of Firestore Lite. In general, weigh these factors when deciding whether to use Firestore Lite:
Online status - Firestore Lite is good for apps that do not need live updates and have connectivity.
Size constraints - Firestore Lite is great if you want to reduce your overall JavaScript bundle size.
Read more here
This can happen if you have both #firebase/firestore and firebase installed and there is a version mismatch.
firebase comes with #firebase/firestore. Remove any #firebase/... dependencies so that you're using the same version that firebase uses.

Next.js and Firebase keep getting serialization error when trying to read one doc

As the title says, I'm trying to build out a blog site and I have most of it done expect for clicking on a post stub to read the full post. I keep getting this error anytime I go to the post page.
Error: Error serializing .post returned from getServerSideProps in "/posts/[slug]".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value.
I've searched everywhere to try and figure out what I'm doing wrong but can't seem to find the right answer.
Here is by firebase code.
import {
collection,
getDocs,
getFirestore,
limit,
onSnapshot,
orderBy,
query,
doc,
setDoc,
getDoc,
} from "firebase/firestore";
import firebase from "firebase/app";
import { initializeApp, getApps, getApp } from "firebase/app";
import { getAuth, GoogleAuthProvider } from "firebase/auth";
import { Timestamp, toJSON } from "firebase/firestore";
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "AIzaSyAB4SbXl-I1TMoa31ybnCzmTASXjZFnMAg",
authDomain: "personal-blog-8decb.firebaseapp.com",
projectId: "personal-blog-8decb",
storageBucket: "personal-blog-8decb.appspot.com",
messagingSenderId: "473768411808",
appId: "1:473768411808:web:c464d23c531b8bdaa4bfc5",
measurementId: "G-6F04591W4N",
};
if (!getApps().length) {
initializeApp(firebaseConfig);
}
const db = getFirestore();
//Reads all the posts in the database
export const getPosts = async () => {
const q = query(collection(db, "posts"), orderBy("date", "desc"));
const querySnapShot = await getDocs(q);
const posts = querySnapShot.docs.map((doc) => ({
...doc.data(),
id: doc.id,
date: doc.data().date?.toDate().getTime(),
}));
return posts;
};
// Get one post from database based on the slug.
export const getPostBySlug = async (slug) => {
const docRef = doc(db, "posts", `${slug}`);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
return docSnap.data();
} else {
console.log("No Such Document");
}
};
// Adds posts to the database
export const createPost = async (post) => {
await setDoc(doc(db, "posts", `${post.slug}`), {
title: post.title,
content: post.content,
date: Timestamp.fromDate(new Date()),
});
};
export const auth = getAuth();
export const googleAuthProvider = new GoogleAuthProvider();
And here is the slug page.
import { async } from "#firebase/util";
import { useRouter } from "next/router";
import { getPostBySlug } from "../../lib/firebase";
import moment from "moment";
export async function getServerSideProps() {
const post = await getPostBySlug();
return {
props: {
post,
},
};
}
export default function PostPage({ post }) {
<div className="post">
<h1>{post.title}</h1>
<span>Published {moment(post.date).format("LL")}</span>
<p dangerouslySetInnerHTML={{ __html: post.content }}></p>
</div>;
}
Thanks in advance.
So here is how I got it to work. First I changed the firebase read file to a custom query.
// Get one post from database based on the slug.
export const getPostBySlug = async (slug) => {
const q = query(collection(db, "posts"), where("slug", "==", `${slug}`));
const querySnapShot = await getDocs(q);
const post = querySnapShot.docs.map((doc) => ({
...doc.data(),
id: doc.id,
date: doc.data().date?.toDate().getTime(),
}));
return post;
I had to do it this way because of the timestamp I used with firestore. I couldn't figure out any other way to serialize it to json.
Next I changed the getServerSideProps function in the slug js file to take a context query.
export async function getServerSideProps(context) {
const post = await getPostBySlug(context.query.slug);
console.log("this is the severside props: ", post);
return {
props: {
post,
},
};
}
After that it worked fine. There are probably better approached to this but this is what worked for me.

Uncaught ReferenceError: getAuth is not defined

Self taught coder here. Hopefully I'm explaining the issue adequately.
I'm trying to create some user authentication using firebase. I keep getting an error saying "Line 18:16: 'getAuth' is not defined". I'm confused because I was following a tutorial. I have tried reordering my imports as I read online that might be the reason for the error. For some reason I think my problem is in the config file and how I've initialized everything. I'm new to firebase. Any potential solves would be appreciated.
Here is my firebase.js config
import { initializeApp } from "firebase/app";
import { getFirestore } from 'firebase/firestore'
import { getAuth } from "firebase/auth";
import "firebase/storage"
const firebaseConfig = {
apiKey: "process.env.REACT_APP_FIREBASE_KEY",
authDomain: "uploadimg.firebaseapp.com",
projectId: "uploadimgofficial",
storageBucket: "uploadimg.appspot.com",
messagingSenderId: "MESSENGER_ID",
appId: "APP_ID",
measurementId: "MESAUREMENT_ID"
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth()
// Init firestore
const db = getFirestore()
export { db }
And this is where I'm trying to set up the login page
import React from "react";
import "./Login.scss";
import { useState } from "react";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "../../firebase";
const Login = () => {
const [error, setError] = useState(false);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const handleLogin = (e) => {
e.preventDefault();
};
const auth = getAuth(); // <------ THIS IS ERROR LINE
signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
console.log(user)
})
.catch((error) => {
setError(true)
});
return (
<div className="login">
<form onSubmit={handleLogin} className="login__form">
<input
className="login__email"
onChange={e => setNewEmail(e.target.value)}
type="email"
placeholder="email" />
<input
The issue with your code is that you have imported the getAuth function incorrectly.
To fix this, you need to correct the name usage when calling the function.
As you have imported getAuth as auth in the import statement at the top of your file, you need to use it as so.
import { auth } from "../../firebase.js";
Right now, you are importing the auth variable, which is set to the return value of getAuth, as defined below in the firebase.js file.
// As you are calling the function with '()', you are getting the return value.
export const auth = getAuth();
To fix this, simply change your function call to auth. Also, rename the variable to something other than auth to avoid name collisions, and/or confusing naming patterns.
Also, as you are getting and setting the return value of getAuth to auth, the return value may not be a function1. In that case, you can't call auth with brackets (()), as, for instance, it may return an object.
// Change the variable name to what you want.
const userAuth = auth;
To check if it is a string/object/function/etc, you can use typeof (for checking/debugging; remove this line once done).
console.log(typeof auth); // Should return: 'string' | 'function' | 'object' | ...
Depending on the return type, you can change your usage to match it.
In conclusion, to fix your issue, you need to correctly use the name (auth instead of getAuth). Also, make sure to check the return value of getAuth, and use it appropriately!
1 Please correct me in the comments if I am incorrect; the return value is a function. In that case, I can remove that part. Thank you for the clarification!

Categories