Query a single document from Firestore in Flutter (cloud_firestore Plugin)
Asked Answered
L

11

61

Edit: This Question is outdated, and I am sure, new documentation and more recent answers are available as of now.

I want to retrieve data of only a single document via its ID. My approach with example data of:

TESTID1 {
     'name': 'example', 
     'data': 'sample data',
}

was something like this:

Firestore.instance.document('TESTID1').get() => then(function(document) {
    print(document('name'));
}

but that does not seem to be correct syntax.

I was not able to find any detailed documentation on querying firestore within flutter (dart) since the firebase documentation only addresses Native WEB, iOS, Android etc. but not Flutter. The documentation of cloud_firestore is also way too short. There is only one example that shows how to query multiple documents into a stream which is not what i want to do.

Related issue on missing documentation: https://github.com/flutter/flutter/issues/14324

It can't be that hard to get data from a single document.

UPDATE:

Firestore.instance.collection('COLLECTION').document('ID')
.get().then((DocumentSnapshot) =>
      print(DocumentSnapshot.data['key'].toString());
);

is not executed.

Lyrate answered 28/11, 2018 at 10:33 Comment(0)
G
43

Null safe code (Recommended)

You can either query the document in a function (for example on press of a button) or inside a widget (like a FutureBuilder).

  • In a method: (one time listen)

    var collection = FirebaseFirestore.instance.collection('users');
    var docSnapshot = await collection.doc('doc_id').get();
    if (docSnapshot.exists) {
      Map<String, dynamic>? data = docSnapshot.data();
      var value = data?['some_field']; // <-- The value you want to retrieve. 
      // Call setState if needed.
    }
    
  • In a FutureBuilder (one time listen)

    FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
      future: collection.doc('doc_id').get(),
      builder: (_, snapshot) {
        if (snapshot.hasError) return Text ('Error = ${snapshot.error}');
    
        if (snapshot.hasData) {
          var data = snapshot.data!.data();
          var value = data!['some_field']; // <-- Your value
          return Text('Value = $value');
        }
    
        return Center(child: CircularProgressIndicator());
      },
    )
    
  • In a StreamBuilder: (always listening)

    StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
      stream: collection.doc('doc_id').snapshots(),
      builder: (_, snapshot) {
        if (snapshot.hasError) return Text('Error = ${snapshot.error}');
    
        if (snapshot.hasData) {
          var output = snapshot.data!.data();
          var value = output!['some_field']; // <-- Your value
          return Text('Value = $value');
        }
    
        return Center(child: CircularProgressIndicator());
      },
    )
    
Gesellschaft answered 6/6, 2021 at 14:54 Comment(2)
Can we get the subcollection along with the document by any of these methods?Morton
what should i return if docSnapsot does not exist?Spenserian
B
91

but that does not seem to be the correct syntax.

It is not the correct syntax because you are missing a collection() call. To solve this, you should use something like this:

var document = await Firestore.instance.collection('COLLECTION_NAME').document('TESTID1');
document.get() => then(function(document) {
    print(document("name"));
});

Or in more simpler way:

var document = await Firestore.instance.document('COLLECTION_NAME/TESTID1');
document.get() => then(function(document) {
    print(document("name"));
});

If you want to get data in realtime, please use the following code:

Widget build(BuildContext context) {
  return new StreamBuilder(
      stream: Firestore.instance.collection('COLLECTION_NAME').document('TESTID1').snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return new Text("Loading");
        }
        var userDocument = snapshot.data;
        return new Text(userDocument["name"]);
      }
  );
}

It will help you set also the name to a text view.

Banka answered 28/11, 2018 at 10:52 Comment(15)
The error you pointed out is true but is not the main problem. According to AndroidStudio: the getter for DocumentReference is not defined. So document().get() is invalid as well. I find there is a lack of information on the basic syntax of these queries. I have even read the specificationLyrate
You should also use await. Please see my updated answer. Does it work now?Banka
I did vote +1, but it will only appear publicly when i earn enough reputation.. Is there any documentation or resource on this, you can recommend?Lyrate
Regarding Firebase, official docs. Regarding Firebase and Flutter I don't know.Banka
I tried the realtime stream and I get this error The argument type 'Stream<DocumentSnapshot>' can't be assigned to the parameter type 'Stream<QuerySnapshot>'.. Any idea ?Undershirt
@ThéoChampion Please post another question for that problem with its own MCVE so me and other Firebase developers can help you.Banka
there are some typos in the code arent they? document('name') should be document['name'] as far as i understand how documents work with firestoreTolliver
if I try to pass userDocument to a new page as an argument I cannot do userDocument["name"] on the second page. I get an error because name doesn't exist (but it's Instance of 'DocumentSnapshot')Tabina
@Tabina Without seeing your code, I cannot be much of a help. So please post another fresh question, so I and other Firebase developers can help you.Banka
It's exactly the same as the code above van sending the params instead: var userDocument = snapshot.data; Navigator.of(context).pushNamed( '/my-set', arguments: userDocument );Tabina
got it. Passing now userDocument.dat, which is the actual map (#56722194)Tabina
Thank you @AlexMamo , you answer is helpful .. Thanks a lotStraitlaced
@AlexMamo for me I am getting this question issue with Builder. can you look into my gist. I have attached code output. and printed document. gist.github.com/surapuramakhil/5dbbc060c92557c18ecab6e2dc9b9cbdChalcedony
@AkhilSurapuram You should post a new question using its own MCVE, so I and other Firebase developers can help you.Banka
I believe "Firestore.instance..." has been deprecated in favor of "FirebaseFirestore.instance..." per documentation at firebase.flutter.dev/docs/migration/#firestoreShluh
G
43

Null safe code (Recommended)

You can either query the document in a function (for example on press of a button) or inside a widget (like a FutureBuilder).

  • In a method: (one time listen)

    var collection = FirebaseFirestore.instance.collection('users');
    var docSnapshot = await collection.doc('doc_id').get();
    if (docSnapshot.exists) {
      Map<String, dynamic>? data = docSnapshot.data();
      var value = data?['some_field']; // <-- The value you want to retrieve. 
      // Call setState if needed.
    }
    
  • In a FutureBuilder (one time listen)

    FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
      future: collection.doc('doc_id').get(),
      builder: (_, snapshot) {
        if (snapshot.hasError) return Text ('Error = ${snapshot.error}');
    
        if (snapshot.hasData) {
          var data = snapshot.data!.data();
          var value = data!['some_field']; // <-- Your value
          return Text('Value = $value');
        }
    
        return Center(child: CircularProgressIndicator());
      },
    )
    
  • In a StreamBuilder: (always listening)

    StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
      stream: collection.doc('doc_id').snapshots(),
      builder: (_, snapshot) {
        if (snapshot.hasError) return Text('Error = ${snapshot.error}');
    
        if (snapshot.hasData) {
          var output = snapshot.data!.data();
          var value = output!['some_field']; // <-- Your value
          return Text('Value = $value');
        }
    
        return Center(child: CircularProgressIndicator());
      },
    )
    
Gesellschaft answered 6/6, 2021 at 14:54 Comment(2)
Can we get the subcollection along with the document by any of these methods?Morton
what should i return if docSnapsot does not exist?Spenserian
N
27

If you want to use a where clause

await Firestore.instance.collection('collection_name').where(
    FieldPath.documentId,
    isEqualTo: "some_id"
).getDocuments().then((event) {
    if (event.documents.isNotEmpty) {
        Map<String, dynamic> documentData = event.documents.single.data; //if it is a single document
    }
}).catchError((e) => print("error fetching data: $e"));
Nuptial answered 3/5, 2020 at 16:5 Comment(5)
I was looking for thisSteed
how to use it later to get value from the fetched document?Illeetvilaine
@Harsh Jhunjhunuwala You can use it as a Map. Eg: if you want to retrieve a field called name from the document, var name = documentData["name"];Nuptial
it says "A value of type 'Map<String, dynamic> Function()' can't be assigned to a variable of type 'Map<String, dynamic>"Toast
can this be cast to custom model?Economist
D
13

This is simple you can use a DOCUMENT SNAPSHOT

DocumentSnapshot variable = await Firestore.instance.collection('COLLECTION NAME').document('DOCUMENT ID').get();

You can access its data using variable.data['FEILD_NAME']

Discomfortable answered 4/9, 2020 at 7:14 Comment(2)
I can't "the operator '[]' isn't defined for the type 'Map<String, dynamic> Function()'. "Toast
To access the data you must write variable.data()['FIELD_NAME']. I had the same problem and the () was missing.Erek
M
7

Update FirebaseFirestore 12/2021

StreamBuilder(
          stream: FirebaseFirestore.instance
              .collection('YOUR COLLECTION NAME')
              .doc(id) //ID OF DOCUMENT
              .snapshots(),
        builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return new CircularProgressIndicator();
        }
        var document = snapshot.data;
        return new Text(document["name"]);
     }
  );
}
Miksen answered 30/12, 2020 at 4:39 Comment(2)
How can you take out a certain piece of information using this? Lets Say my collection is books Document is Harry Potter And under that i have table with Title Author Description, how would i print the author?Tennison
Widget _buildBookItem(BuildContext context, int index, AsyncSnapshot snapshot) { final doc = snapshot.data.docs[index]; return Text(print(doc.author)); };Miksen
L
3

This is what worked for me in 2021

      var userPhotos;
      Future<void> getPhoto(id) async {
        //query the user photo
        await FirebaseFirestore.instance.collection("users").doc(id).snapshots().listen((event) {
          setState(() {
            userPhotos = event.get("photoUrl");
            print(userPhotos);
          });
        });
      }
Lunkhead answered 11/1, 2021 at 7:11 Comment(1)
Is this a Future Query or a Stream Query? The return is a Future, but isn't the snapshots query for Stream? I'm confused.Bloomers
Q
3

Use this code when you just want to fetch a document from firestore collection , to perform some operations on it, and not to display it using some widget (updated jan 2022 )

   fetchDoc() async {

   // enter here the path , from where you want to fetch the doc
   DocumentSnapshot pathData = await FirebaseFirestore.instance
       .collection('ProfileData')
       .doc(currentUser.uid)
       .get();

   if (pathData.exists) {
     Map<String, dynamic>? fetchDoc = pathData.data() as Map<String, dynamic>?;
     
     //Now use fetchDoc?['KEY_names'], to access the data from firestore, to perform operations , for eg
     controllerName.text = fetchDoc?['userName']


     // setState(() {});  // use only if needed
   }
}
Quillet answered 3/1, 2022 at 10:10 Comment(0)
R
1

Simple way :

StreamBuilder(
          stream: FirebaseFirestore.instance
              .collection('YOUR COLLECTION NAME')
              .doc(id) //ID OF DOCUMENT
              .snapshots(),
        builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return new CircularProgressIndicator();
        }
        var document = snapshot.data;
        return new Text(document["name"]);
     }
  );
}
Robinia answered 21/5, 2021 at 22:16 Comment(0)
F
1
        var  document = await FirebaseFirestore.instance.collection('Users').doc('CXvGTxT49NUoKi9gRt96ltvljz42').get();
        Map<String,dynamic>? value = document.data();
        print(value!['userId']);
Fateful answered 29/5, 2022 at 12:52 Comment(1)
Please include an explanation with your answer to help users understand how this answers the questionDeel
C
1

You can get the Firestore document by following code:

future FirebaseDocument() async{

    var variable = await FirebaseFirestore.instance.collection('Collection_name').doc('Document_Id').get();
    print(variable['field_name']); 
}
Cognizable answered 5/10, 2022 at 10:26 Comment(0)
L
-3

Use this simple code:

Firestore.instance.collection("users").document().setData({
   "name":"Majeed Ahmed"
});
Leftist answered 25/9, 2021 at 7:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.