How to delete data from firebase live database using id? - reactjs

I am trying to delete a record in firebase live database using this id.
My removeFromFavorites action takes in a recipe (with the id) and I want to match that with the record in the database and delete it.
export const removeFromFavorites = (recipe: RecipeConfig) => async (
dispatch: Dispatch
): Promise<void> => {
};
If this is not possible, can you please suggest an alternative, thanks.

To delete (or otherwise write to) a node from the database you must know its full path. If you don't know it's full path, you can determine that by first running a query, and then deleting the node/all nodes that match the query.
If recipe has an id, then that'd be something like this:
const ref = firebase.database().ref('favorites');
const query = ref.orderById().equalTo(recipe.id);
query.once('value').then((results) => {
results.forEach((snapshot) => {
snapshot.ref.remove();
});
});
Also see:
How to delete specific record in firebase having specified Title
Firebase - Delete a node
Firebase query and delete data in javascript

Related

How to Update this mobile no field to firestore database when all the data have route to this screen

How do i update this mobile no field to firestore database i am unable to find the doc id. i tried many times but it showing me error that doc id is missing which doc id should i have to put please make a help for me in this case. Thankyou.
const ItemDetails = ({ route }) => {
const[values, setValue] = useState('')
let data = route.params
console.log(data)
const updateValue = () => {
db.collection("FinalData")
.doc()
.update({
mobile_no: values
})
.then(function () {
alert("Mobile Number Updated Successfully")
})
}
Okay, you do not know which doc id to put.
In Firestore, you can only update an existing document.
Right now, what you want to do with this line db.collection("FinalData").doc().update(...) is to update a document, but you have not told firestore which document to remove the old mobile no from and put the new mobile no in.
Another way to understand this is we can assume that your firestore database is a book. What you want to do with this line db.collection("FinalData").doc().update(...) is to tell firestore to please change mobile no to 'bla bla bla' on page (you didn't give any page number). So you see, firestore can not change anything because it does not which page to change.
So the doc id being referred to is the id of the document you want to correct.
This mobile no, is probably one of your users mobile number, so get the document (which could be something like user-settings, user-details or so) id.
Then you put that document id as shown below:
db.collection("FinalData").doc('PUT-DOC-ID-HERE').update(...)

Firestore function to listen for updates

I am a beginner in React native and firestore, and using these to build a kind of social media app, and I have a weird problem(I think I structured the db the wrong way). I want to have a feed, with all posts, no following-based, no nothing. The first time I structured my posts in db like this: users(collection)->user(doc)->thisUserPosts(collection inside doc) - but I couldn't find a way to fetch through all the thisUserPosts from all user(doc) and display them properly.
So I re-structured the db like this:
2 main collection, posts and users. Completely different. In users collection, only docs of users and their data(name, age, etc). In the other, their posts(name, media, desc, AND userId - where userId == the person who created it. userId field from posts collection docs should exist in users collection).
This second approach works just fine. In feed, I only fetch posts. But the problem arrises when I try to open the post(need to have this feature). I need to be able to display on react-navigation header the name of the user, yet I only have details of the post and only userId, which is to no good use.
So I came up with a solution : add a userName field in the posts collection doc, next to userId and simply display that. Now here's the catch: I need to figure a way(in firestore I think) to listen to updates from users collection docs, in case a user updates his name/username(I don't want to showcase the old name). And I don't know if that's possible inside firestore or how. Or is it better to find a different db structure?
TLDR: Need a function in firestore to listen to updates from other collection OR restructuring the db.
If you are fetching posts of a single user then you can just set a listener for his document.
Make sure that document has no sensitive information that must not be shared with others and is limited to the owner only.
If you are fetching posts from multiple users then you can use in operator:
db.collection("users").where("userID", "in", ["user_id1", "user_id2"])
.onSnapshot((snapshot) => {
console.log(snapshot.docs.map(user => user.data()))
});
If I assume you will be updating the new name in all the user's posts then you can set the listener on the posts document itself but that won't be nice in case all 30 posts fetched are from same user. That'll end up costing 30 reads just to update the same name.
Edit:
A simple example of reading a user's posts and listening updates on the user name:
const userID = "my_user_id"
// fetching user's 30 posts
const postsRef = firebase.firebase().collection("posts").where("userID", "==", userID).limit(30)
const postsSnapshot = await postsRef.get()
const postsData = postsSnapshot.docs.map(post => post.data())
// Array of posts data objects
// listening to change in user's name
firebase.firestore().collection("users").doc("user_id")
.onSnapshot((doc) => {
console.log("data: ", doc.data());
const newUsername = doc.data().username
const updatedPostsData = postsData.map(post => {
return ({...post, username: newUsername})
})
});

Let users create elements that only they can see in Firebase (in React)

I recently started learning firebase and i find it great. I was able to let users register/login with email and password and once they are on the app they can create "Cards" with some data. However any user that creates an account on my app can then view and delete, edit, etc. any Card created by any user.
My question is simply how can i only display Cards strictly to the users who created them only?
Here is my code up to now:
useEffect(() => {
const cardRef = firebase.database().ref('Cards')
cardRef.on('value', (snapshot) => {
const cards = snapshot.val()
const cardslist = []
for (let id in cards) {
cardslist.push({id, ...cards[id] })
}
setCardslist(cardslist)
})
},[])
//in my jsx i then have cardslist which displays the cards
<div>{cardslist}</div>
Here is what you need to do:
1 - Make sure every "card" document has a "creator" field, so you can filter the query with something like...
your_query().where("creator", "==", current_viewer_id)
2 - Make sure you use Firestore Rules, to limit read/write operations on a card to only the creator of the card. Your use case is one of the first examples you'll see in Firestore Rules documentation and explainer videos.
Good luck! You're almost there.

Delay in Firestore to create a new document in the users collection

I hope someone can help me with this issue.
I'm currently working on a project in which I use firebase to create new users. So, when someone sign a new user up, firebase creates a new user, then it sends a promise to firestore, so it can create a new document in a collection called 'users', so I can access some user data, as name, last name and initials.
My problem is that, when I sign a new user up, the account is instantly created in firebase, but it takes a long time to create a new document with the user data in firestore. When I say a long time, I mean 10, 20 minutes or even more. Thus, an account is created with undefined data, until firestore decide to create new document.
The described procedure is shown in the code below:
export const signUp = newUser => {
return (dispatch, getState, { getFirebase }) => {
const firebase = getFirebase()
const firestore = getFirebase().firestore()
firebase.auth().createUserWithEmailAndPassword(
newUser.email,
newUser.password
).then(resp => {
return firestore.collection('users').doc(resp.user.uid).set({
firstName: newUser.firstName,
lastName: newUser.lastName,
initials: newUser.firstName[0] + newUser.lastName[0]
}).then(() => {
dispatch({ type: 'SIGN_UP_SUCCESS' })
})
}).catch(err => {
dispatch({ type: 'SIGN_UP_FAIL', err })
})
}
}
I'm using redux-firestore and react-redux-firebase as dependencies to connect my project to firebase. But it does not seem to be the problem, because firestore works seamlessly for other functionalities of the project, as add and delete new data to the user when its document is finally created, or when I try to delete an user, it also works fine.
So, I would be glad if someone could find an explanation for this delay and help me to overcome this problem.
I believe you're following The Net Ninja's series (I am too). If you follow what he did exactly (here) it will work. I've personally diffed yours and my implementation with his, and the only thing that was different was the semicolons. Try adding semicolons after each line. Perhaps the chaining of promises confuses the compiler?
It still won't work when you signup, then signout repeatedly. You need to refresh after each signout.
After some time I realized that the problem was not the code or firebase. The problem was something in the structure of the project it self.
In order to solve this problem, I needed to get rid of
"#testing-library/jest-dom"
"#testing-library/react"
"#testing-library/user-event"
In package.json. Then install the dependencies again.

Good way to query server object being in local cache

So I have a database that store users. When someone log on my website, it stores in apollo cache a user as currentUser. And I only store his id.
So I made a query to get a user by passing his id :
query {
user(id: "id") {
id
username
avatar
}
}
But everytime I wanna get data for that user I need to make two query (the first one locally to get back his id from the cache and a second one to the server).
const GET_CURRENT_USER = gql`
query getCurrentUser {
currentUser #client
}
`;
const GET_USER_DATA = gql`
query getUser($id: String!) {
user(id: $id) {
id
username
avatar
}
}
`;
const currentUserData = useQuery(GET_CURRENT_USER);
const { currentUser } = currentUserData.data;
const { data, loading } = useQuery(GET_USER_DATA, {
variables: { id: currentUser.id },
fetchPolicy: "cache-and-network"
});
Is here a way that I can reduce that to only one query (the one to the server) ?
id value stored in the cache can be read using readQuery, you can store it in other global store/state, f.e. redux.
If you're using apollo cache as global store then using queries is a natural part of this process.
Using readQuery you can read the value without querying (but doing the same). One query 'saved' ;)
Deeper integration (additional query, local resolver) is not a good thing - creating unnecessary dependencies.
If you want to reuse this "unneccessary query" extract it to some module or create a custom hook (id read/used/saved once during initialization) - probably the best solution for this scenario.
Another solutions:
make login process providing user data - for some inspiration take a look at apollo-universal-starter-kit - but this is for initial data only (login/avatar changing during session??) - further user querying still needs an id parameter - it must be stored and read somewhere in the app.
make id optional parameter (for getUser query - if you can change backend) - if not provided then return data for current user (id read from session/token)

Resources