How can I get firebase data as Querysnapshot? - arrays

Im trying to get Array from firebase as a Querysnaoshot from flutter but how can I do that ?
This is the code
class Videos {
final String allhashtagsofeveryvideo;
final String categorie;
final String commentcount;
final String hashtag1;
final String hashtag2;
final String hashtag3;
final String likes;
final String previewimage;
final String profilepic;
final String sharecount;
final String uid;
final String username;
final String videourl;
Videos( {this.allhashtagsofeveryvideo,this.commentcount, this.hashtag1, this.hashtag2, this.hashtag3, this.likes, this.previewimage, this.profilepic, this.sharecount, this.uid, this.videourl, this.categorie, this.username});
}
Videos videosfromsnapshot(DocumentSnapshot snapshot) {
return Videos(
categorie: snapshot.data()['categorie'],
commentcount: snapshot.data()['commentcount'].toString(),
hashtag1: snapshot.data()['hashtag1'],
hashtag2: snapshot.data()['hashtag2'],
hashtag3: snapshot.data()['hashtag3'],
likes:snapshot.data()['likes'].length.toString(),
previewimage: snapshot.data()['previewimage'],
profilepic: snapshot.data()['profilepic'],
sharecount: snapshot.data()['sharecount'].toString(),
uid: snapshot.data()['uid'],
allhashtagsofeveryvideo:snapshot.data()['Hashtagsforallvideos'],
username: snapshot.data()['username'],
videourl: snapshot.data()['videourl'],
);
}
var firestore = FirebaseFirestore.instance;
List<QueryDocumentSnapshot> _allResults = [];
QuerySnapshot snapshots = await firestore.collection('videos').get();
for (var doc in snapshots.docs) {
_allResults.addAll(doc.data()["Hashtagsforallvideos"]);
Maybe I should map over it or something like that ?
So instead of adding it like you seeing I wanna use like that
QuerySnapshot snapshots = await firestore.collection('videos').get();
for (var doc in snapshots.docs) {
....
_allResults= qn.docs
But how can I do this maybe anyone can help
No im getting this error
[VERBOSE-2:ui_dart_state.cc(186)] Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'QueryDocumentSnapshot'
#0 _OpenallsinglehashtagsState.getusers
package:wichtigdenyady/homesearchingall/openalldocs.dart:90
<asynchronous suspension>
And the line is this one
_allResults.addAll(doc.data()["Hashtagsforallvideos"]);
Probably something like that
var firestore = FirebaseFirestore.instance;
QuerySnapshot qn = await firestore.collection('videos').get();
if (!mounted) return;
setState(() {
_allResults = qn.docs;
});

It's a little bit hard withot the data but I hope this can help you:
Future<List<QueryDocumentSnapshot>> getVideos() async {
List<String> allVideoHastags = [];
List<QueryDocumentSnapshot> _allResults = [];
QuerySnapshot snapshots = await _firestore.collection('videos').get();
for (QueryDocumentSnapshot videoSnapshot in snapshots.docs) {
List<String> videoHastags =
List.from(videoSnapshot.data()['Hashtagsforallvideos']);
allVideoHastags.addAll(videoHastags);
_allResults.add(videoSnapshot);
}
return _allResults;
}
In most cases we miss the List.from constructor when we work with Firestore arrays and need them in a List.

Related

How to update data in local json file in flutter

I'm the junior flutter developer, and I would like to seek your support.
Currently, I would need to update data in a local JSON file in Flutter as below.
{"title":"ករណី ពិនិត្យផ្ទៃពោះ",
"lists":[
{
"id":"127",
"faci_code":"20018",
"y_txt":"2022",
"m_txt":"1",
"ind_id":"1",
"qty":"100",
"rec_by":"od123456",
"rec_date":"2022-06-27 13:50:31",
"lock_txt":"0",
"sec_id":"1",
"ind_num":"1",
"ind_eng":"# of ANC 1",
"ind_kh":"ចំនួនស្រ្ដីបានពិនិត្យផ្ទៃពោះលើកទី១ទាំងអស់",
"HFAC_NAME":"Boeng Pram",
"HFAC_NAMEKh":"បឺងប្រាំ",
"OD_CODE":"201",
"OD_NAME":"Thma Koul",
"OD_NAME_KH":"ថ្មគោល",
"PRO_CODE":"2",
"PROVINCE":"Battambang",
"PROVINCE_KH":"បាត់ដំបង"
}]}
I have searched and tried multiple solutions, but I couldn't resolve this issue yet. 
I hope someone can provide a solution in advance.
Regard, thanks.
You can't right files in project folders.
Try local storage.
I used path_provider package in this example for get application directory path to write json file on local storage.
1. Create data class
Note. this data class should match your stored json structure
class DataClass {
String name;
int age;
DataClass(this.name, this.age);
factory DataClass.fromJson(Map<String, dynamic> json) {
return DataClass(json['name'], json['age']);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'age': age,
};
}
}
2.create and update json file
DataClass? updateJson;
void createJson() async {
String data = await rootBundle.loadString('assets/data.json');
Directory appDocDir = await getApplicationDocumentsDirectory();
File jsonFile = File("${appDocDir.path}/data.json");
jsonFile.writeAsStringSync(data);
updateJson = DataClass.fromJson(jsonDecode(data));
setState(() {});
}
void updateJsonFile() async {
Directory appDocDir = await getApplicationDocumentsDirectory();
File jsonFile = File("${appDocDir.path}/data.json");
//update
final jsonAsString = jsonFile.readAsStringSync();
updateJson = DataClass.fromJson(jsonDecode(jsonAsString));
updateJson?.name = "updated name";
updateJson?.age = _counter;
jsonFile.writeAsStringSync(jsonEncode(updateJson?.toJson()));
setState(() {});
}

SqfLite No such table (code 1 SQLITE_ERROR)

Maybe this question was already answered but I try to add sqfLite to my project but I get this error:
In my debug console:
no such table: infotable in "SELECT * FROM infotable"
This is my code:
final String infoTable = 'infotable';
final String columnID = '_id';
final String columnName = 'name';
final String columnCivilStatus = 'civil';
final String columnWorking = 'working';
final String columnJobTitle = 'job';
final String columnWorkingDomain = 'workingdomain';
final String columnMonthlyIncome = 'monthlyincome';
class SqfLite {
int id;
int sliderValue;
int monthChoiceChip;
String reasonChoiceChip;
String name;
String civilStatus;
int working;
String jobTitle;
int workingDomain;
String monthlyIncome;
String currency;
Position latitude;
Position longitude;
Map<String, dynamic> toMap() {
var map = <String, dynamic>{
columnCivilStatus: civilStatus,
columnJobTitle: jobTitle,
columnMonthlyIncome: monthlyIncome,
columnWorkingDomain: workingDomain,
columnWorking: working,
columnName: name,
};
if (id != null) {
map[columnID] = id;
}
return map;
}
SqfLite();
SqfLite.fromMap(Map<String, dynamic> map) {
id = map[columnID];
name = map[columnName];
civilStatus = map[columnCivilStatus];
working = map[columnWorking];
jobTitle = map[columnJobTitle];
workingDomain = map[columnWorkingDomain];
monthlyIncome = map[columnMonthlyIncome];
}
}
class SqfLiteProvider {
Database db;
Future open(String path) async {
db = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute('''
create table $infoTable (
$columnID integer primary key autoincrement,
$columnName text not null,
$columnCivilStatus text not null,
$columnWorking integer not null,
$columnJobTitle text not null,
$columnWorkingDomain integer not null,
$columnMonthlyIncome text not null)
''');
});
}
Future<SqfLite> getSqfLite(int id) async {
List<Map> maps = await db.query(infoTable,
columns: [
columnID,
columnName,
columnCivilStatus,
columnWorking,
columnJobTitle,
columnWorkingDomain,
columnMonthlyIncome,
],
where: '$columnID = ?',
whereArgs: [id]);
if (maps.length > 0) {
return SqfLite.fromMap(maps.first);
}
return null;
}
Future close() async => db.close();
}
I get the error here:
Future<void> openDataBase() async {
db = await openDatabase('infotable.db');
records = await db.query('infotable');
mapRead = records.first;
....
}
I've followed the example from the official page of the plugin
I can't use the latest version because of some pubspec.yaml conflicts.
I've tried to flutter clean and reinstalling the app but it didn't work
You have defined the open method inside SqfLiteProvider, but you are not using it. Instead, you are calling the same openDatabase('infotable.db'); method from sqflite package where the onCreate callback is not defined - you get an error.
So, instead of calling db = await openDatabase('infotable.db'); directly, use the SqfLiteProvider.open() you have defined.

How to save nested list with sqflite in flutter?

Here I want to add bookmark functionality in my flutter news application. I get data from APIs. I display that data below.
This Image shows you how I get data from APIs
I am using this snippet for saving data with SQflite which I display below. I save this file with name bookmark_db_provider.dart.
import 'dart:io';
import 'home_screen_data.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class DBProvider {
static Database _database;
static final DBProvider db = DBProvider._();
DBProvider._();
Future<Database> get database async {
if (_database != null) _database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, 'ProductData.db');
return await openDatabase(path, version: 1, onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE ProductData('
'id INTEGER PRIMARY KEY,' //id
'categoryName Text,' //headline
'publisherName Text,' //description
'isAvailable Text,' //content
'categoryImgUrl Text' //image
')');
});
}
createProductData(ProductData productData) async {
await deleteAllProductData();
final db = await database;
final res = await db.insert('ProductData', productData.toJson());
return res;
}
Future<int> deleteAllProductData() async {
final db = await database;
final res = await db.delete('DELETE FROM ProductData');
return res;
}
Future<List<ProductData>> getProductDataList() async {
final db = await database;
final res = await db.rawQuery("SELECT * FROM ProductData");
List<ProductData> list = res.isNotEmpty ? res.map((x) => ProductData.fromJson(x)).toList() : [];
return list;
}
}
So, I want to how to save data and get data this with SQflite database in flutter. How I accomplish this?
This is an old question and hopes you have gotten an answer to it. However, a lot of flutter dev using sqflite struggles with handling data in a nested array format of the type mentioned e.g
``` {
"id": 1,
"name": "xyz",
"images": [
{
"imageId": 1,
"image": "image1"
},
{
"imageId": 2,
"image": "image2"
}
]
}
```
Since json handling is not part of sqflite at the moment, it is suggested to either;
a., save inner array as a string/text field in the 'image' column of table 'data' like
**
"[{"imageId": 1, "image": 'image1'}, {"imageId": 2, "image":
'image2'},}"
** , no guaranty.
or, b., flatten out the inner array so as to have only **
data[id, name, image1, image2, image3,...].
** this approach may be possible in a simple array as given but in a complex system. flattening out may be really cumbersome.
my suggestion, create two tables, one for data, and another for images. let each row of images table have reference or relationship with corresponding data table row. Your data class and images class will be something like,
```
class Data {
int dataId;
String name;
List<Image> images;
data({this.id, this.images, this.name});
...
```
and
```
class Image {
int imageId;
int dataId;
String image;
Image({this.imageId, this.dataId, this.image});
...
}
```
Your sqflite table data will have only two fields 'dataId' and 'name' and the image table must include 'dataId' as the relationship between the two tables.
to save data, you can use transactions like
```
void saveData(Data data, Map<String, Object> map) async {
await db.execute(""" INSERT INTO "data" (name) values (?) """, [data.name]);
// retrieve dataId of the new row inserted. last_inserted_rowid can also be used if the database does not contain several tables that may have been updated or saved before completing the transaction.
int dataId;
List<Map> x = await db.query('data', columns: ['dataId'], where: 'name = ?', whereArgs: [data.name]);
dataId = x[x.length - 1]['dataId'];
db.transaction((txn) async {
var batch = txn.batch();
data.images
.map((e) => {
batch.rawInsert(
""" INSERT INTO "images" (dataId,image,) values (?,?,?,? ) """, [dataId, e.image])
}).toList();
});
}
```
to retrieve data and images, you can try something like
```
Data _data = new Data();
Future<void> fetchData() async {
if (db != null) {
// do not execute if db is not instantiate
//retrieve all data from data table and store in instantiated, also instantiate images array as empty list
final dataList = await db.query(data);
_data = (dataList as List)
.map(
(data) => Data(
dataId: data['dataId'],
name: data['name'],
images: data['images'] != null ? data['images'] : []
)) .toList();
_data.forEach((data) async {if (data.images != null) {
List<Image> _images = [];
var imageResults = await db.query(images,where: 'dataId =?', whereArgs: [data.dataId]);
_images = (imageResults as List).map((e) => Image(
imageId: e['imageId'],
dataId: e['dataId'],
image: e['image']
)).toList();
_data.images.addAll(_images);
} });
}
}
```
with that approach, you should be able to handle nested array in flutter and sqflite
I might be unclear with your question, but according to what I understood,
You need to call the method of this provider with data that you want:
DBProvider.init() // Use this only one which when the application is instaled
After that, you can call these methods from anywhere to put and get data
DBProvider.createProductData(productData) //insert data
Get data
DBProvider.getProductDataList() //get data

TokenCache: No matching token was found in the cache, Azure AD Api

I'd like to use Azure AD Api and I couldn't acquire token some reason. I have two methods, and I got this after calling:
TokenCache: No matching token was found in the cache iisexpress.exe Information: 0
Here's my code:
public string GetToken()
{
string authority = "https://login.microsoftonline.com/{tenantId}/";
string clientId = "";
string secret = "";
string resource = "https://graph.windows.net/";
var credential = new ClientCredential(clientId, secret);
AuthenticationContext authContext = new AuthenticationContext(authority);
//I think the problem is here:
var token = authContext.AcquireTokenAsync(resource, credential).Result.AccessToken;
return token;
}
public string MakeRequest()
{
string accessToken = GetToken();
var tenantId = "";
string graphResourceId = "https://graph.windows.net/";
Uri servicePointUri = new Uri(graphResourceId);
Uri serviceRoot = new Uri(servicePointUri, tenantId);
ActiveDirectoryClient client = new ActiveDirectoryClient(serviceRoot, async () => await Task.FromResult(accessToken));
foreach (var user in client.Users.ExecuteAsync().Result.CurrentPage)
Console.WriteLine(user.DisplayName);
var client1 = new HttpClient();
var uri = "https://graph.windows.net/" + tenantId + "/users?api-version=1.6";
client1.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
var response = client1.GetAsync(uri).Result;
var result = response.Content.ReadAsStringAsync().Result;
return result;
}
I don't know what's the problem, and I didn't find any great hint, under other questions and a little explanation would be helpful. I'd like to understand this part, of course.
//When you are calling
Main() { Method_A() }
aync Method_A() { await Method_B() }
Task < T > Method_B() { return T; }
//It will through the error. //Need to keep Mehtod_B in another Task and run.
// Here I am avoiding few asyncs
Main() { Method_A() }
Method_A() { Method_B().Wait() }
Task Method_B() { return T; }
There is no output using the Console.WriteLine in a IIS progress. If you want to output the result in a output window for the web project, you can use System.Diagnostics.Debug.WriteLine() method.

Web API 2, return string as a file

I have a Web API 2 POST endpoint which takes a parameter, queries the database and returns an xml string as the response.
public async Task<IHttpActionResult> Post(long groupId)
{
People people = await _someService.GetPeople(groupId);
XElement peopleXml = _xmlService.ConverToXml(people);
return Ok(peopleXml);
}
How do I to return the xml as a file instead?
Figured it out myself, but I hope there is a simpler way -
public async Task<IHttpActionResult> Post(long groupId)
{
People people = await _someService.GetPeople(groupId);
XElement peopleXml = _xmlService.ConverToXml(people);
byte[] toBytes = Encoding.Unicode.GetBytes(peopleXml.ToString());
var stream = new MemoryStream(toBytes);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(stream)
};
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = "test.txt"
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
var response = ResponseMessage(result);
return response;
}

Resources