I would like to check/compare if a value is inside this data:
example:
const uid = '35nv594aotgcv'
#check if uid is inside
firebase
.database()
.ref('followers/2mvouwB0E0aEN5MnAhOLWaHiu6b2')
.once("value", snapshot => {
if (snapshot.exists()) {
const data = snapshot.val(); // data are the other two uid's in the image above
}
});
So how can I check if the const uid = '35nv594aotgcv' is inside the snapshot data?
or if I have an Array with uid's like const uids = ['234', '343', '3242', ...]
If I understand you correctly, you're looking for DataSnapshot.hasChild(). With that you can check whether the snapshot has a certain child node.
Something like:
firebase
.database()
.ref('followers/2mvouwB0E0aEN5MnAhOLWaHiu6b2')
.once("value", snapshot => {
if (snapshot.hasChild('35nv594aotgcv')) {
console.log('Yes');
}
});
Related
I have a post feed combining of two firebase firestore collections.
userPosts = [] // collectionGroup() query of all users images
users = {} // the users data after for looping posts results
I'm currently getting both the posts from the post collection and the users data from the users collection after for looping the post uids.
This is working fine and shows the user object combined with the post object in the console.log() but It will not show in the flatlist when combining this end result to a state hook!
Basically, it seams to be working fine but I can't display it. I need the end result to be the post with the users data retrieved after for looping.
Again, console.log shows correct merge of data, attaching to state hook and displaying in flatlist is not working.
My code:
useEffect(() => { // showGlobal feed
if (showGlobalFeed) {
firebase.firestore()
.collectionGroup("userPosts")
.orderBy("creation", "asc")
.get()
.then((snapshot) => {
let posts = snapshot.docs.map(doc => {
const data = doc.data();
const id = doc.id;
const uid = data.uid;
return { id, uid, ...data }
})
for(let i = 0; i< posts.length; i++){
firebase.firestore()
.collection("users")
.doc(posts[i].uid)
.get()
.then((snapshot) => {
if (snapshot.exists) {
let user = snapshot.data();
user.uid = snapshot.id;
// the below cosloe.log works fine.
console.log('\nFOR LOOP COMBINED ==========> \n',[posts[i], user])
// the hook fails to display combined data correctly
setGlobalPosts([posts[i], user])
}
else {
console.log('does not exist')
}
})
}
// console.log({...posts})
})
}
}, [showGlobalFeed])
Flatlist = data={globalPosts}
I have some code that gets a collection reference to the users collection and then queries an animeID field whether it contains a certain value or not. I want to change this and only query inside the document with the id i pass. So if you look at the picture of my firestore you can see that i have two documents inside the users collection each with their unique id. I want to query for the animeID field only in the document that i want. Not all the documents as it does right now. How would i go about doing this? I have tried using doc and then passing in the id of the document but i don't think query works on doc as it gives me an error. Thanks
const docRef = collection(db, 'users')
const q = query(docRef, where('animeID', 'array-contains', parseInt(id)))
onSnapshot(q, (snapshot) => {
let results = []
snapshot.docs.forEach((doc) => {
results.push({...doc.data(), id: doc.id})
})
if(results.length > 0){
console.log(true)
}
else{
console.log(false)
}
}, (error) => {
console.log(error)
})
Firestore structure:
You need to do as explained in the doc:
import { doc, getDoc } from "firebase/firestore";
const docRef = doc(db, "users", "dbmbEiR6....");
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const animeID = docSnap.data().animeID;
// Do whatever you want with animeID
// E.g. log its value:
console.log(JSON.stringify(animeID));
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
So you don't need to declare a Query in this case. Just declare a DocumentReference and use the getDoc() method.
I am listening to a firestore database (lets call it ALBUMS) and when a new object gets created, I fetch the info from firestore. After fetching the info from ALBUMS database, I receive userId as a field. Here is my listener:
firebase
.firestore()
.collection("ALBUMS")
.doc(albumId)
.onSnapshot((snapshot) => {
const objectThatIWantToSet = snapshot.docs.map((doc) => {
const data = doc.data();
const id = doc.id;
const userId = doc.cP.proto.fields.userId.stringValue;
...
// I want to fetch some more info from another db before constructing my object
});
});
};
After retrieving userId, I need to fetch some more info from another database: I want to fetch userName from database users. Fetching itself is pretty straightforward:
firebase
.firestore()
.collection("USERS")
.doc(userId)
.get()
.then((snapshot) => {
if (snapshot.exists) {
//take the fields that I need
}
});
What I do have problem with is the following: from both fetches I need to construct an object, s.t. it will contain the info from PHOTOS database and from the USERS database. This info, I need to keep it in store. So what I tried is the following:
function FetchInfo(props) {
const [obj, setObj] = useState(null);
// I need to set it in useeffect
useEffect(() => {
firebase
.firestore()
.collection("ALBUMS")
.doc(albumId)
.onSnapshot((snapshot) => {
const finalObject = snapshot.docs.map((doc) => {
const data = doc.data();
const id = doc.id;
//I am getting userId from the first db
const userId = doc.cP.proto.fields.creator.stringValue;
let photoInfo = {
photoId: doc.id,
photoURL: doc.cP.proto.fields.photoURL.stringValue,
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
//I need to insert user data here
};
firebase
.firestore()
.collection("users")
.doc(userId)
.get()
.then((snapshot) => {
if (snapshot.exists) {
photoInfo.user = {
userName: user.name,
userProfilePic: user.profilePicURL
};
//here updated result does have users data
console.log("updated photoInfo: ", photoInfo);
}
});
//my actual result does not have users data
console.log("actual photoInfo: ", photoInfo);
return photoInfo;
});
//my finalObject does not contain users info
//finalObj is array of photoInfo objects
setObj(finalObject);
});
}), []);
I tried to use async await synthax inside useEffect, but it didnt let me put await infront of the second firebase call (it only let me put await infront of the first one, which didnt help).
Any ides would be welcome!
EDIT : the fields which I need from the first db (ALBUMS) are photoId, photoURL, createdAt and userId.
The fields which I need from the second database (USERS) are userName and userProfilePic.
So my final object should be array of objects (I call them photoInfo) which have the following json format:
photoInfo = {
photoId: //taken from the ALBUMS db,
photoURL: //taken from the ALBUMS db,
createdAT: //taken from the ALBUMS db,
user: {
userName: //taken from the USERS db,
userProfilePic: //taken from USERS db
}
}
Again, I am returning array of photoInfo objects.
So far I can easily construct the photoInfo obj, only with the fields from ALBUMS db; the fields from USERS db dont get updated.
What are you trying to do by this?
const userId = doc.cP.proto.fields.creator.stringValue;
If creator is a field containing a string value in the document then you can simply access it by:
const data = doc.data();
const id = doc.id;
const userId = data.creator
Try refactoring the useState as follows.
useEffect(() => {
// Adding a listener on doc
firebase
.firestore()
.collection("ALBUMS")
.doc(albumId)
.onSnapshot(async (snapshot) => {
// An array of requests to get user info
const userReqs = []
// Initialized final object
const finalObject = {}
// Running a loop on the array field*
snapshot.data().array_field.forEach((doc) => {
const data = doc.data();
const id = doc.id;
const userId = data.creator;
finalObject[id] = {
_id: doc.id,
text: "",
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
...data,
};
userReqs.push(
firebase
.firestore()
.collection("users")
.doc(userId)
.get()
.then((snapshot) => {
if (snapshot.exists) {
finalObject[id]["user"] = snapshot.data()
//here updated result does have users data
console.log(`Added user to ${id}`, snapshot.data());
}
})
)
})
await Promise.all(userReqs)
console.log("Final Obj", finalObject);
setObj(Object.keys(finalObject).map((key) => finalObject[key]));
});
}, []);
I am querying firebase firestore by...
let database = firebase.firestore();
let places = database.collection("place");
console.log("places", places);
now the logged data is bizarre and not the actual documents..
here is a picture of the log...can you please advice regarding tackling this ?
If you want to retrieve all items in your collections called "place" you can do something like this:
let database = firebase.firestore();
let places = database.collection("place");
const querySnapshot = places.get()
// You can make an empty array to eventually push the items into
const collectionArray = []
querySnapshot.forEach((doc) => {
const data = doc.data()
collectionArray.push(data)
}).catch(function(error) {
console.log("Error getting documents: ", error);
})
console.log('collectionArray:',collectionArray)
}
Your code hasn't actually executed any query yet. All it's done is build a Query object.
If you want to execute the query, call get() on it, and handle the results as shown in the documentation.
let database = firebase.firestore();
let query = database.collection("place");
query.get()
.then(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
console.log("document", documentSnapshot.data());
})
})
I am transitioning a Firebase real-time database to a Firebase Firestore database but am having trouble finding the appropriate reference to query the current user.
onAuthUserListener = (next, fallback) =>
this.auth.onAuthStateChanged(authUser => {
if (authUser) {
this.user(authUser.uid)
.once('value')
.then(snapshot => {
const dbUser = snapshot.val();
// default empty roles
if (!dbUser.roles) {
dbUser.roles = [];
}
// merge auth and db user
authUser = {
uid: authUser.uid,
email: authUser.email,
emailVerified: authUser.emailVerified,
providerData: authUser.providerData,
...dbUser,
};
next(authUser);
});
} else {
fallback();
}
});
Most specifically, what would be the replacement for once('value') and snapshot.val();?
I had thought that
.onSnapshot(snapshot => {
const dbUser = snapshot.val();
...
The equivalent of once('value' in Firestore is called get(), and the equivalent of val() is data(). Calling get() returns a promise, so:
.get().then(snapshot => {
const dbUser = snapshot.data();
...
If you have a collection of users, where the profile of each user is stored within a document with their UID as its ID, you can load that with:
firebase.firestore().collection('users').doc(authUser.uid)
.get()
.then(snapshot => {
const dbUser = snapshot.val();
Note that this is pretty well covered in the documentation on getting data, so I'd recommend spending some time there and potentially taking the Cloud Firestore codelab.