I want to use the json data that I receive from mongodb on to my flutter client.
The format of my mongodb document is:
{
"_id":"2020-10-10 18:35:19.465085",
"classhours":"56",
"sleephours":"56",
"studyhours":"56",
"activity":"9.0"
}
I am able to fetch data like this:
db = await mongo.Db.create(
"mongodb+srv://id:pass#cluster0.qkmvt.mongodb.net/students?retryWrites=true&w=majority");
await db.open();
print('DB Connected');
coll = db.collection(widget.uid);
print(coll);
var response = await coll.find();
print(response);
I am able to print all the documents in the console using this. How to use the response in the client ui like for text.Can someone help me with it?
You can use FutureBuilder widget to set Text widget with value that you receive from asynchronous calls.
For more info refer: https://flutter.dev/docs/cookbook/networking/fetch-data
You can convert the JSON response to a Map. Here's an example
import 'dart:convert';
void main() {
var db="{\"_id\":\"2020-10-10 18:35:19.465085\",\r\n\"classhours\":\"56\", \r\n \"sleephours\":\"56\",\r\n\"studyhours\":\"56\",\r\n\"activity\":\"9.0\"\r\n}";
Map<String, dynamic> db_map=jsonDecode(db);
print(db_map['_id']);
}
Or you can make a Plain Old Dart Object of the response using Quicktype. Here is what you would get
// To parse this JSON data, do
//
// final dbModel = dbModelFromJson(jsonString);
import 'dart:convert';
DbModel dbModelFromJson(String str) => DbModel.fromJson(json.decode(str));
String dbModelToJson(DbModel data) => json.encode(data.toJson());
class DbModel {
DbModel({
this.id,
this.classhours,
this.sleephours,
this.studyhours,
this.activity,
});
DateTime id;
String classhours;
String sleephours;
String studyhours;
String activity;
factory DbModel.fromJson(Map<String, dynamic> json) => DbModel(
id: DateTime.parse(json["_id"]),
classhours: json["classhours"],
sleephours: json["sleephours"],
studyhours: json["studyhours"],
activity: json["activity"],
);
Map<String, dynamic> toJson() => {
"_id": id.toIso8601String(),
"classhours": classhours,
"sleephours": sleephours,
"studyhours": studyhours,
"activity": activity,
};
}
After you receive your response, just use
DbModel model=DbModel.fromJson(json.decode(db));
print(model._id); // Access whatever variables you want
EDIT 1: In my example, I have hardcoded the response as a String variable db. This is equivalent to the response variable as mentioned in the question
Related
I'm looking at the docs, but it does not mention file Upload.
The GraphQl Upload service I need to consume is this one.
Would it be possible with GraphQlClient?
I believe it is possible indeed.
You should build your GraphQlClient or reuse a previous one. Then, you should write the the document (or refer to an existing one using documentName) specifying the variables required. Finally, you assign that variable to a value, which can be any Object (in your case, a file; in my example, an Integer number 1), using the variable method of the RequestSpec.
graphQlClient
.mutate()
.header("Authorization","Basic XXXXX")
.build()
.document("""
query artistaPorId($unId:ID){
artistaPorId(id:$unId){
apellido
}
}
""")
.variable("unId",1)
.retrieve("artistaPorId")
.toEntity(Artista.class)
.subscribe( // handle onNext, onError, etc
);
My schema.graphqls:
type Query {
artistaPorId(id:ID): Artista
}
type Artista {
id: ID
apellido: String
estilo: String
}
I have figured it out with the help of this answner.
This uses Spring WebClient. I just need to figure it out how to extract data from the response (it's a graphql response).
var variables = new LinkedHashMap<String, Object>();
variables.put("cartao", cartao);
variables.put("mime", MediaType.APPLICATION_PDF_VALUE);
variables.put("file", null);
var query = StreamUtils.copyToString(new ClassPathResource("/graphql-documents/UploadPrescriptionMutation.graphql").getInputStream(),
Charset.defaultCharset());
var params = new LinkedHashMap<String, Object>();
params.put("operationName", "upload");
params.put("query", query);
params.put("variables", variables);
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("operations", objectMapper.writeValueAsString(params));
builder.part("map", "{\"uploaded_file\": [\"variables.file\"]}");
builder.part("uploaded_file", new FileSystemResource(file));
return webClient.post()
.headers(h -> h.setBearerAuth(token))
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(builder.build()))
.retrieve()
.bodyToMono(Prescription_AddPrescriptionDto.class)
.block();
GraphQL file:
mutation upload($file: Prescription_Upload!, $cartao: String!, $mime: String!) {
Prescription_uploadPrescription(
file: $file uploadInfo: {
cardNumber: $cartao
source: UNKNOWN
mime: $mime })
{
id
uploadedAt
deletedAt
expiresAt
source
file
name
cardNumber
identity
status
storage
originalName
extension
}
}
I´m getting an empty object for the admin.firestore.FieldValue.serverTimestamp(), below is the screenshot of the document being stored in Firestore:
Here´s the code for creating the message object (that corresponds to the screenshot above):
import {Message} from "./Message";
import {MessageType} from "./MessageType";
import * as admin from "firebase-admin";
export class TextMessage extends Message {
constructor(objectID: string,
content: string,
authorName: string,
authorID: string,
authorPhotoUrl: string,
createdAt: FirebaseFirestore.FieldValue = admin.firestore.FieldValue.serverTimestamp()) {
super(objectID,
content,
authorName,
authorID,
authorPhotoUrl,
MessageType.text,
createdAt,)
}
}
Here´s where I create the TextMessage object:
const message: TextMessage = new TextMessage(
messageID,
"Cualquier consulta escríbeme un mensaje y estaré para ayudarte",
SUPPORT_NAME,
SUPPORT_USER_ID,
defaultProfilePicture
)
And here´s the Firebase function code in which the code from above is being used:
// Create the chat
const createChatPromise =
firestoreDB
.collection("Chats")
.doc(chatID)
.collection("Messages")
.add(JSON.parse(JSON.stringify(message)))
// Return the method when both functions are finished
return Promise.all(
[
addToFirestorePromise,
addToAlgoliaPromise,
emailPromise,
createCurrentUserInboxPromise,
createSupportInboxPromise,
createChatPromise, ==> This is the promise from above
addUsersIDsPromise
]
).catch(error => functions.logger.log("The error is: " + error.message))
From the object´s documentation:
Returns a sentinel used with set(), create() or update() to include a server-generated timestamp in the written data.
Returns:
The FieldValue sentinel for use in a call to set(), create() or update().
However, I´m using the add function, I don´t know if this is the reason why is not working.
NOTE: I´m using the following versions for firebase admin and functions:
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.7.0",
It's not clear to me why you are using both stringify and parse together like this:
JSON.parse(JSON.stringify(message))
The stringify will destroy the token that internally represents the server timestamp. You're supposed to pass the object to store in Firestore directly to add() or set() - never stringify it.
I am building a tool to use for work. Basically I upload a csv to extract details which will act as parameters in an axios get request.
I am using multiple urls in axios.all, and my problem is I cannot match up the reponse data to each object of that specific url. The details are below with code snippets. I hope I've made it clear enough below, but this has to do with mass requesting many urls at once, and receiving response data. The problem lies in matching up that response data to its correct url from which it was called.
Here we go...to start, I am mapping an array of vehicle data I am uploading from an external csv file. 'resultsArray' is my array and it holds the year, make, model, trim, price, a url to locate the original posting, and location of the vehicle.
let vehicle_specs = resultsArray.map(function(d, index) {
let values = {
year: d['Title_name'].split(' ')[0], // Iterate with bracket notation
make: d['Title_name'].split(' ')[1],
model: d['Title_name'].split(' ')[2],
trim: d['Title_name'].split(' ')[3],
price: d['Title_Price'],
cl_url: d['Title_Price_url'],
cl_location: d['Title_Location'],
}
return values;
});
I use the new keyword to create an object of the vehicle.
let Vehicle = function(year, make, model, trim, price, url, cl_url, cl_location) {
this.year = year;
this.make = make;
this.model = model;
this.trim = trim;
this.price = price;
this.url = url;
this.cl_url = cl_url;
this.cl_location = cl_location;
}
I then build the object with a new instance of Vehicle and return each vehicle as I need it to be.
let vehicle_data = vehicle_specs.map(function(s) {
let url = `http://api.marketcheck.com/v2/stats/car?api_key={}&ymm=${s.year}|${s.make}|${s.model}`;
let new_vehicle = new Vehicle(`${s.year}`, `${s.make}`, `${s.model}`, `${s.trim}`, `${s.price}`, `${url}`, `${s.cl_url}`, `${s.cl_location}`);
return new_vehicle;
});
I extract the URL's in the following code snippet and use axios.all to request data from each one.
let urls = vehicle_data.map(function(m) {
return m.url;
})
let options = {
'method': 'GET',
'headers': {
'Host': 'marketcheck-prod.apigee.net'
}
};
axios.all(urls.map(url => {
request(url, options, function (error, response, body) {
if(error) {
console.log(error);
} else {
console.log(response);
}
});
}))
My Problem:
I am using a 3rd Party API (Marcketcheck) - Holds data on vehicles.
The response data comes back (See below as an example. This is data for just 1 url)
{"price_stats":{"geometric_mean":3413,"min":899,"median":3595,"population_standard_deviation":1323,"variance":1750285,"ax":7995,"mean":3655,"trimmed_mean":3572,"standard_deviation":1323,"iqr":1800},"miles_stats":{"geometric_mean":97901,"min":2,"median":125000,"population_standard_deviation":51713,"variance":2147483647,"max":230456,"mean":125182,"trimmed_mean":125879,"standard_deviation":51713,"iqr":74734},"dom_stats":{"geometric_mean":100,"min":1,"median":100,"population_standard_deviation":399,"variance":159152,"max":2513,"mean":247,"trimmed_mean":162,"standard_deviation":399,"iqr":217},"count":101}
I cannot figure out how to match up each response data to the vehicle object of that specific url.
For example, if I request 3 urls from the vehicle object. Let's name them:
Url-1
Url-2
Url-3
I get my response data back as objects:
OBJ-1
OBJ-2
OBJ-3
I have no way as far as I know with my level of knowledge, how to assign each object back to it's specific URL and THEN, match up that OBJ data with it's specific vehicle.
I haven been beating my head against a wall for about 4 days, I cannot figure this out.
Any suggestions are welcome and I really appreciate anybody looking at this post to help out.
Check this out
let requests = urls.map((url) => {
return axios.get(url, {
headers: {
'Host': 'marketcheck-prod.apigee.net'
}
});
});
Promise.all(requests).then((responces) => {
console.log(responces);
}).catch((err) => {
console.log(err)
});
There is a problem with my work. since Firebase's Web/JavaScript API always returns the full tree under the nodes that we request.
So in my case i retrieved all of existing fields from firebase including sensitive fields first and after that I want to export to excel selected fields only, not all of the fields that i got. the problem is, I always succeed exported all existing fields, including the sensitive fields.
Can I export selected field only and exclude the sensitive field? Below is my code:
I retrieve all of my fields include the data from firebase in my .ts file like this:
getData() {
this.dataLoading = true;
this.querySubscription = this._backendService.getDocs('report')
.subscribe(members => {
this.members = members;
this.dataSource = new MatTableDataSource(members);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
},
(error) => {
this.error = true;
this.errorMessage = error.message;
this.dataLoading = false;
},
() => { this.error = false; this.dataLoading = false; });
}
//export func
exportAsXLSX():void{
this._backendService.exportAsExcelFile(this.members, 'sample');
}
My Backend service Code :
getDocs(coll:string,filters?:any){
this.itemsCollection=this.afs.collection<any>(this.getCollectionURL(coll));
return this.itemsCollection.valueChanges();
}
getCollectionURL(filter){
return "ReportApp/fajar/"+filter;
}
//export func
public exportAsExcelFile(json: any[], excelFileName: string): void {
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(json);
const workbook: XLSX.WorkBook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] };
const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
this.saveAsExcelFile(excelBuffer, excelFileName);
}
private saveAsExcelFile(buffer: any, fileName: string): void {
const data: Blob = new Blob([buffer], {type: EXCEL_TYPE});
FileSaver.saveAs(data, fileName + '_export_' + new Date().getTime() + EXCEL_EXTENSION);
}
as for reference im using code from here to exporting to excel :https://medium.com/#madhavmahesh/exporting-an-excel-file-in-angular-927756ac9857
as u can see I put all of my data into this.member variable and export em, But the result is that I exported all of em, i want to export selected fields only.
You will need to "trim down" the array of member data before you send it to your exportAsExcelFile() method. Your problem is that you are passing ALL of the member data to that export function. So the solution is to remove any sensitive information before you call the export function.
exportAsXLSX():void {
// TRIM DOWN ARRAY HERE
this._backendService.exportAsExcelFile(this.members, 'sample');
}
Since you didn't provide your member database structure, or details of what you consider sensitive information, I'll provide a generic example. You have an array of members... Most likely, you've made each "member" in the array into an object... so we need to loop over that array and delete the "sensitive" property of each member object.
As a precaution, since we don't want to delete the properties from the ACTUAL array, since arrays are reference-types, and since you might need those details elsewhere... let's make a copy of the array - a deep copy to ensure even nested objects are copied.
var newMemberArray = JSON.parse(JSON.stringify(this.members))
Then, we need to loop over that new array and delete our sensitive properties:
newMemberArray.forEach(function(m){
delete m.sensitivePropertyName1;
delete m.sensitivePropertyName2;
});
and pass that "sanitized" array to your export function... so putting all this together, something like:
exportAsXLSX():void {
var newMemberArray = JSON.parse(JSON.stringify(this.members))
newMemberArray.forEach(function(m){ delete m.sensitivePropertyName });
this._backendService.exportAsExcelFile(newMemberArray, 'sample');
}
*Disclaimer: untested code, for explanation purposes only
I know this is a general question but I have exhausted google and tried many approaches.Any feedback is appreciated.
The HTTPClient is Angular 5+ so it returns an object created from the response JSON data. I get a massive JSON response from an endpoint I have no control over and I want to use about 20% of the response in my app and ignore the rest.
I am really trying hard to avoid using a series of templates or export objects or whatever and trying to force this massive untyped Observable into a typed object with hundreds of fields many being Arrays. All I need for the app is just a Array of very small objects with 3 fields per object. The 3 fields are all over within the JSON response and I want to map them to my object .map only seems to work when you are using the full response object and I can't find an example where .map does custom work besides in the case where you are mapping a few fields to 1 object and I am trying to map to an Array of my small objects.
UPDATED
Basically I want this service to return an object of Type DislayData to the module that subscribes to it but I get just an Object back. This is not what I ultimately need to do but if I can prove I can map the body of the response to my needed return type I can then start to break down the response body and return an Array of the Type I really need based on my silly DisplayData object. Thanks again!
export interface DislayData {
body: any;
}
...
export class DataService {
constructor(private http: HttpClient) { }
/** GET data from the black box */
getData(): Observable<DislayData> {
return this.http.get<HttpResponse<any>>(searchUrl, { observe: 'response' })
.pipe(
map(res => {
return res.body as DislayData;
}
tap(res => console.log(//do stuff with entire respoonse also)),
catchError(err => this.handleError(err)));
}
private handleError(error: HttpErrorResponse) {
...
Do you know the structure of the answering object?
If yes, you can do something like this:
item$ = new BehaviorSubject<any>({});
item = {
foo: 'a',
bar: 'b',
iton: [1, 2, 3],
boo: {
far: 'c'
}
};
logNewItem() {
this.item$
.pipe(
map(response => {
if (response.foo
&& response.iton
&& response.iton.length >= 3
&& response.boo
&& response.boo.far) {
let newItem = {
foo: response.foo,
iton2: response.iton[2],
far: response.boo.far
};
console.log(newItem); // output: Object { foo: "a", iton2: 3, far: "c" }
}
})
)
.subscribe();
this.item$.next(this.item);
}
Basically, you can simply make sure the properties exist, call them directly and map them to a better fitting object.
I heavily recommend creating an interface for the object you're receiving and an interface or class for the object you're mapping to. In that case you can also write the code more compact like this:
[...]
map(response: MyAPIResponse => {
let newItem = new NewItem(response);
console.log(newItem); // output: Object { foo: "a", iton2: 3, far: "c" }
}
})
[...]
class NewItem {
foo: string;
iton2: string;
far: string;
constructor(apiResponse: MyAPIResponse) {
//Validate parameter first
this.foo = apiResponse.foo;
this.iton2 = apiResponse.iton[2];
this.far = apiResponse.boo.far;
and make your code a lot more readable.