I've a collection called users, inside each document's users have a collection called monthlies and I want get it.
This is the structure:
At now, I tried get it using:
var getUsers = async function() {
var db = firebase.firestore()
var users = await firebase
.firestore()
.collection("users")
.get();
return users
}
var getMonthlyByUserId = async function () {
var users = await getUsers()
users.forEach(element => {
var monthlies = element.collection('monthlies').get()
console.log(monthlies.docs.map(doc => doc.data()))
})
}
But it prints nothing. The goal is iterate of all documents' monthlies of the collection.
In addition to the problem that Doug pointed out (you need to use the ref property of the QueryDocumentSnapshot), you need to take into account that the get() method is asynchronous.
So doing
users.forEach(snapshot => {
var monthlies = snapshot.ref.collection('monthlies').get()
console.log(monthlies.docs.map(doc => doc.data()))
})
will not work.
If you cannot use a collection group query (for example, let's imagine that your getUsers() function only returns a subset of all the users, e.g. all users of a given country) you could use Promise.all() as follows:
var getMonthlyByUserId = async function () {
const users = await getUsers();
const promises = [];
users.forEach(snapshot => {
promises.push(snapshot.ref.collection('monthlies').get());
});
const monthlies = await Promise.all(promises);
monthlies.forEach(snapshotArray => {
console.log(snapshotArray.docs.map(doc => doc.data()));
});
}
OR you could use the technique described in this article on how to use async/await inside a forEach().
In your code, element is a QueryDocumentSnapshot type object. It doesn't have a method called collection(), so I would expect your code will crash with an error in the log.
If you want to reference a subcollection organized under a document represented by QueryDocumentSnapshot, you should build upon its ref property:
users.forEach(snapshot => {
var monthlies = snapshot.ref.collection('monthlies').get()
console.log(monthlies.docs.map(doc => doc.data()))
})
Alternatively, if you just want to query all documents in all subcollections called "monthly", you can simplify that with a single collection group query.
Related
I'm fetching data from MongoDB, and the response is coming through fine, however it appears to be wrapped in array when it comes out of the User.find() function.
For example, one response is:
[{"_id":"62fe3c888e2776ef3c1a010f","username":"Drago D Trial","password":"U2FsdGVkX1867hs26KL0KitTGhWnP9tdVX6AcmI5pWE=","fullname":"Drago DaTrial","firstname":"","surname":"","email":"drago#hotmail.com","position":"QA Tester","userImage":"","locationCity":"","country":"","role":"","company":"","emailAuthorised":true,"professionalBio":"","positionRecentTitle":"","positionRecentCompany":"","companyAuthorised":"","isAdmin":false,"createdAt":"2022-08-18T13:20:08.045Z","updatedAt":"2022-08-18T13:21:02.619Z","__v":0}]
I'm accessing this through an api like this:
router.get('/inviteToJoinTeam/:token/:email', async (req, res) => {
try {
//verify the token against DB
const userToken = (req.params.token)
const indivEmailAdd = (req.params.email)
// creating user auth
try{
const userDetails = await User.find({email: indivEmailAdd})
const indivIDAdd = await userDetails (!want to access the data here and just get ID)
res.send(indivIDAdd)
}catch{
console.log('failure')
}
} catch (e) {
res.send('This isnt working');
}
});
How would you access this and just get the _id field out?
If there is only one item in the array then - simply get the id property of the first item intthe returned array
const indivIDAdd = await userDetails[0]['_id'];
or using dot notation
const indivIDAdd = await userDetails[0]._id;
if there are multiple results then map over the results and get the id from each
const ids = await userDetails.map(user => user._id);
just use response[0]._id
Ps: Response is the array coming from the database
Try projection for the same it should work
const userDetails = await User.find({ email: indivEmailAdd }, { _id : 1 })
it will return array of ObjectId. if you need to get only one object then use findOne instead of find.
According to me you have 2 solutions :
Option 1 use findOne instead of find :
const userDetails = await User.findOne({email: indivEmailAdd});
Option 2 access array / object with basic js:
const usersDetails = await User.find({email: indivEmailAdd});
const userDetails = usersDetails.at(0)._id; // or
const userDetails = usersDetails[0]['_id'];
I am trying to get a post title from firestore but somehow I could not figure out how that could be done using async await.
async getVideo(id) {
var self = this;
const ref = this.$fire.firestore
.collection("posts")
.where("ytid", "==", id)
.orderBy("createdAt", "desc");
try {
let post = await ref.get();
console.log(post.data());
} catch (e) {
console.log(e);
}
}
I tried to console log post.data() but it says post.data() is not a function.
Any help would be appreciated.
When you call ref.get(), you will get a QuerySnapshot object. This object contains zero or more DocumentSnapshot objects that contain the data from the query results. QuerySnapshot does not have a method called data(). You will have to iterate the documents using the provided API to get the DocumentSnapshots:
const qsnapshot = await ref.get();
qsnapshot.forEach(doc => {
const data = doc.data();
console.log(data);
})
You are retrieving multiple documents, so post will be a snapshot of documents which does not have a data() method.
You'll need to iterate through the snapshot to access the individual documents.
See https://firebase.google.com/docs/firestore/query-data/get-data#get_multiple_documents_from_a_collection for a quick guide or https://googleapis.dev/nodejs/firestore/latest/QuerySnapshot.html for a full reference of the QuerySnapshot type.
So i have 2 collections
1 collection is 'users'. There i have documents (objects) with property 'profile', that contains string. It's id of profile, that is stored in other collection 'roles' as document.
So i'm trying to get this data, but without success. Is there exist join method or something like that? Or i must use promise for getting data from collection roles, and then assign it with agent?
async componentDidMount() {
firebase
.firestore()
.collection('users')
.orderBy('lastName')
.onSnapshot(async snapshot => {
let changes = snapshot.docChanges()
const agents = this.state.agents
for (const change of changes) {
if (change.type === 'added') {
const agent = {
id: change.doc.id,
...change.doc.data()
}
await firebase
.firestore()
.collection('roles')
.doc(change.doc.data().profile).get().then( response => {
//when i get response i want to set for my object from above this val
agent['profile'] = response.data().profile
//after that i want to push my 'agent' object to array of 'agents'
agents.push(agent)
console.log(agent)
}
)
}
}
this.setState({
isLoading: false,
agents: agents
})
})
}
To do async operation on array of objects you can use promise.all, i have given a example below that is similar to your use case where multiple async operation has to be done
const all_past_deals = await Promise.all(past_deals.map(async (item, index) => {
const user = await Users.get_user_info(item.uid);
const dealDetails = await Deals.get_deal_by_ids(user.accepted_requests || []);
const test = await Users.get_user_info(dealDetails[0].uid);
return test
}))
}
This way you can get data from once api call and make other api call with the obtained data
I have fetch some data from firestore but in my query I want to add a conditional where clause. I am using async-await for api and not sure how to add a consitional where clause.
Here is my function
export async function getMyPosts (type) {
await api
var myPosts = []
const posts = await api.firestore().collection('posts').where('status', '==', 'published')
.get()
.then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.data())
})
})
.catch(catchError)
}
In my main function I am getting a param called 'type'. Based on the value of that param I want to add another qhere clause to the above query. For example, if type = 'nocomments', then I want to add a where clause .where('commentCount', '==', 0), otherwise if type = 'nocategories', then the where clause will be querying another property like .where('tags', '==', 'none')
I am unable to understand how to add this conditional where clause.
NOTE: in firestore you add multiple conditions by just appending your where clauses like - .where("state", "==", "CA").where("population", ">", 1000000) and so on.
Add the where clause to the query only when needed:
export async function getMyPosts (type) {
await api
var myPosts = []
var query = api.firestore().collection('posts')
if (your_condition_is_true) { // you decide
query = query.where('status', '==', 'published')
}
const questions = await query.get()
.then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.data())
})
})
.catch(catchError)
}
For the frontend Web SDK:
Or you can look at this link for a different method:
Firestore conditional where clause using Modular SDK v9
let showPublishStatus: boolean = true
let conditionalConstraint: QueryConstraint = showPublishStatus
? where("status", "==", "published")
: where("status", "!=", "published")
let queryWebSDK = query(collection(db, "Collection"), conditionalConstraint)
I try to put a listener on Firebase that will replicate a value in the matching element in Firestore.
exports.synchronizeDelegates = functions.database.ref(`delegates/{userId}/activities`).onUpdate((event) => {
const userKey = event.data.ref.parent.key
console.log("User Key:" + userKey)
return admin.database().ref(`delegates/${userKey}/email`).once('value', snapshot => {
let email = snapshot.val()
console.log("Exported Email:" + email)
const userRef = admin.firestore().collection('users')
const firestoreRef = userRef.where('email', "==", email)
firestoreRef.onSnapshot().update({ activities: event.data.toJSON() })
}).then(email => {
console.log("Firebase Data successfully updated")
}).catch(err => console.log(err))
}
)
This function is able to retrieve and locate the elemnt needed to target the right document in firestore, but the .update()function still error firestoreRef.update is not a function
I try several ways to query but I still have this error.
How to properly query then update a document in this scenario?
The onSnapshot() method of Query introduces a persistent listener that gets triggered every time there's a new QuerySnapshot available. It keeps doing this until the listener is unsubscribed. This behavior is definitely not what you want. Also, there's no update() method on QuerySnapshot that your code is trying to call.
Instead, it looks like you want to use get() to fetch a list of documents that match your query, then update them all:
exports.synchronizeDelegates = functions.database.ref(`delegates/{userId}/activities`).onUpdate((event) => {
const userId = event.params.userId
console.log("User Key:" + userKey)
return admin.database().ref(`delegates/${userId}/email`).once('value', snapshot => {
let email = snapshot.val()
console.log("Exported Email:" + email)
const usersRef = admin.firestore().collection('users')
const query = usersRef.where('email', "==", email)
const promises = []
query.get().then(snapshots => {
snapshots.forEach(snapshot => {
promises.push(snapshot.ref.update(event.data.val()))
})
return Promise.all(promises)
})
}).then(email => {
console.log("Firebase Data successfully updated")
}).catch(err => console.log(err))
}
Note that I rewrote some other things in your function that were not optimal.
In general, it's a good idea to stay familiar with the Cloud Firestore API docs to know what you can do.