Hi I'm starting with javascript and react-native and I'm trying to figure out this problem for hours now. Can someone explain me how to get all the documents from firestore collection ?
I have been trying this:
async getMarkers() {
const events = await firebase.firestore().collection('events').get()
.then(querySnapshot => {
querySnapshot.docs.map(doc => {
console.log('LOG 1', doc.data());
return doc.data();
});
});
console.log('LOG 2', events);
return events;
}
Log 1 prints all the objects(one by one) but log 2 is undefined, why ?
This question is related to
javascript
firebase
react-native
google-cloud-firestore
The example in the other answer is unnecessarily complex. This would be more straightforward, if all you want to do is return the raw data objects for each document in a query or collection:
async getMarker() {
const snapshot = await firebase.firestore().collection('events').get()
return snapshot.docs.map(doc => doc.data());
}
if you want include Id
async getMarkers() {
const events = await firebase.firestore().collection('events')
events.get().then((querySnapshot) => {
const tempDoc = querySnapshot.docs.map((doc) => {
return { id: doc.id, ...doc.data() }
})
console.log(tempDoc)
})
}
Same way with array
async getMarkers() {
const events = await firebase.firestore().collection('events')
events.get().then((querySnapshot) => {
const tempDoc = []
querySnapshot.forEach((doc) => {
tempDoc.push({ id: doc.id, ...doc.data() })
})
console.log(tempDoc)
})
}
if you need to include the key of the document in the response, another alternative is:
async getMarker() {
const snapshot = await firebase.firestore().collection('events').get()
const documents = [];
snapshot.forEach(doc => {
documents[doc.id] = doc.data();
});
return documents;
}
I made it work this way:
async getMarkers() {
const markers = [];
await firebase.firestore().collection('events').get()
.then(querySnapshot => {
querySnapshot.docs.forEach(doc => {
markers.push(doc.data());
});
});
return markers;
}
You could get the whole collection as an object, rather than array like this:
async getMarker() {
const snapshot = await firebase.firestore().collection('events').get()
const collection = {};
snapshot.forEach(doc => {
collection[doc.id] = doc.data();
});
return collection;
}
That would give you a better representation of what's in firestore. Nothing wrong with an array, just another option.
I prefer to hide all code complexity in my services... so, I generally use something like this:
In my events.service.ts
async getEvents() {
const snapchot = await this.db.collection('events').ref.get();
return new Promise <Event[]> (resolve => {
const v = snapchot.docs.map(x => {
const obj = x.data();
obj.id = x.id;
return obj as Event;
});
resolve(v);
});
}
In my sth.page.ts
myList: Event[];
construct(private service: EventsService){}
async ngOnInit() {
this.myList = await this.service.getEvents();
}
Enjoy :)
Here's a simple version of the top answer, but going into an object with the document ids:
async getMarker() {
const snapshot = await firebase.firestore().collection('events').get()
return snapshot.docs.reduce(function (acc, doc, i) {
acc[doc.id] = doc.data();
return acc;
}, {});
}
Try following LOCs
let query = firestore.collection('events');
let response = [];
await query.get().then(querySnapshot => {
let docs = querySnapshot.docs;
for (let doc of docs) {
const selectedEvent = {
id: doc.id,
item: doc.data().event
};
response.push(selectedEvent);
}
return response;
Two years late but I just began reading the Firestore documentation recently cover to cover for fun and found withConverter
which I saw wasn't posted in any of the above answers. Thus:
If you want to include ids and also use withConverter
(Firestore's version of ORMs, like ActiveRecord for Ruby on Rails, Entity Framework for .NET, etc), then this might be useful for you:
Somewhere in your project, you probably have your Event
model properly defined. For example, something like:
Your model (in TypeScript
):
./models/Event.js
export class Event {
constructor (
public id: string,
public title: string,
public datetime: Date
)
}
export const eventConverter = {
toFirestore: function (event: Event) {
return {
// id: event.id, // Note! Not in ".data()" of the model!
title: event.title,
datetime: event.datetime
}
},
fromFirestore: function (snapshot: any, options: any) {
const data = snapshot.data(options)
const id = snapshot.id
return new Event(id, data.title, data.datetime)
}
}
And then your client-side TypeScript
code:
import { eventConverter } from './models/Event.js'
...
async function loadEvents () {
const qs = await firebase.firestore().collection('events')
.orderBy('datetime').limit(3) // Remember to limit return sizes!
.withConverter(eventConverter).get()
const events = qs.docs.map((doc: any) => doc.data())
...
}
Two interesting quirks of Firestore to notice (or at least, I thought were interesting):
Your event.id
is actually stored "one-level-up" in snapshot.id
and not snapshot.data()
.
If you're using TypeScript, the TS linter (or whatever it's called) sadly isn't smart enough to understand:
const events = qs.docs.map((doc: Event) => doc.data())
even though right above it you explicitly stated:
.withConverter(eventConverter)
Which is why it needs to be doc: any
.
(But! You will actually get Array<Event>
back! (Not Array<Map>
back.) That's the entire point of withConverter
... That way if you have any object methods (not shown here in this example), you can immediately use them.)
It makes sense to me but I guess I've gotten so greedy/spoiled that I just kinda expect my VS Code, ESLint, and the TS Watcher to literally do everything for me. Oh well.
Formal docs (about withConverter
and more) here: https://firebase.google.com/docs/firestore/query-data/get-data#custom_objects
Source: Stackoverflow.com