List remains empty after adding elements in flutter firebase - flutter

I have tried to add session model to a list of sessions like this but the list reamains empty. My database has the following structure
void getData()
{
var Ref = fb.ref("sessions");
Ref.onValue.listen((event){
var snapshot = event.snapshot;
Iterable<DataSnapshot> children = snapshot.children;
for( var k in children)
{
var ref = fb.ref("sessions/${k.key}");
ref.onValue.listen((event) {
var snp = event.snapshot;
Iterable<DataSnapshot> chi = snp.children;
for(var v in chi)
{
Session s = new Session();
s.timeStamp = v.key.toString();
s.date = k.key.toString();
s.session = v.value.toString();
sessions.add(s);
}
});
}
sessions.refresh();
print(sessions);
totalsessions.value = sessions.length;
});
}
Output
I/flutter (11551): []

Data is loaded from Firebase (and most modern cloud APIs) asynchronously, and while that is going on your main code continues to execute.
It's easiest to see this if you run in a debugger or add some logging statements like this:
var ref = fb.ref("sessions");
print("Before attaching first onValue");
ref.onValue.listen((event) {
print("In first onValue");
var snapshot = event.snapshot;
Iterable<DataSnapshot> children = snapshot.children;
for( var k in children) {
var ref = fb.ref("sessions/${k.key}");
ref.onValue.listen((event) {
print("In second onValue");
});
}
print("After second onValue");
});
print("After first onValue");
When you run this code, it prints:
Before first onValue
After first onValue
In first onValue
After second onValue
In second onValue
This may not be what you expect, but it does explain why your sessions is empty when you print it. By the time your print(sessions) runs, the sessions.add(s) hasn't happened yet.
This problem is incredibly common, and the solution is always the same: any code that needs the data from the database has to be inside the callback that runs when that data is available.
So:
var ref = fb.ref("sessions");
ref.onValue.listen((event){
var snapshot = event.snapshot;
Iterable<DataSnapshot> children = snapshot.children;
for(var k in children) {
var ref = fb.ref("sessions/${k.key}");
ref.onValue.listen((event) {
var snp = event.snapshot;
Iterable<DataSnapshot> chi = snp.children;
for(var v in chi) {
Session s = new Session();
s.timeStamp = v.key.toString();
s.date = k.key.toString();
s.session = v.value.toString();
sessions.add(s);
}
sessions.refresh();
print(sessions);
totalsessions.value = sessions.length;
});
}
});
In your case though, we can simplify the code a lot further. Since you get a read sessions, the snapshot you get contains all data under that path in the database. So you don't need additional listeners to get each specific sessions, but can get the data from the children.
Something like:
var ref = fb.ref("sessions");
ref.onValue.listen((event){
var snapshot = event.snapshot;
Iterable<DataSnapshot> children = snapshot.children;
for(var child in children) {
Iterable<DataSnapshot> grandchildren = child.children;
for(var grandchild in grandchildren) {
Session s = new Session();
s.timeStamp = grandchild.key.toString();
s.date = child.key.toString();
s.session = grandchild.value.toString();
sessions.add(s);
}
sessions.refresh();
print(sessions);
totalsessions.value = sessions.length;
}
});

Related

Dialogflow fulfillment - How to add multiple agent.add() responses?

I have a list of firestore snapshot that I want to be as responses to an intent. I declare it into "res" varible and pass it into agent.add but it doesn't work. The "res" variable doesn't print anything.
Here is my code:
async function handlerReadFromDB(agent) {
let uId = agent.originalRequest.payload.uId;
console.log(uId);
const dataRef = db.collection('users').doc(`${uId}`).collection('medic_reminder');
const snapshot = await dataRef.get();
var med={};
var medObj = [];
var medRef={};
snapshot.forEach(doc => {
med=doc.data();
medObj.push({data: med});
});
var i;
var str="You need to take ";
for( i in medObj){
str = str +`${medObj[i].data.medName} at ${medObj[i].data.hour}:${medObj[i].data.min},`;
i++;
}
console.log(str);
return agent.add(`Yes, `+str);
}

Trying to Move Cards

I am trying to move a card I have found using the search function from one list to another on the same board.
I have tried to set up a new list using the a new factory.list and searching for the list using FirstorDefault LINQ Query but keep getting an Error.
Below is some code I have tried to move my cards.
string query = jnum;
var search = factory.Search(query, 1, SearchModelType.Cards, new IQueryable[] { board });
await search.Refresh();
var CardList = search.Cards.ToList();
foreach (var card in CardList)
{
string tName = card.Name.Substring(0, 6);
if (tName == jnum.Trim())
{
cardid = card.Id;
}
}
var FoundCard = factory.Card(cardid);
string FoundListid = FoundCard.List.Id;
var fromlist = factory.List(FoundListid);
if (Item != null)
{
if (mail.Body.ToUpper().Contains("Approved for Print".ToUpper()))
{
//var ToList = factory.List("5db19603e4428377d77963b4");
var ToList = board.Lists.FirstOrDefault(l => l.Name == "Signed Off");
FoundCard.List = ToList;
// from on proof
//MessageBox.Show("Approved for Print");
}
else if (mail.Body.ToUpper().Contains("Awaiting Review".ToUpper()))
{
//var ToList = factory.List("5db19603e4428377d77963b3");
var ToList = board.Lists.FirstOrDefault(l => l.Name == "On Proof");
FoundCard.List = ToList;
// from in progress or to start
// MessageBox.Show("Awaiting Review");
}
else if (mail.Body.ToUpper().Contains("Amends".ToUpper()))
{
var ToList = factory.List("5dc9442eb245e60a39b3d4a7");
FoundCard.List = ToList;
// from on proof
//MessageBox.Show("Amends");
}
else
{
// non job mail
}
}
I keep getting a is not a valid value Error.
Thanks for help

How to improve speed of query for Firestore + Flutter?

I have Flutter + Firestore app with a perfomance problem: large database query execution time (about a 5 sec.). I have a small database size, I think that if it increases, the query execution speed will be even greater. How can I improve application performance?
import 'package:carstat/models/entry.dart';
import 'package:carstat/models/operation.dart';
import 'package:carstat/services/data_service.dart';
class DashboardService {
DataService dataService = DataService();
getMarkers(List<Entry> entries, String carId) async {
var _markers = [];
for (int i = 0; i < entries.length; i++) {
List<Operation> _operations = [];
_operations =
await dataService.getEntryOperations(entries[i].entryId, carId);
_markers.add({'entry': entries[i], 'operations': _operations});
}
return _markers;
}
}
My data structure for example:
.document(docId)
.collection('cars')
.document(carId)
.collection('entries')
.document(entryId)
.collection('operations')
.document();
DataService code:
getEntryOperations(String entryId, String carId) async {
List<Operation> _operations = [];
Future<QuerySnapshot> _userDoc =
fs.where('userId', isEqualTo: _userId).getDocuments();
await _userDoc.then((res) {
docId = res.documents[0].documentID;
});
Future<QuerySnapshot> _entryOperations = fs
.document(docId)
.collection('cars')
.document(carId)
.collection('entries')
.document(entryId)
.collection('operations')
.getDocuments();
await _entryOperations.then((val) {
for (int i = 0; i < val.documents.length; i++) {
var _operation = Operation();
_operation.entryId = entryId;
_operation.operationNote = val.documents[i].data['operationNote'];
_operation.operationDate =
val.documents[i].data['operationDate'].toDate();
_operation.operationMileage = val.documents[i].data['operationMileage'];
_operation.operationPartName =
val.documents[i].data['operationPartName'];
_operation.operationPrice = val.documents[i].data['operationPrice'];
_operation.partPrice = val.documents[i]['partPrice'];
_operation.operationId = val.documents[i]['operationId'];
_operations.add(_operation);
}
});
return _operations;
}
The query you're showing is unconditionally getting all of the documents in a specific subcollection. Of course, that will take more time as the collection grows. There is no secret trick or special flag to pass to make this query happen any faster.
In fact, there is not much you can do about this at all, other than to limit the size of the collection, or limit the number of documents in the query. You might also want to reconsider your database structure to reduce the number of documents you're fetching.
My answer, much faster
class DashboardService {
DataService dataService = DataService();
getMarkers(List<Entry> entries, String carId) async {
var _marker = []; // коллекция списков операторов для каждого регламента ТО
final opsForEntries = await Future.wait(
entries.map((value) {
return dataService.getEntryOperations(value.entryId, carId);
})
);
for(int i = 0; i < entries.length; i++) {
_marker.add(
{
'entry': entries[i],
'operations': opsForEntries[i]
}
);
}
return _marker;
}
}

How do I retrieve the files from localstorage by the extension name ".log"?

I am new to angular/js/ionic. I have a really quick question.
How do I retrieve data from localstorage when I don't really know the index name? I just want to grab whatever ends with ".log"?
I understand that the code below will try to retrieve the data by the index 'notes'.
var logFile = angular.fromJson(window.localStorage['notes'] || '[]');
var localLogFile = function() {
for(var i = 0; i < localStorage.length; i++) {
var keyName = localStorage.key(i);
var extension = keyName.substring(keyName.lastIndexOf("."));
if(extension == ".log") {
return localStorage.getItem(keyName);
}
}
};
var logFile = angular.fromJson(localLogFile());

not able to save documents in mongodb c# with .Net driver 2.0

I want to save the document in a collection my method is as below but it is not saving at all.
internal static void InitializeDb()
{
var db = GetConnection();
var collection = db.GetCollection<BsonDocument>("locations");
var locations = new List<BsonDocument>();
var json = JObject.Parse(File.ReadAllText(#"..\..\test_files\TestData.json"));
foreach (var d in json["locations"])
{
using (var jsonReader = new JsonReader(d.ToString()))
{
var context = BsonDeserializationContext.CreateRoot(jsonReader);
var document = collection.DocumentSerializer.Deserialize(context);
locations.Add(document);
}
}
collection.InsertManyAsync(locations);
}
If I made async and await then it runs lately, I need to run this first and then only test the data.
For future reference, wait() at end of async method work like synchronously
internal static void InitializeDb()
{
var db = GetConnection();
var collection = db.GetCollection<BsonDocument>("locations");
var locations = new List<BsonDocument>();
var json = JObject.Parse(File.ReadAllText(#"..\..\test_files\TestData.json"));
foreach (var d in json["locations"])
{
using (var jsonReader = new JsonReader(d.ToString()))
{
var context = BsonDeserializationContext.CreateRoot(jsonReader);
var document = collection.DocumentSerializer.Deserialize(context);
locations.Add(document);
}
}
collection.InsertManyAsync(locations).wait();
}