i am facing issue i am trying to get only 10 data from firebase but how can i achieve that if ref(database, "messages/").limitToFirst(10) is throwing:
ref(...).limitToFirst is not a function
My code:
const newMsg = ref(database, 'messages/').limitToFirst(10);
onChildAdded(newMsg, (data) => {
if(data.val().name != name){
var divData = '<div class="message"><div class="others">'+data.val().name+': </div><div>'+data.val().message+'</div></div>';
//oponent message
$("#chat-history").append(divData);
}else{
var divData = '<div class="message"><div class="user">'+data.val().name+': </div><div>'+data.val().message+'</div></div>';
//sent message
$("#chat-history").append(divData);
}
});
Where database is
const app = initializeApp(firebaseConfig);
const database = getDatabase(app);
And my imports look like this:
import {initializeApp} from "https://www.gstatic.com/firebasejs/9.6.6/firebase-app.js";
import {
getDatabase,
set,
ref,
push,
child,
onValue,
onChildAdded
} from "https://www.gstatic.com/firebasejs/9.6.6/firebase-database.js";
EDIT:
After a hour i see where is the problem in my import i need to add query, limitToLast
import {
getDatabase,
set,
ref,
query,
push,
child,
onValue,
onChildAdded,
limitToLast
} from "https://www.gstatic.com/firebasejs/9.6.6/firebase-database.js";
And in my function just call it like this:
const newMsg = query(ref(database, 'messages/'), limitToLast(10));
onChildAdded(newMsg, (data) => {
In the new Modular SDK (v9.0.0+), you can build a Query using query() function (instead of chaining the QueryConstraints):
import { ref, query, limitToFirst } from "firebase/database"
const newMsg = query(ref(database, 'messages/'), limitToFirst(10))
onChildAdded(newMsg, (data) => {
// ...
})
The new SDK uses a functional syntax unlike the older name-spaced one so limitToFirst is a top-level function now as in above code snippet.
Also checkout:
How to read, write and query data in Firebase Realtime Database using Firebase SDK v9 (Modular)
Working with lists of data
Related
I'm trying to learn Firestore Cloud 9 using a tutorial written for Web version 8. I am stuck trying to refactor what appears to be a subcollection of some sort.
The Web 8 code looks like this:
const ref = firestore.collection('users').doc(auth.currentUser.uid).collection('posts');
const query = ref.orderBy('createdAt');
const [querySnapshot] = useCollection(query);
My (failed) attempt looks something like this:
import { firestore, auth, serverTimestamp } from "#/lib/firebase";
import { collection, getDocs, orderBy, query } from "firebase/firestore";
import { useRouter } from "next/router";
import { useCollection } from "react-firebase-hooks/firestore";
const ref = collection(firestore, 'users');
const q = query(
ref,
where('username', '==', auth.currentUser.uid),
orderBy('createdAt', 'desc')
);
//const newPosts = (await getDocs(q)).docs.map((doc) => doc.data());
const [querySnapshot] = useCollection(q);
I can get the first collection without issue. However grabbing the subcollection (?) via the doc(ument) isn't something I can figure out. I've tried getDocs() (commented out, above) as well as getDoc() & .doc.
This line in the v8 and before syntax:
const ref = firestore.collection('users').doc(auth.currentUser.uid).collection('posts');
Will look like this in v9 and later:
const ref = collection(firestore, 'users', auth.currentUser.uid, 'posts');
I am getting the following error when trying to get all documents from a collection in Firestore using firebase admin SDK:
[nuxt] [request error] Expected first argument to collection() to be a
CollectionReference, a DocumentReference or FirebaseFirestore
I am testing via a simple console.log:
/server/api/posts.js:
import { firestore } from '../utils/firebase'
import { collection, getDocs } from 'firebase/firestore'
export default defineEventHandler(async (event) => {
const colRef = collection(firestore, 'posts')
console.log(colRef)
})
Here is how I am initializing firestore:
/server/utils/firebase.js:
import { initializeApp, cert } from 'firebase-admin/app'
import { getFirestore } from 'firebase-admin/firestore'
import serviceAccount from '../../service-account.json'
export const app = initializeApp({
credential: cert(serviceAccount)
})
export const firestore = getFirestore()
Note: The following code works on the server-side and I am able to get a document back, but for some reason I can't use the collection() like in the above example.
import { firestore } from '../utils/firebase'
export default defineEventHandler(async (event) => {
const ref = firestore.doc(`animals/dog`)
const snapshot = await ref.get()
const data = snapshot.data()
console.log(data)
// return {
// data
// }
})
Also, if I run the collection() function on the client side, I can successfully retrieve the posts. I just can't figure out why it won't work server-side.
Anyone know why I get the above error?
None of the server code you have shared align to such an error message. The error indicates that you are calling .get() or .onSnapshot() with something that is not a DocumentReference or a CollectionReference.
Note: collection() and doc() are functions that return References. They don't actually communicate to the FS service...a Reference is (essentially) a string such as `/posts' or '/posts/1234567'
So, somewhere in your code, you need to find where it is hitting the above error and either share it here or understand why what you are calling it on is not a valid CollectionReference or DocumentReference.
I've used the new tree-shakeable version of Firebase SDK, which still seems to produce quite a large chunk, considering what I use it for.
I only use the Firestore part, and have actually moved all Firestore operations to the backend, the only thing I'm doing on the front end is initiating the Firebase app instance and starting a snapshot listener (due to the real-time ability), yet the bundle produced is still 275kb large.
import { initializeApp } from 'firebase/app'
import { getFirestore, collection, doc, onSnapshot, query, where, orderBy } from 'firebase/firestore'
const documents = ref(null)
const firebaseApp = initializeApp(firebaseConfig)
const db = getFirestore(firebaseApp)
const ref = query(collection(db, 'documents'), where(`something`, '==', 'something'), orderBy('createdAt', 'desc'))
const unsub = onSnapshot(ref, (snap) => {
let results = []
snap.docs.forEach(el => {
el.data().createdAt && results.push({ ...el.data(), id: el.id })
})
documents.value = results
}, err => {
console.log(err.message)
documents.value = null
})
Is there a way to reduce that size slightly, without sacrificing the real-time ability?
The attached image is a screenshot of two "date/time" entries in my Firestore document.
timeCompleted is a value that I entered directly in the database, choosing "timestamp" as the field's type. Per the screenshot, you can tell that the date/time shows in a readable format (not that it matters to me).
timeCreated is a value added by my JavaScript Reactjs application, using firebase.firestore.Timestamp.fromDate(new Date(myDate + " " + myTime)), as prescribed by the Google docs. As opposed to being stored as a timestamp type, it is stored as a map containing nanoseconds and seconds.
Is there a way to store my JavaScript date (timeCreated) as a true timestamp, similarly to timeCompleted?
My firebase class (gets imported through React's Context API)
import app from "firebase/app";
import "firebase/firestore";
import "firebase/functions";
const config = {
apiKey: ...,
authDomain: ...,
databaseURL: ...,
projectId: ...
};
class Firebase {
constructor() {
app.initializeApp(config);
this.auth = app.auth();
this.firestore = app.firestore;
this.functions = app.functions;
}
}
export default Firebase;
My React Component
import React, { useState, useEffect, useContext } from "react";
import { FirebaseContext } from "../../Firebase";
const InnerComponent = React.memo(props => {
const firebase = useContext(FirebaseContext);
//Calls Google Cloud function below
firebase.functions().httpsCallable("storeInDb")({
const myDate = "2019-02-25";
const myTime = "17:45";
orderDetails {
name: "someName",
timeCreated: firebase.firestore.Timestamp.fromDate(new Date(myDate + " " + myTime))
}
)}
My Google Cloud Function
exports.storeInDb = functions.https.onCall(async (data, context) => {
return id = await orderCreation(data.orderDetails);
});
const orderCreation = async orderDetails => {
try {
const docRef = await admin.firestore()
.collection(pathToCollection...)
.add(orderDetails);
return docRef.id;
} catch (error) {
console.log("ORDER CREATION ERROR", error);
}
};
It looks like you're expecting the type of the Timestamp object that you're passing into the callable function to be retained between the client and server. Unfortunately, it doesn't work that way. When a Timestamp object is serialized, it just converts to a JavaScript object with seconds and nanoseconds properties. The callable function on the other side isn't going to automatically reconstitute that object into a Timestamp. In fact, all types are lost, and everything is just converted to JSON.
What you're going to have to do is take that serialized object in the function and turn it back into a Timestamp yourself before you pass it to the Firestore SDK. Then, the SDK will arrange for Firestore to save it as a timestamp type field. This means you're going to have to do some initial processing on the data parameter and make sure it has all the correct values to write into Firestore.
Again, if it's not completely clear - the type of the object must be correct with the Firestore SDK calls. You can't pass arbitrary objects and expect it to do smart conversions.
I am using Jest to test my firebase functions. This is all in the browser, so I don't have any conflicts with firebase on the server side. When I use firebase.auth() or firebase.database() everything works fine. When I try to use firebase.storage() my tests fail.
Here is my firebase import and initialization:
import firebase from 'firebase';
import config from '../config';
export const firebaseApp = firebase.initializeApp(config.FIREBASE_CONFIG);
export const firebaseAuth = firebaseApp.auth();
export const firebaseDb = firebaseApp.database();
I have an imageUtils file that has an upload function in it:
import { firebaseApp } from './firebase';
export const uploadImage = (firebaseStoragePath, imageURL) => {
return new Promise((resolve, reject) => {
// reject if there is no imagePath provided
if (!firebaseStoragePath) reject('No image path was provided. Cannot upload the file.');
// reject if there is no imageURL provided
if (!imageURL) reject('No image url was provided. Cannot upload the file');
// create the reference
const imageRef = firebaseApp.storage().ref().child(firebaseStoragePath);
let uploadTask;
// check if this is a dataURL
if (isDataURL(imageURL)) {
// the image is a base64 image string
// create the upload task
uploadTask = imageRef.putString(imageURL);
} else {
// the image is a file
// create the upload task
uploadTask = imageRef.put(imageURL);
}
// monitor the upload process for state changes
const unsub = uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
(snapshot) => {
// this is where we can check on progress
}, (error) => {
reject(error.serverResponse);
unsub();
}, () => {
// success function
resolve(uploadTask.snapshot.downloadURL);
unsub();
});
});
};
And I am trying to create a test case for that function and every time it fails with:
TypeError: _firebase3.firebaseApp.storage is not a function
When I run the app normally everything works fine and I never get errors about storage() being undefined or not a function. It is only when I try to run a test case.
I have set a console.dir(firebaseApp); line in the firebase import, and it comes back with both auth() and database() but no storage. How can I get storage to import/initialize/exist properly?
Add the following import
import "firebase/storage";
It looks like this was fixed in a recent update to the firebase javascript package:
I had the same problem. Another possible solution:
import * as firebase from "firebase";
import "firebase/app";
import "firebase/storage";