The following query below returns me a collection of data based on a user id. How do I do I make sure it returns the uid of each document in the query.
getWebsitesByUserId(id) {
return this.afs.collection('websites', ref => ref.where('createdBy', '==', id)).valueChanges();
}
I understand that it involves something like this:
return this.afs.collection('websites').doc(id).snapshotChanges().pipe(map(action => {
const data = action.payload.data();
const uid = action.payload.id;
return {uid, ...data};
}));
Just not sure how to implement in a query.
According to this pull request on the AngularFire Repo now there is an option that you can pass a string to the valueChanges method on a collection reference.
This string will be the name of the property that will hold the IDs of the documents.
For example:
collectionRef.valueChanges('myIdKey').subscribe()
Would emit:
emits [ { myIdKey: 'MrfFpRBfWLTd7LqiTt9u', ...data }, ... ]
So in your situation I guess it would be something like this:
getWebsitesByUserId(id) {
return this.afs.collection('websites', ref => ref.where('createdBy', '==', id)).valueChanges('uid');
}
Related
I am rather new to angular & firebase and current using the angular/fire to retrieve the collections with the condition as per below in the service;
service.ts
get posts() {
return this.afs
.collection<Todo>('posts', ref => {
let query:
| firebase.firestore.CollectionReference
| firebase.firestore.Query = ref;
query = query.where('posted', '==', true);
return query;
})
.snapshotChanges()
.pipe(
map(action =>
action.map(a => {
const data = a.payload.doc.data();
const id = a.payload.doc.id;
return { id, ...data };
}),
),
);
}
In the component I am subscribing to the observable to retrieve the posts with "posted" field equals true. The below is working as expected and only the "posted" posts are being logged.
component.ts
ngOnInit() {
this.service.posts.subscribe(posts => {
console.log(posts);
})
}
But, when adding the post with the "posted" field equals to false, this post is also being logged in the console.
Partially it makes sense to me, since the collection is updated and the component is subscribed to it, resulting in an update.
However, my expectations was event if the collections has changed, it will still have the conditions applied & filter out again.
Thank you all for helping out a newbie
I don't know angularfire2 and firebase too well but you can take advantage of the map operator and filter operator of array maybe.
Try:
ngOnInit() {
this.service.posts.pipe(
map(posts => posts.filter(post => post.posted)),
).subscribe(posts => {
console.log(posts);
})
}
I am trying to fetch the documents of a collection in my React-Native app but I dont know how to fetch them by ID (key).
P.S: I dont have any field called unique id or id inside the document but as I have understood, the unique id is the auto-generated key when I create a document which stands as the name of that document (20 characters id).
This is how I fetch all the fields inside a document:
var ref = firebase.firestore().collection('discounts')
.orderBy('rest_id')
EDIT:
getDiscounts = () => {
try {
this.setState({
loading: true
})
var ref = firebase.firestore().collection('discounts')
.orderBy('rest_id')
.limit(this.state.limit)
ref.onSnapshot((querySnapshot => {
var discounts = querySnapshot.docs.map(document => document.data());
var lastVisibleDiscount = discounts[discounts.length - 1].rest_id;
this.setState({
discounts: discounts,
lastVisibleDiscount: lastVisibleDiscount,
loading: false,
});
}));
}
catch (error) {
console.log(error);
}
}
To print the keys of the documents in the collection in the order of the value of their rest_id field, you can do something like this:
firebase.firestore().collection("discounts").orderBy('rest_id').get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id);
});
});
This is an almost literal copy of the code in the documentation on getting all documents from a collection, so I recommend spending some time there.
You can use (using await/async)
const ref = await ref.get()
It will have an array called docs that you can map over to get the id and data of the document:
const data = ref.docs.map(doc => {return {id: doc.id, data: doc.data()} })
I am trying to fetch all fieldnames inside of payload > (random doc id) objects.
Currently I am fetching other collections with:
async fetchPage() {
const query = firebase
.firestore()
.collection('PAGES')
.where('type', '==', 'page')
try {
const { docs } = await query.get()
this.pageIndex = docs.map((doc) => {
if (doc && doc.exists) {
this.items = doc.data()
}
let { id } = doc
const data = doc.data()
return { id, ...data }
})
console.log('Loaded items', this.items)
} catch (error) {
throw new Error('Something gone wrong!')
}
},
The first question is: What is the best practice to query objects? I read this in firebase docs but didn't lead me to any results trying it out that way.
Second question, since the child object of payload is the actual id of its document, what method must I use to declare that I'm looking for e.g payload > doc id > content: "This is some content"?.
Here are some information that are helpful about how Firestore operates and they may prove helpful to you on how to improve queries in your database.
Here is the Firebase documentation about queries and the Query Client Library.
This is an article that refers to the causes of slow queries.
Regarding your second question you can get a snapshot of the whole document and then you have to iterate through the data.
Let me know if this is helpful to you.
I'm looking for the best way to:
1. query for one single result, or
2. extract the first result from the query
tried: collection[0] and collection.pop() or collection.shift() and nothing works
I really don't like the code i'm using, but it works...
export const findUserByEmail = email => {
return firestore()
.collection('users')
.where('email', '==', email.toLowerCase())
.get()
.then(collection => {
console.log(collection)
let user
collection.forEach(doc => user = doc.data())
return user
})
}
Your query returns a QuerySnapshot (see docs). You can access the docs as an array via the docs property; each doc has a data() method:
export const findUserByEmail = email => {
return firestore()
.collection('users')
.where('email', '==', email.toLowerCase())
.get()
.then(querySnapshot => {
if(!querySnapshot.empty) {
const user = querySnapshot.docs[0].data()
// rest of your code
}
})
}
Firestore with Flutter solution:
await FirebaseFirestore.instance
.collection('users')
.where('userId', isEqualTo: loggedInUserId)
.get()
.then((querySnapshot) {
List listData = querySnapshot.docs.toList().map((item) {
// to fetch list of all documents information
return item.data();
}).toList();
if (querySnapshot.docs.length > 0) {
// to fetch first document information
_mappedUserInfo = querySnapshot.docs[0].data();
}
print("listData: ${listData.toString()}");
print("_mappedUserInfo: ${_mappedUserInfo.toString()}");
}).catchError((e) {
print('data error: $e');
});
Result:
Fetched List of documents:
listData: [{name: null, addedOn: Timestamp(seconds=1623663004, nanoseconds=581000000), email: john.doe2021#mailinator.com, phoneNumber: null, userId: yRARGJOaAbM78MW5OBlVEB3VyKkr, lastSignInOn: Timestamp(seconds=1623663004, nanoseconds=581000000), photoURL: null}]
Fetched single document:
_mappedUserInfo: {name: null, addedOn: Timestamp(seconds=1623663004, nanoseconds=581000000), email: john.doe2021#mailinator.com, phoneNumber: null, userId: yRARGJOaAbM78MW5OBlVEB3VyKkr, lastSignInOn: Timestamp(seconds=1623663004, nanoseconds=581000000), photoURL: null}
It worked for me. I hope, this will help you.
tried: collection[0] and collection.pop() and nothing works
Those 2 in order means:
collection[0] - access the first element of an array
collection.pop() - pop get's rid of the last
element of an array
Maybe based on your code logic, you should try: collection[0].data(); as by using collection[0] you access the first element, but from your existing code you need to call .data() to extract it.
forEach does simply access to the whole content of collection.
Whilst collection.pop() is just not the proper tool for the job in this case.
I am trying to query a Firestore sub collection in an ionic 4 app/angular app. My database looks as follows people(id) ----> tasks(id)
{ description : this is a description about a cat,<br>
title: this is a cat <br>
category: cat }
I am using a Firestore function to query all of the data in the collection. This is what the Firestore function looks like:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin'
admin.initializeApp()
export const getFeed = functions.https.onCall(async (req,res) =>{
const docs = await
admin.firestore().collection('people').limit(5).get()
return docs.docs.map(doc => {
return {
postID: doc.id,
...doc.data()
}
})
})
the typescript home.ts file looks like this :
const getFeed = this.aff.httpsCallable('getFeed')
this.posts = getFeed({}).subscribe(data=> {
console.log(data)
// this.posts = data
})
}
I've tried to use the array-contains option to query, but it doesn't
work. The array shows up empty on the console.
export const getFeed = functions.https.onCall(async (req,res) =>{
const docs = await
admin.firestore().collection('people').where("category",
"array-
contains", "cat").limit(5).get()
return docs.docs.map(doc => {
return {
postID: doc.id,
...doc.data()
}
})
})
It's not very clear from your question, but it looks like the category field of your database isn't actually a list type field. array-contains only works if the value is a list, not if it's just a single string value. If it's just a string, then use a == filter on it.
I have found workaround by adopting array field type instead of subcollection.
Here is an example of my code:
var coll = this.firestore.collection('credentials', ref => ref.where('tags', 'array-contains-any', ['agile']).orderBy('shortName')); // selects part of collection where roomId = roomStripped, sorted by name
return coll.snapshotChanges();
I have main collection called credentials, and a list of tags in each document.