Getting all documents from one collection in Firestore

JavascriptFirebaseReact NativeGoogle Cloud-Firestore

Javascript Problem Overview


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 ?

Javascript Solutions


Solution 1 - Javascript

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());
}

Solution 2 - Javascript

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)
   })
 }

Solution 3 - Javascript

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;
}

Solution 4 - Javascript

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 => {
       const document = { [doc.id]: doc.data() };
       documents.push(document);
    }
    return documents;
}

Solution 5 - Javascript

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.

Solution 6 - Javascript

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 :)

Solution 7 - Javascript

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):

  1. Your event.id is actually stored "one-level-up" in snapshot.id and not snapshot.data().

  2. 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

Solution 8 - Javascript

The docs state:

import { collection, getDocs } from "firebase/firestore";

const querySnapshot = await getDocs(collection(db, "cities"));
querySnapshot.forEach((doc) => {
  // doc.data() is never undefined for query doc snapshots
  console.log(doc.id, " => ", doc.data());
});

However I am using the following (excuse the TypeScript):

import { collection, Firestore, getDocs, Query, QueryDocumentSnapshot, QuerySnapshot } from 'firebase/firestore'

const q: Query<any> = collection(db, 'videos')
const querySnapshot: QuerySnapshot<IVideoProcessed> = await getDocs(q)
const docs: QueryDocumentSnapshot<IVideoProcessed>[] = querySnapshot.docs
const videos: IVideoProcessed[] = docs.map((doc: QueryDocumentSnapshot<IVideoProcessed>) => doc.data())

where db has the type Firestore

Solution 9 - Javascript

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;
            }, {});
}

Solution 10 - Javascript

General example to get products from Cloud Firestore:

  Future<void> getAllProducts() async {
    CollectionReference productsRef =
        FirebaseFirestore.instance.collection('products');
    final snapshot = await productsRef.get();
    List<Map<String, dynamic>> map =
        snapshot.docs.map((doc) => doc.data() as Map<String, dynamic>).toList();
  }

Solution 11 - Javascript

I understand your query, This is because how Javascript handles promises and variables. So basically events variable is hoisted with the value undefined and printed on the LOG 2 console log, while the Event Loop responsible for the promise call resulted in an array of objects as the value of the events variable and then the console log (LOG 1) was printed with the resolved promise response

Solution 12 - Javascript

All answers are true, but when you have heavy data you will face memory and bandwidth problems, so you have to write a [cursor] function to read data part by part.

also, you may face to Bandwidth Exhausted error, please have a look at this solution I have implemented on a gist https://gist.github.com/navidshad/973e9c594a63838d1ebb8f2c2495cf87

Otherwise, you can use this cursor I written to read a collection doc by doc:

async function runCursor({
	collection,
	orderBy,
	limit = 1000,
	onDoc,
	onDone,
}) {
	let lastDoc;
	let allowGoAhead = true;

	const getDocs = () => {
		let query = admin.firestore().collection(collection).orderBy(orderBy).limit(limit)
        // Start from last part
		if (lastDoc) query = query.startAfter(lastDoc)

		return query.get().then(sp => {
			if (sp.docs.length > 0) {
				for (let i = 0; i < sp.docs.length; i++) {
					const doc = sp.docs[i];
					if (onDoc) onDoc(doc);
				}
				// define end of this part
				lastDoc = sp.docs[sp.docs.length - 1]
				// continue the cursor
				allowGoAhead = true
			} else {
				// stop cursor if there is not more docs
				allowGoAhead = false;
			}
		}).catch(error => {
			console.log(error);
		})
	}

	// Read part by part
	while (allowGoAhead) {
		await getDocs();
	}

	onDone();
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStroiView Question on Stackoverflow
Solution 1 - JavascriptDoug StevensonView Answer on Stackoverflow
Solution 2 - JavascriptImanullahView Answer on Stackoverflow
Solution 3 - JavascriptStroiView Answer on Stackoverflow
Solution 4 - JavascriptRodrigoView Answer on Stackoverflow
Solution 5 - JavascriptOneHoopyFroodView Answer on Stackoverflow
Solution 6 - JavascriptNowdeenView Answer on Stackoverflow
Solution 7 - Javascriptr002View Answer on Stackoverflow
Solution 8 - Javascriptdanday74View Answer on Stackoverflow
Solution 9 - JavascriptJoshView Answer on Stackoverflow
Solution 10 - JavascriptSwiftiSwiftView Answer on Stackoverflow
Solution 11 - JavascriptSayanta BhattacharjeeView Answer on Stackoverflow
Solution 12 - JavascriptNavid ShadView Answer on Stackoverflow