React FIrebase Failed-precondition - javascript

Im using Firebase to store some data in my React app. Its working fine on my local emulator with the same settings, but when i publish the app, i get this error:
#firebase/firestore: Firestore (9.12.1): Uncaught Error in snapshot listener: {"code":"failed-precondition","name":"FirebaseError"}
Im using the where() clause, and i red i need to add some sort of index in my firebase rules.
useEffect(() => {
if (activeList === 'null') {
} else {
const userRef = collection(database, activeList.id);
const sort = query(userRef, where("checked", "==", showDoneTodos), orderBy('title', 'asc'))
const unsubsctibeAllTodos = onSnapshot(sort, (snapshot) => {
setAllTodos(snapshot.docs.map(doc => ({
id: doc.data().id,
title: doc.data().title,
desc: doc.data().desc,
checked: doc.data().checked
})
))
})
return () => {
unsubsctibeAllTodos()
}
}
}, [activeList, showDoneTodos])
Some info:
activeList is an object with and ID. The problem is that this is generated live so i cant preconfigure any collection ID before i publish.
showDoneTodos is a boolean.
Any guidance would be very welcome!
Thanks!

Firebase logs this error when the required index is missing. It only shows this error when you use the onSnapshot method. When you use the getDocs methode it will show the good old link to create the index in the Firebase console. A solution is to create a similar request with the getDoc methode, create the index and switch back to the onSnapshot methode.

It seems that Firebase does not provide a link to create the necessary index anymore. They only provide the error code:{"code":"failed-precondition","name":"FirebaseError"}
The solution is the same, go to Firebase -> Indexes and add it there...

Related

How to delete a single entry from my Realtime Firebase database in React Native?

I'm not quite sure how to delete a single entry in my Realtime database, each time I run the following, it deletes everything in that database:
const deleteTask = () => {
console.log('will delete: ', id);
remove(ref(db, '/todos', id))
}
I do have the id (can see that with the console.log) and it matches what my firebase shows on the web console. But why is "remove" deleting the entire database?
What makes it strange to me is that this code successfully updates the "done"-status of a single database entry:
const onCheck = (isChecked) => {
setDone(isChecked);
update(ref(db, '/todos'), {
[id]: {
title,
done: !doneState,
},
});
console.log('set done/undone')
};
I had a look at the official Realtime database, but this wouldn't help me figure out what's wrong. Same goes for other solutions here on stackoverflow, but most of them have the issue of getting the id, something I already do have.
Any help / tipps are much appreciated! :)
The ref function only takes a single path parameter:
Signature:
export declare function ref(db: Database, path?: string): DatabaseReference;
So the ID you specify as a second parameter isn't used, so you're indeed deleting all the todos.
The solution is to call child:
remove(child(ref(db, '/todos'), id))
Or pas in the entire path as one string:
remove(ref(db, '/todos/'+id))

FIrebase firestore onSnapshot not firing on change

I am following a simple tutorial on Firebase 9. Everything worked fine until I tried to use onSnapshot method to get the snapshot of changes in db every time the cahnge occurs.
But onSnapshot is not working. I mean it work only for the initial fetch of data, but does not execute the callback function when the change occurs.
I am following a tutorial so my code is identical to the code from the tutorial. My question is whether there is something I need to do in the console to rectify this, some kind of rules or permissions or something.
My code:
const colRef = collection(db, 'books');
const q = query(colRef, where('author', '==', 'patrick rothfuss'));
onSnapshot(q, (snapshot) => {
let books = []
snapshot.docs.forEach(doc => {
books.push({ ...doc.data(), id: doc.id })
})
console.log(books)
})
You can use snapshot.docChanges().forEach method to read and detect changes in data on real time.
I recommend you use this method to modify the array when a change occur.
You can view the code here: https://github.com/firebase/snippets-web/blob/1c4c6834f310bf53a98b3fa3c2e2191396cacd69/snippets/firestore-next/test-firestore/listen_diffs.js#L8-L23
For me, the issue was that I imported collection from the lite version:
import { collection } from "firebase/firestore/lite";
After I changed it
import { collection } from "firebase/firestore";
All is working well. Also, make sure other functions are imported from a normal version.
You can read more about the lite version here:
https://firebase.google.com/docs/firestore/solutions/firestore-lite
You can see it doesn't support snapshot listeners.
Cheers,

How to enable persistence on reactfire?

I'd like to implement Firestore offline persistence on my PWA React app using the reactfire library.
const firestore = useFirestore().enablePersistence();
let documentReference = firestore
.collection("food")
.doc("milkshake");
const { data } = useFirestoreDocData(documentReference);
but running the code i get an error:
FirebaseError: Firestore has already been started and persistence can no longer be enabled. You can only enable persistence before calling any other methods on a Firestore object.
This component is wrapped inside a <Suspense> as mentioned in the documentation
That database read is the only one that i make in the entire app, how can i solve?
Edit.
Using the example that #Ajordat gave, I've imported the preloadFirestore function inside the App component I do get an error:
"Cannot read property 'name' of undefined".
Whereas adapting (because I cannot use hooks inside the fetch function)
the example from #DougStevenson: I've imported useFirestore function in the App component (in order to get the Firestore object) to enable persistence, and then importing it (useFirestore) into my component in order to retrieve the data, but now, I get the same error as before,
Firestore has already been started and persistence can no longer be enabled.
Edit 2:
I've tried to enablePersistence without errors, thank guys, this is my approach, let me know if it is the best:
const firestore = useFirestore();
React.useEffect(() => {
firestore.enablePersistence();
}, []);
And in my custom component:
let docRef = useFirestore()
.collection("food")
.doc("milkshake");
let document = useFirestoreDocDataOnce(docRef);
console.log(document)
But now I do have a problem, when I log the document, the data are not emitted instantly, yeah I know that it is an asynchronous operation, but the component is wrapped inside a <Suspense>, in this way:
<Suspense fallback={<div>Loading</div>}>
<FoodComponent foodName={"Milkshake"} />
</Suspense>
But I don't see the loading text before the component is actually rendered.
Does the suspense fragment show the fallback component only while is loading the function (useFirestore) and not the actual data?
Well, I've solved, have to destructure the data, doing like that:
let docRef = useFirestore()
.collection("food")
.doc("milkshake");
let { data: document } = useFirestoreDocData(docRef);
console.log(document)
On other JavaScript libraries for Firestore, enablePersistence() returns a promise. That means it will complete some time in the future, with no guarantees how long it will take. If you're executing the query immediately after you call enablePersistence(), without waiting for the returned promise to become fulfilled, then you will see this error message. That's because the query "beats" the persistence layer and effectively executes first.
You will have to figure out how to use that promise to wait until it's OK to make that query with persistence enabled. For example:
seFirestore().enablePersistence()
.then(() => {
let documentReference = firestore
.collection("food")
.doc("milkshake");
const { data } = useFirestoreDocData(documentReference);
})
.catch(error => {
console.error("enablePersistence failed", error);
})
Notice how the query will complete only after the persistence is fully enabled.
Thanks for the suggestion guys #DougStevenson and #Ajordat
In app component:
import { useFirestore } from "reactfire"
...
const firestore = useFirestore();
React.useEffect(() => {
firestore.enablePersistence();
}, []);
In your custom component, where you want to use Firestore:
import { useFirestore, useFirestoreDocData /* or what you want to use */ } from "reactfire"
let docRef = useFirestore()
.collection("food")
.doc("milkshake");
let { data: document } = useFirestoreDocData(docRef);
console.log(document);

Manipulating documents in Firebase collection with Vuex [Vuex/Vuexfire]

I've a simple question but I can't find the answer.
I'm using Vuexfire to import data from Firebase in Vuex.
const state = {
ricettario: [] // data that contains all recipes (objects)
}
const actions = {
// Get data from Firebase
init: firestoreAction(({ bindFirestoreRef }) => {
bindFirestoreRef('ricettario', db.collection('ricettarioFirebase'))
}),
}
It works perfectly but I want to manipulate every document of the collection 'ricettarioFirebase'. With vue + firebase was easy, with .get() and .then()
I can't find a solution! I thought using GETTERS is the best way to do that but I'm new with Vuex and Vuexfire so I don't know how to do that.
In particular, I want to convert this (classic firebase command):
db.collection("ricettarioFirebase")
.orderBy("data")
.get()
.then(snapshot => {
snapshot.forEach(doc => {
let ricetta = doc.data();
ricetta.data = dayjs(ricetta.data)
.locale("it")
.format("D MMMM YYYY");
ricetta.diffClass = ricetta.diff.split(" ").join("_");
this.ricettario.push(ricetta);
});
});
In Vuexfire. So change every object in the "ricettario[ ]" will be "ricetta", and I want to edit the "ricetta.diffClass" and "ricetta.data"
As you will see in the Vuexfire documentation:
Vuexfire does not handle writing data back to Firebase because you can
directly use the Firebase JS SDK to precisely update whatever you
need.
The doc gives some example of use of the "standard" JS SDK, exactly like you did in your question ("classic firebase command"). So you'll have to go this way, wrapping the database writes in Vuex Actions.

Issue retrieving Firebase data on React Native app

I'm trying to display the WeightGoal that's already been stored on my Firebase RealTime Database, but I'm getting the following error. "Objects are not valid as a React child (found: object with keys {…})"
Here's my json file:
Here's my componentWillMount code:
componentWillMount() {
const { currentUser } = firebase.auth();
firebase
.database()
.ref(`/users/${currentUser.uid}/goals`)
.on('value', snap => {
this.setState({ WeightGoal: snap.val()})
})
}
And here's how I'm referencing the value inside of render:
{this.state.WeightGoal}
My expectation is to see 170 displayed on the screen.
Any help would be greatly appreciated.
snap.val() is the object consisting of the goal object in your database, because that is what you are referencing:
.ref(`/users/${currentUser.uid}/goals`)
So, if you want to store only the WeightGoal property, the line, where you use this.setState should look like this:
this.setState({ WeightGoal: snap.val().WeightGoal })
P.S. Next time try adding console.log(this.state) into render() to see what you are displaying. Or add a breakpoint in Chrome Debugger, which is a more reliable way.

Categories

Resources