Flutter and Cloud Firestore fetch issue - database

I have a problem with Flutter and Cloud Firestore from Firebase.
I already can add data to the database but I can't fetch it, because every time I call my method I get null back.
Here is my code:
dynamic getFromDatabase(String path, String item) {
DocumentReference _docu = Firestore.instance.document('$path');
var data;
_docu.get().then((datasnapshot) {
if(datasnapshot.exists){
data = datasnapshot.data['$item'];
}
});
return data;
}
This is where I call the method:
print((await getFromDatabase("User/$_uid","Vorname")));
And the error:
I/flutter (26289): null

I've not used Firestore before. Only the normal database of firebase. But I think this is a async timing issue. It looks like it's returning null before it can complete the datasnapshot. (PS. datasnapshot is spelled wrong). Try something like this. Like I said. Not sure if it works.
Future<String> getFromDatabse(String path, String item){
DocumentReference _docu = Firestore.instance.document(path);
_docu.get().then((datasnapchot){
if(datasnapchot.exists){
return datasnapchot.data[item];
}
});
}
And when calling the method. Do this.
String getData = await getFromDatabse(path, item);
(PS also database is spelled wrong haha)

A good option is using the FutureBuilder widget.
You can use it inside a StatelessWidget, avoiding to implemente a StatefulWidget
FutureBuilder(
future: Firestore.instance.document(path).get(),
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text('Something went wrong.');
}
DocumentSnapshot docSnap = snapshot.data as DocumentSnapshot;
return Text(docSnap.data['doc_field']);
}
)

Related

Hive database not working offline while works fine when connected to internet

I am developing a flutter application in which I am implementing hive database for caching data.
I have added both hive and hive_flutter packages.
I am getting data from APIs and store that to hive to update data, It works fine when I used app connected to internet but didn't works when I try to read while being offline. Here is the code of my API method I am calling to get data:
static Future<List<UserPost>> getPosts() async {
//I call my API in try block, if its successful, I update the data in hive
List<UserPost> posts = [];
Hive.openBox(Constants.APIDATA_BOX);
try {
var response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'),);
if (response.statusCode == 200) {
//Clear hive box from old data
Hive.box(Constants.APIDATA_BOX).clear();
Hive.box(Constants.APIDATA_BOX).put(Constants.API_DATA,jsonDecode(response.body));
}
} catch (e) {
print('You are not connected to internet');
}
//I am getting data here from hive database and it works fine while connected to internet
var listMaps =await Hive.box(Constants.APIDATA_BOX).get(Constants.API_DATA, defaultValue: []);
posts = listMaps.map<UserPost>((map) {
//Here flow stucked whenever working offline,
//Data is also available but here conversion cause error, I have tried many way but fails.
return UserPost.fromMap(map);
}).toList();
return posts;
}
I don't why I am getting error, I have tried many conversion ways here but all works while being online. Any help will be highly apprerciated.
I think I've understood the error but you should explain better which type of error you're having.
Anyway pay attention to the operations on Hive, which are often async, for example Hive.openBox(Constants.APIDATA_BOX);.
So when you have internet connection, you have to await for the response and Hive has time to open the box, otherwise it will throw an error so, considering the futures, you should do this:
static Future<List<UserPost>> getPosts() async {
List<UserPost> posts = [];
await Hive.openBox(Constants.APIDATA_BOX);
try {
var response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'),);
if (response.statusCode == 200) {
//Clear hive box from old data
await Hive.box(Constants.APIDATA_BOX).clear();
await Hive.box(Constants.APIDATA_BOX).put(Constants.API_DATA,jsonDecode(response.body));
}
} catch (e) {
print('You are not connected to internet');
}
var listMaps = await Hive.box(Constants.APIDATA_BOX).get(Constants.API_DATA, defaultValue: []);
posts = listMaps.map<UserPost>((map) {
return UserPost.fromMap(map);
}).toList();
return posts;
}
Note that await Hive.put() in a normal box is not strictly necessary, as explained in the docs

Flutter: How to fetch a particular record from firebase

This is the screenshot of my database.
I want to fetch the record for a particular username. (For eg: where user=nam#gmail.com) Can anyone suggest to me how to fetch this in flutter?
It would be a great help, Thank you.
To get the data, you can create a function like:
Future getData(String username) async {
List dataList = [];
try {
await FirebaseFirestore.instance.collection('userdata').where('user', isEqualTo: username).get().then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) {
itemList.add(doc.data());
}),
});
return itemList;
} catch (e) {
print(e.toString());
return null;
}
}
When you'll call this function, you will have to pass the username and it would return a list of data items.
This list can then be used to show data in the UI as:
child: Text(
title: Text(subjectList[index]['user']),
),
you can try this approach it helped me, but if you have migrated to null safety just make sure that you change the code accordingly
You can try the following query to get your result.
FirebaseFirestore.instance
.collection('your-collection-name')
.where('user', arrayContains: 'nam#gmail.com')
.get();
For android solution follow this:
FirebaseFirestore.getInstance()
.collection("users").whereArrayContains("user","nam#gmail.com").get();

I want to send an array of objects to asp.net web api from React

//This is how i'm trying to send[this how it appear in the console ][1]
const paramz = new URLSearchParams()
paramz.append('meals',this.state.meals)
let URLL=`https://localhost:44327/api/AddMealOrderr`
axios.post(URLL,paramz,config).then(res=>{
console.log(res)
}).catch(error=>{
console.log(error)
})
}
//this is my web api action
public IHttpActionResult PostMealOrder(List<MealOrder> meals)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
for (int i = 0; i < meals.Count; i++)
{
db.MealOrders.Add(meals[i]);
}
db.SaveChanges();
return Ok(meals);
}
[1]: https://i.stack.imgur.com/kYwI8.png*emphasized text*
is the request getting a hit ? adding a breakpoint at the if statement should detect whether the request is being detected at the api or not.
that being said, i dont think you need URLSearchParams since you are issuing a post request you should be looking at FormData()
check this it should help a little bit.

How does Meteor methods return results?

I am using meteor/react for learning facebook graph api.
I want to access users' post on facebook timeline and display them on screen. How can that be done?
With the guidance of the solution provided here [How to perform common FB actions using Meteor?. I have tried the following code: server.js
Meteor.methods({
'seePost' : function(){
var graph=Npm.require('fbgraph');
if(Meteor.user().services.facebook.accessToken){
graph.setAccessToken(Meteor.user().services.facebook.accessToken);
var future = new Future();
var onComplete = future.resolver();
graph.get('/me/feed',function(err,result) {
console.log(result);
return onComplete(err,result);
})
Future.wait(future);
}
else{
return false;
}
}
});
client side code :
Meteor.call("seePost", function(err,result) {
if(err) console.log("error" , err);
else console.log("RES", result);
});
I expect the result displayed in the client side console since I want to show the users the posts on his/er timeline, But I get following output :
RES, undefined
You can do it using await and Meteor.callAsync
Basically the client code waits for the call to complete, and gives you the returned data
const result = await Meteor.callAsync("seePost");
Errors should be handled with a try..catch block
If you use fibers/future, you need to return something with "future".
const future = new Future();
// some code getting result or something
future.return(something);
return future.wait();
this will return something in the callback from client call.
try this code, when you're using fibers you need to "wait" for the response
Meteor.methods({
'seePost': function () {
var graph = Npm.require('fbgraph');
if (Meteor.user().services.facebook.accessToken) {
graph.setAccessToken(Meteor.user().services.facebook.accessToken);
var future = new Future();
var onComplete = future.resolver();
graph.get('/me/feed', function (err, result) {
console.log(result);
if (err) {
return future.return(false);
} else {
return future.return(result);
}
})
return future.wait();
}
return false;
}
});

Firebase: Access to database.....but confused at onDataChange method

So i am curious when does onDataChange method occur?
It seems like it is activated when user add new information or change already existed data.
However, what I am trying to do is that, before adding new data, I want to check if the item is existing in database....if there is an identical item, adding new data won't be done, or if there is no such item, then it should be added to database.
so, my actual question is that, this process "Checking all the database items", can it be done without using onDataChange method?
You basically set up a subscription to the "onDataChange" so its actually watching firebase for changes.
But for checking you could literate through the results or do one time query to the exact path your data it held at.
It also may be a better choice to record everything and then remove the data when not needed.
import { AngularFirestore } from 'angularfire2/firestore';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
import { map } from 'rxjs/operators';
import { Observable, Subscription } from 'rxjs';
import firebase as firebase from 'firebase/app';
private mysubscription: Subscription;
public this.items:any = [];
constructor(
public _DB: AngularFireDatabase
) {
try {
//subscription using AngulaFire
this.mysubscription = this._DB.list("myFireBaseDataPath").snapshotChanges().pipe(map(actions => {
return actions.map(action => ({ key: action.key, val: action.payload.val() }));
}))
.subscribe(items => {
this.items = [];
this.items = items.map(item => item);
console.log("db results",this.items);
var icount=0;
for (let i in this.items) {
console.log("key",this.items[i].key);
console.log("val",this.items[i].val);
console.log("----------------------------------);
//checking if something exists
if (this.items[i].key == 'SomeNodePath') {
var log = this.items[i].val;
}
}
} catch (e) {
console.error(e);
}
});
}
ngOnDestroy() {
this.mysubscription.unsubscribe();
}
//or we can do a one time query using just the firebase module
try {
return firebase.database().ref("myFireBaseDataPath").once('value').then(function(snapshot) { return snapshot.val(); })
.then(res => {
for (let myNode in res) {
console.log(res[myNode]);
console.warn(res[myNode].myChildPath);
console.log("----------------------------------);
}
})
.catch(error => console.log(error));
} catch (e) {
console.error(e);
}
//however it may be better practice to log all data and then firebase.database().ref(/logs").remove(); the entire log when not needed
var desc ="abc";
let newPostKey = firebase.database().ref("/logs").push();
newPostKey.set({
'info': desc,
'datetime': new Date().toISOString()
});
When does onDataChange method occur?
The onDataChange method is called for every change in the database reference it is attached to. It is also called for every visit to the database reference it is attached to.
For example,
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("some/database/refrence");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method will be fired for any change in the
database.getReference("some/database/refrence") part of the database.
// It will also be fired anytime you request for data in the
database.getReference("some/database/refrence") part of the database
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
// This method will be fired anytime you request for data in the
database.getReference("some/database/refrence") part of the database
and an error occurred
}
});
Before adding new data, I want to check if the item is existing in database....if there is an identical item, adding new data won't be done, or if there is no such item, then it should be added to database.
This can be done by calling the exists() method on the snapshot retrieved from your database query.
Check this stackoverflow question Checking if a particular value exists in the firebase database for an answer to that
So, my actual question is that, this process "Checking all the database items", can it be done without using onDataChange method?
No. The onDataChange method is the callback used to retrieve data from the database. Even if you use the equalTo() method on a query, you'll still have to use the onDataChange method.
I am not a Firebaser Specialist tho. There are folks who work at Firebase on here. They could give you more information
PS: Please make your own research on your questions first before asking. Some questions are already answered in the documentation and on stackoverflow.

Resources