I'm using Vue.js and firestore to make a landing page for my project, I've tried to make a registration form to make new account for my website.
I've created a collection in my firebase project, named "users", where the user information where stored when the sign up completed. But when I call the function, the error appeared:
Cannot read property 'collection' of undefined
What can I do? I'll share my code here:
Signup.vue
import { Auth, db, usersCollection } from '#/firebase/auth.js'
import * as fb from 'firebase'
import {App} from '#/firebase/app.js'
async addEmail(email,password) {
var noticeMessage = "🎉 Your account has been reserved 🎉"
const {user} = await Auth.createUserWithEmailAndPassword(email, password )
await fb.usersCollection.doc(user.uid).set({
email: email,
password: password,
userId: user.uid,
createdAt: new Date().toISOString(),
})
auth.js
import {App} from './app';
import 'firebase/auth';
import 'firebase/firestore';
import 'firebase/storage';
var config = {
apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
databaseURL: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
projectId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
storageBucket: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
messagingSenderId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
appId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
measurementId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
export const Auth = App.auth();
export const db = App.firestore();
export const usersCollection = db.collection('users')
app.js
import Firebase from 'firebase/app'
import credentials from './credentials'
export const App = Firebase.initializeApp(credentials.config);
async-firestore.js
import firebase from 'firebase/app'
import { isNil } from 'lodash'
let asyncFirestore = null
// Lazy load firestore with async import is important for performance
export default () => {
if (isNil(asyncFirestore)) {
asyncFirestore = import(/* webpackChunkName: "chunk-firestore" */ 'firebase/firestore').then(
() => {
firebase.firestore().settings({})
firebase.firestore().enablePersistence({ synchronizeTabs: true })
return firebase.firestore()
}
)
}
return asyncFirestore
}
generic-db.js
import { isNil, keys, cloneDeep } from 'lodash'
import firebase from 'firebase/app'
import firestore from './async-firestore'
export default class GenericDB {
constructor(collectionPath) {
this.collectionPath = collectionPath
}
/**
* Create a document in the collection
* #param data
* #param id
*/
async create(data, id = null) {
const collectionRef = (await firestore()).collection(this.collectionPath)
const serverTimestamp = firebase.firestore.FieldValue.serverTimestamp()
const dataToCreate = {
...data,
createTimestamp: serverTimestamp,
updateTimestamp: serverTimestamp
}
const createPromise = isNil(id)
? // Create doc with generated id
collectionRef.add(dataToCreate).then(doc => doc.id)
: // Create doc with custom id
collectionRef
.doc(id)
.set(dataToCreate)
.then(() => id)
const docId = await createPromise
return {
id: docId,
...data,
createTimestamp: new Date(),
updateTimestamp: new Date()
}
}
/**
* Read a document in the collection
* #param id
*/
async read(id) {
const result = await (await firestore())
.collection(this.collectionPath)
.doc(id)
.get()
const data = result.exists ? result.data() : null
if (isNil(data)) return null
this.convertObjectTimestampPropertiesToDate(data)
return { id, ...data }
}
/**
* Read all documents in the collection following constraints
* #param constraints
*/
async readAll(constraints = null) {
const collectionRef = (await firestore()).collection(this.collectionPath)
let query = collectionRef
if (constraints) {
constraints.forEach(constraint => {
query = query.where(...constraint)
})
}
const formatResult = result =>
result.docs.map(ref =>
this.convertObjectTimestampPropertiesToDate({
id: ref.id,
...ref.data()
})
)
return query.get().then(formatResult)
}
/**
* Update a document in the collection
* #param data
*/
async update(data) {
const { id } = data
const clonedData = cloneDeep(data)
delete clonedData.id
await (await firestore())
.collection(this.collectionPath)
.doc(id)
.update({
...clonedData,
updateTimestamp: firebase.firestore.FieldValue.serverTimestamp()
})
return id
}
/**
* Delete a document in the collection
* #param id
*/
async delete(id) {
return (await firestore())
.collection(this.collectionPath)
.doc(id)
.delete()
}
/**
* Convert all object Timestamp properties to date
* #param obj
*/
convertObjectTimestampPropertiesToDate(obj) {
const newObj = {}
keys(obj)
.filter(prop => obj[prop] instanceof Object)
.forEach(prop => {
if (obj[prop] instanceof firebase.firestore.Timestamp) {
newObj[prop] = obj[prop].toDate()
} else {
this.convertObjectTimestampPropertiesToDate(obj[prop])
}
})
return {
...obj,
...newObj
}
}
}
init.js
import firebase from 'firebase/app'
import 'firebase/auth'
const config = {
apiKey: ...,
authDomain: ...,
databaseURL: ...,
projectId: ...,
storageBucket: ...,
messagingSenderId: ...,
appId: ...,
}
firebase.initializeApp(config)
users-db.js
import GenericDB from './generic-db'
export default class UsersDB extends GenericDB {
constructor() {
super('users')
}
}
main.js
...
// firebase setup
import './firebase/init'
...
You can do firebase auth like this
import firebase from 'firebase/app'
...
const { user } = await firebase
.auth()
.createUserWithEmailAndPassword(form.email, form.password)
// create a user in firestore `users` table
const userDb = new UsersDB()
const newUser = {
email: form.email,
name: form.name,
}
userDb.create(newUser, user.uid)
...
Related
Good Day,
Please help me figure out how to filter the firestore query to show only the data from today's date.
Here is my React code:
`
const History = () => {
const [codeexplainer, setExamples] = useState([]);
const [user] = useAuthState(auth);
const uid = user ? user.uid : "null";
useEffect(() => {
const fetchData = async () => {
const response = await fetch("/api/code/firebase-config");
const data = await response.json();
setExamples(data);
};
fetchData();
}, []);
const filteredData = useMemo(() => {
if (uid) {
return codeexplainer
.filter((result) => result.uid === uid && result !== undefined)
.sort((a, b) => b.timestamp - a.timestamp)
// .slice(0, 10);
}
return undefined;
}, [codeexplainer, uid])
const datafromfirebase = useMemo(() => {
if (filteredData && filteredData.length > 0) {
return filteredData.map((result) => (
<>
<Examples
code={result.code}
result={result.explanation}
/>
</>
))
} else {
return <p>Hey there! Add some code snippets and come back to see your history here.</p>
}
}, [filteredData])
`
Sample Firestore Data
This is the Firebase Config I am currently using.
Firebase Config:
import { initializeApp } from "firebase/app";
import { getFirestore } from "#firebase/firestore";
import {
collection,
addDoc,
getDocs,
serverTimestamp,
} from "firebase/firestore";
export const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
};
const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
const resultsCollectionRef = collection(db, "codeexplainer");
const profaneCollectionRef = collection(db, "swear");
export default async function firebaseGet(req, res) {
if (req.method === "GET") {
const data = await getDocs(resultsCollectionRef);
const response = data.docs.map((doc) => ({ ...doc.data(), id: doc.id }));
res.status(200).json(response);
}
}
export async function createFirebaseData(code, user, choices, userid) {
await addDoc(resultsCollectionRef, {
code: code,
user: user,
explanation: choices,
timestamp: serverTimestamp(),
uid: userid,
});
}
export async function getFirebaseData(req, res) {
const data = await getDocs(resultsCollectionRef);
const response = data.docs.map((doc) => ({ ...doc.data(), id: doc.id }));
return response;
}
export async function loggedProfane(code, user, userid) {
await addDoc(profaneCollectionRef, {
code: code,
timestamp: serverTimestamp(),
user: user,
uid: userid,
});
}
Thank you.
I have tried the sorting and slice method but it's not working.
I'm new to React.
You are essentially fetching all the documents and the filtering them on the client side. If a user is supposed to read/write their documents only then this is not secure as anyone can read documents of all users and also inefficient as you are loading all the documents everytime just to show a subset. Instead you should use a query and security rules so a user can read their own data only. Try using this query:
import { query, collection, getDocs, where } from "firebase/firestore"
const startOfToday = new Date();
startOfToday.setUTCHours(0,0,0,0);
// Documents created today (after 00:00 UTC)
const q = query(resultsCollectionRef, where("timestamp", ">", startOfToday));
const data = await getDocs(resultsCollectionRef);
const response = data.docs.map((doc) => ({ ...doc.data(), id: doc.id }));
You don't need any filtering or sorting on client side and can simply map the data into UI.
I am currently trying to make an account page for users using data from Firebase auth, database, and storage. The only problem with the code is that the text and images that need data from the database(username and profile picture) are appearing as undefined so it seems like the database isn't returning data
the code:
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.13.0/firebase-app.js"
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut, onAuthStateChanged } from 'https://www.gstatic.com/firebasejs/9.13.0/firebase-auth.js';
import { getDatabase, set, ref } from 'https://www.gstatic.com/firebasejs/9.13.0/firebase-database.js';
import { getStorage, ref as storageRef, getDownloadURL } from 'https://www.gstatic.com/firebasejs/9.13.0/firebase-storage.js'
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
};
//Initiate firebase services
const app = initializeApp(firebaseConfig);
const auth = getAuth(app)
const database = getDatabase(app)
const storage = getStorage(app)
//Get image folder from storage
const imageFolder = storageRef(storage, "gs://betterbadgeworld.appspot.com/profile-pictures")
//Get user UID and accountData
let user = onAuthStateChanged(auth, (user)=>{
if (user) {
var user = auth.currentUser
return user
}
else {
return
}
})
let accountData = onAuthStateChanged(auth, (user)=>{
if (user) {
var userUID = user.uid
var accountData = ref(database, 'users/' + user.uid)
console.log(accountData)
return accountData
}
else {
return
}
})
//Add username and profile picture to website with accountData
function initializeData(accountData) {
//Get profile picture file name
let userProfilePicture = accountData.profilePicture + ".png"
//Set username in text box
const usernameText = document.createTextNode(accountData.username)
const usernameBox = document.getElementById('username')
usernameBox.appendChild(usernameText)
//Get profile picture div, make gs:// link, and get downloadURL for it
const profilePicBox = document.getElementById("profile-picture")
var profileGSLink = imageFolder + "/" + userProfilePicture
var profileLink = getDownloadURL(storageRef(storage, profileGSLink))
//Make image element and use profileLink as source
let img = document.createElement("img");
img.src = profileLink;
profilePicBox.appendChild(img);
}
initializeData(accountData)
the code that isn't returning the data:
let accountData = onAuthStateChanged(auth, (user)=>{
if (user) {
var accountData = ref(database, 'users/' + user.uid)
console.log(accountData)
return accountData
}
else {
return
}
})
I'm trying to interact with the database in a function, but I'm getting an error when trying to use the doc() function within a firebase function
The error im getting is: " Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app).
"
See the code below and the function I'm getting the error on.
Im guessing in has something to do with not being able to use the db variable? But if I cant do that, how do I interact with the database?
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import {
collectionGroup, doc, getDoc,
getDocs,
getFirestore,
query,
} from "firebase/firestore";
// Sendgrid Config
import sgMail from "#sendgrid/mail";
import {
ClientUserData,
Course,
EventType,
Task,
} from "../../src/views/types/interfaces";
import {startOfDay} from "date-fns";
const adminApp = admin.initializeApp();
const auth = adminApp.auth();
const db = getFirestore();
//THE FUNCTION IT FAILS ON
export const checkCourseForNewClientProgram = functions.pubsub.schedule("Every day").onRun(async () => {
const courses: Course[] = [];
const coursesByCompanies = query(collectionGroup(db, "courses"));
// eslint-disable-next-line max-len
const checkCourseForNewClientProgramSnapshot = await getDocs(coursesByCompanies);
checkCourseForNewClientProgramSnapshot.forEach((courseSnapshot) => {
const course = courseSnapshot.data() as Course;
if (course.events && course.events.length > 0) {
const courseEvents = course.events;
const todayDate = startOfDay(new Date()).getTime();
courseEvents.forEach((event) => {
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore
// eslint-disable-next-line max-len
const eventStart = convertFirebaseDateIntoJSDate(event.start.seconds).getTime();
if (todayDate === eventStart) {
courses.push(course);
}
if (event.type === EventType.TASK) {
const eventLessons = (event as Task).lessons;
if (eventLessons && eventLessons.length > 0) {
eventLessons.forEach((eventLesson) => {
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore
// eslint-disable-next-line max-len
const lessonStart = convertFirebaseDateIntoJSDate(eventLesson.start.seconds).getTime();
if (todayDate === lessonStart) {
courses.push(course);
}
});
}
}
});
}
});
let userIds: string[] = [];
courses.forEach((course) => {
if (course.users) {
userIds = course.users.map((userId) => userId);
}
});
const userEmails = await Promise.all(
userIds.map(async (userId) => {
// eslint-disable-next-line max-len
const userData = await getDocumentFromId<ClientUserData>("company_clients", userId);
return userData.email;
})
);
await Promise.all(
userEmails.map(async (userEmail) => {
const msg = {
to: userEmail,
from: "nicky#byplayart.dk",
templateId: "d-8609d087e96e42d5abe6991d19afb22d",
dynamic_template_data: {
email: userEmail,
toName: "Testing tasks",
fromName: "Unlimited Performance",
subject: "Du har en opgave der venter",
text: "Dette er din tekst",
},
};
try {
await sgMail.send(msg);
return {
success: true,
};
} catch (e) {
return {
success: false,
error: e,
};
}
})
);
});
With the Admin SDK version 9 you should use the namespaced syntax, similarly to the Client SDK v8. The corresponding reference for the Admin DSK is actually the Node.js one.
Your code should then been adapted as follows:
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp();
const db = admin.firestore();
export const checkCourseForNewClientProgram = functions.pubsub.schedule("Every day").onRun(async () => {});
const coursesByCompanies = db.collectionGroup("courses");
const checkCourseForNewClientProgramSnapshot = await coursesByCompanies.get();
checkCourseForNewClientProgramSnapshot.forEach((courseSnapshot) => {...});
//...
return null;
});
Don't forget to correctly terminate your Cloud Function, either by returning the Promise returned by the last Promise.all() call or a value (e.g. return null;) after all the asynchronous work is complete. This is a key point and I would suggest you read this part of the doc and watch the 3 videos about "JavaScript Promises" from the Firebase video series.
Error message:
TypeError: _this.db is not a function
Code:
import app from "firebase/app";
import "firebase/auth";
import "firebase/database";
const config = {
apiKey: "some-api-key",
authDomain: "myapp.firebaseapp.com",
databaseURL: "https://myapp.firebaseio.com",
projectId: "aofndiuf",
storageBucket: "project-somenumber.appspot.com",
messagingSenderId: "793813245724y6597"
};
class Firebase {
constructor() {
app.initializeApp(config);
this.auth = app.auth();
this.db = app.database();
}
// Auth API
doCreateNewsletter = (news, name, description, email) => {
const newsletter = { news, name, description, email };
const newPostKey = this.db()
.ref()
.child("newsletters")
.push().key;
return this.db
.ref()
.child("/newsletters/" + newPostKey)
.set(newsletter);
};
You assigned this.db like this:
this.db = app.database();
But then you refer to it later like this:
const newPostKey = this.db()
...
The object returned from app.database() isn't a function, so you can't call it like a function as you are now. It's a Database object. Perhaps you can just get rid of those parenthesis to make your code work the way you intended.
I am trying to retrieve the data from firebase database.
And I can connect to firebase auth and check currentUser data, it's fine.
But I can't retrieve the data from firebase database, it just return the empty array.
firebase version = 5.0.4
vue version = 2.5.16
The database structure
users/
--------uId/
--------------name
--------------email
Vue Js folder structure
App.vue
firebase.js
main.js
components /
------------ Home.vue
firebase.js
var firebase = require('firebase');
require("firebase/auth");
require("firebase/database");
var config = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "..."
};
firebase.initializeApp(config)
export const auth = firebase.auth();
export const db = firebase.database()
Home.vue
<script>
import {db} from './../firebase';
import {auth} from './../firebase';
var usersRef = db.ref('users');
export default {
name: "Home",
components: {
add_new
},
data(){
return {}
},
mounted: function(){
console.log(usersRef);
var userId = auth.currentUser.uid;
return db.ref('/users/' + userId).once('value').then(function(snapshot) {
snapshot.forEach(function (childData) {
console.log(childData.val())
})
})
}
}
</script>
Here, Vue app works correctly,
only the firebase.database ( usersRef ) returns the empty array.
This is the screenshot of console.log(usersRef) result
https://i.stack.imgur.com/NH7gh.png
First instead of using multiple import statements, why not
import {auth, db} from './../firebase';
And try to change
snapshot.forEach(function (childData) {
console.log(childData.val())
})
to snapshot.val()
var userId = auth.currentUser.uid;
return db.ref('/users/' + userId).once('value').then(function(snapshot) {
console.log(snapshot.val());
});