Fetch data from Firestore Document using StreamBuilder - flutter

In my Flutter app, I'm trying to get the data from a Document in Firestore. Here's the data I want to get :
Firestore document's data
I need to fetch that url from the Document. So far, when I needed to fetch data from a collection, I used a Streambuilder. But here I need to fetch data from a document, so I get this error message :
late Stream<DocumentSnapshot<Map<String, dynamic>>>? personnalData =
FirebaseFirestore.instance
.collection('Decembre')
.doc(uid)
.collection('Docs')
.doc('test')
.snapshots();
StreamBuilder<QuerySnapshot>(
stream: personnalData, // Error: The argument type 'Stream<DocumentSnapshot<Map<String, dynamic>>>?' can't be assigned to the parameter type 'Stream<QuerySnapshot<Map<String, dynamic>>>?'.
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Stack(
children: snapshot.data!.docs
.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return PageView.builder(
controller: _controller,
itemCount: 3,
itemBuilder: (context, index) {
return Container(
child: InteractiveViewer(
minScale: 0.1,
maxScale: 4.0,
child: Image.network(
// FETCH URL FROM DOCUMENT 'TEST'
width:
MediaQuery.of(context)
.size
.width,
fit: BoxFit.cover,
loadingBuilder: (context,
child,
loadingProgress) {
if (loadingProgress ==
null) {
return child;
} else {
return Center(
child:
CircularProgressIndicator(),
);
),
);
}),
),
],
),
),
);
},
child: Text('Open'));
})
.toList()
.cast(),
);
},
),
Any suggestions ?

I found the solution !
The problem was that I was trying to fetch data from a DocumentSnapshot using a StreamBuilder<QuerySnapshot> instead of StreamBuilder<DocumentSnapshot>
Here's how I solved it :
late Stream<DocumentSnapshot<Map<String, dynamic>>> personnalData =
FirebaseFirestore.instance
.collection('Decembre')
.doc(uid)
.collection('Docs')
.doc('test')
.snapshots();
StreamBuilder<DocumentSnapshot>(
stream: personnalData,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!['url']);
}
return CircularProgressIndicator();
}),
This code is working well for me. I hope that will help somebody !

Maybe what you need is just to specify the type of the QuerySnapshot:
late Stream<DocumentSnapshot<Map<String, dynamic>>> personnalData = // like this FirebaseFirestore.instance
.collection('Decembre')
.doc(uid)
.collection('Docs')
.doc('test')
.snapshots();
because the snapshots() is a method that returns Stream<DocumentSnapshot<Map<String, dynamic>>>, and setting only Stream<DocumentSnapshot> will be considered as a different type, which throws the error.

maybe you can try
StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: personnalData,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Stack(
children: snapshot.data!.docs
.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return PageView.builder(
controller: _controller,
itemCount: 3,
itemBuilder: (context, index) {
return Container(
child: InteractiveViewer(
minScale: 0.1,
maxScale: 4.0,
child: Image.network(
// FETCH URL FROM DOCUMENT 'TEST'
width:
MediaQuery.of(context)
.size
.width,
fit: BoxFit.cover,
loadingBuilder: (context,
child,
loadingProgress) {
if (loadingProgress ==
null) {
return child;
} else {
return Center(
child:
CircularProgressIndicator(),
);
),
);
}),
),
],
),
),
);
},
child: Text('Open'));
})
.toList()
.cast(),
);
},
),
in streamBuilder you can add <DocumentSnapshot<Map<String, dynamic>>> same as you create stream.

Refer the following example:
StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance.collection('Decembre').doc(uid).collection('Docs').doc('test').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return Column(
children:[
Text(doc['url'])
);
});
} else {
return Text("No data");
}
},
)

Related

Null check operator used on a null value

body: StreamBuilder(
stream: db.collection('products').where('category', isEqualTo: 'category').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if(snapshot.hasError){
Fluttertoast.showToast(msg: 'Something error');
}
if(snapshot.connectionState == ConnectionState.waiting) {
CircularProgressIndicator();
}
final values = snapshot.data!.docs;
return ListView.builder(
itemCount: values!.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(values![index]['name']),
),
),
);
}
);
},
),
The following _CastError was thrown building StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(dirty, state: _StreamBuilderBaseState<QuerySnapshot<Map<String, dynamic>>, AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>>>#c87c1):
you missed return in your if blocks, so those widgets are not being returned, this redirect to the snapshot.data!.docs widget which is null initially, change it to this:
body: StreamBuilder(
stream: db.collection('products').where('category', isEqualTo: 'category').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if(snapshot.hasError){
Fluttertoast.showToast(msg: 'Something error');
return Text("error"); // add this to showcase the error
}
if(snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator(); // add this to show loading when data is fetching
}
final values = snapshot.data!.docs;
return ListView.builder(
itemCount: values!.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(values![index]['name']),
),
),
);
}
);
},
),

Null check operator used on a null value in a stream builder, flutter

im getting this exception when i load the page, it appear on display for a moment but when list is loaded it disappears. errors reads out line 255, att line 255 i have a child: streambuilder
i cannot figure out whats wrong
Expanded(
child: StreamBuilder(
stream: restaurants.where('status', isEqualTo: 'Approved').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
return ListView(
children: snapshot.data!.docs.map((restaurants) {
return RestaurantCard(restaurants: restaurants,);
}).toList(),
);
},
),
)
You have to check for different statuses in StreamBuilder, and only build the ListView if there is data available:
StreamBuilder<DocumentSnapshot>(
stream: restaurants.where('status', isEqualTo: 'Approved').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return const Center(
child: Text('Snapshot error'),
);
}
if (!snapshot.hasData) {
return const Center(
child: Text('Snapshot data missing'),
);
}
return ListView(
children: snapshot.data!.docs.map((restaurants) {
return RestaurantCard(restaurants: restaurants,);
}).toList(),
);
})

Stream Builder Returning Null Value in flutter although Data is present in cloud firestore document

I need help with one case in which my stream builder is returning null values.
I am trying to retrieve a list of services stored in cloud firestore and will display using listview builder later. For now trying to see in the container widget.
I am attaching a snap from my cloud firestore data.
Thanks in Advance.
Here is my code,
return Scaffold(
key: _globalKey,
body: Padding(
padding: EdgeInsets.only(left: 20, top: 50, right: 20),
child: StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('city')
.doc(Pune)
.collection(Pashan)
.doc('merchantData')
.collection('merchantInfo')
.where('categoryType', isEqualTo: 'Services')
.orderBy('storeType', descending: true)
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
print(snapshot.data);
if (snapshot.data != null) {
_storeTypes.clear();
for (var num in snapshot.data.docs) {[enter image description here][1]
if (!_storeTypes.contains(num['storeType'])) {
_storeTypes.add(
num['storeType'],
);
}
}
}
return ListView.builder(
itemCount: _storeTypes.length,
itemBuilder: (context, index) {
return Container(
child: Center(
child: Text(_storeTypes[index]),
),
);
},
);
},
),
),
it's because your trying to use the data before it's fetching from firebase so to avoid the above error add the below code above your if conditions .If you find this answer is correct up vote this answer
if (snapshot.hasError) {
return Center(
child: Text("Something went wrong"),
);
}
if (!snapshot.hasData) {
return Center(
child: Text("No notice found"),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}

Why is there an error with snapshot.data.length?

I am trying to parse data from an API. For that, I am using FutureBuilder to list all the parsed data in a ListView.
I've performed a check for nullity of snapshot.data but I keep on getting this error in the segment snapshot.data.length, it says, The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').
I've a similar error in the snapshot.data[i] section, which says The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').
Here is my code's section of the same:
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i].partOfSpeech,
);
});
}
},
),
),
Here's getData(String s):
Future<List> getData(String s) async {
var response = await http
.get(Uri.https('api.dictionaryapi.dev', 'api/v2/entries/en_US/' + s));
var jsonData = jsonDecode(response.body)[0];
List<Data> data = [];
for (var x in jsonData["meanings"]) {
String definition = x["definitions"][0]["definition"];
Data d = Data(x["partOfSpeech"], definition);
data.add(d);
}
return data;
}
if u are using a new version of flutter (2.2.0 or above). first try adding a null check to the target ('!'). because of the null safety feature.
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i].partOfSpeech,
);
});
}
},
),
),
then try specifying the FutureBuilder type to a List of Data type
body: Container(
child: FutureBuilder<List<Data>>(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i].partOfSpeech,
);
});
}
},
),
),
In continuation to this answer,
I found the solution to my problem. Apparently getData was not returning a List as intended. Instead, it was returning an Object.
Typecasting the Object to List solved the problem.
Here's the corrected code:
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
//typecasting Object to List
var data = (snapshot.data as List<Data>).toList();
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, i) {
return ListTile(
title: data[i].partOfSpeech,
);
});
}
},
),
),
Put 'AsyncSnapshot' before snapshot in the builder parameter.
builder: (context, AsyncSnapshot snapshot)
Since you are checking that snapshot.data is not null you can do the following to fix it.
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
} else{
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i]!.partOfSpeech,
);
});
}
},
),
),
What you need to look at is the result of getData('hello')
Apparently, it does not return something that has a length property.

Flutter query (where + order by) from firebase firestore returns error

My queries from flutter app return error. any ideas why?
Query user = FirebaseFirestore.instance.collection('users').where('approvedStatus', isEqualTo: true).orderBy('name');
How i show data from query
Container(
child: StreamBuilder(
stream: user.snapshots(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasError) {
return Text('Snapshot return error');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading ..."); // CircularProgressIndicator();
}
return Container(
height: MediaQuery.of(context).size.height,
child: ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.docs.length,
itemBuilder: (context, i) {
return Card(
child: ListTile(
title: Text(snapshot.data.docs[i]['name'].toString()),
),
);
},
),
);
},
),
),
The result i got is snapshot return error
Nevermind guys. I found the problem after printing snapshot.error
[cloud_firestore/failed-precondition] The query requires an index.
I just follow the link provided and it solve the problem . Thanks