how to create a list <> in flutter from Firestore? - list

I am new to flutter.
How can I retrieve data from Firestore and form a new profile with every child in my collection? Second question is how can I use this list in another dart file? thank you
Thank you.
final List<Profile> demoProfiles = [
Profile (
photos: [
"https://",
],
name: "abc",
),
Profile (
photos: [
"https://",
],
name: "abc",
)
];

Assuming you have a firestore strucuture like this:
Profile
photos: []
name: ""
age: ""
distance: ""
education: ""
You can fetch data and build it into your object with this code snippet:
fetchData() async{
final db = await Firestore.instance;
List<Profile> demoProfiles = []
db.collection("Profile").get().then(function(snapshot){
snapshot.forEach((document) {
demoProfiles.add(Profile(
photos: document.data.photos,
name: document.data.name,
age: document.data.age,
distance: document.data.distance,
education: document.data.education
))
})
})
}
Edit:
1) Remove the mockedup list of profiles from your profiles class, it should not be there
2) Edit your mainController to the following:
class _MainControllerState extends State<MainController> {
List<Profile> demoProfiles = [];
demoProfiles = fetchData();
Final MatchEngine match Engine = MatchEngine (
matches:demoProfiles.map((Profile profile) => Match(profile: profile)).toList();
);
fetchData() async{
final db = await Firestore.instance;
List<Profile> list = [];
db.collection("Profile").get().then(function(snapshot){
snapshot.forEach((document) {
list.add(Profile(
photos: document.data.photos,
name: document.data.name,
age: document.data.age,
distance: document.data.distance,
education: document.data.education
))
})
});
return list;
}
}

Related

How to count category value of array of List

let's say I have a list like the example below
<Categories>myList = [
Categories(
nameCategory: 'Book',
amount: '20'
),
Categories(
nameCategory: 'Book',
amount: '40'
),
Categories(
nameCategory: 'Food',
amount: '20'
),
Categories(
nameCategory: 'Food',
amount: '15'
),
];
How I can combine the duplicate values of that list and count the value of the list based on name ??
I can combine the list and the count value of the list but that only works just in a general list like sum total
what I want to do is make a new List but only combine several parts that share the same property like the same category or same class like that
this is an example what I want to achieve
<Categories> anotherList= [
Categories(
nameCategory: 'Book',
amount: '60'
),
Categories(
nameCategory: 'Food',
amount: '35'
),
];
I would replace your List<Categories> with a Map<String, Categories>. Then you can easily look up the Categories object given its name and mutate the existing Categories object. For example, something like:
var mergedCategories = <String, Categories>{};
for (var categories in myList) {
var name = categories.nameCategory;
var amount = categories.amount;
(mergedCategories[name] ??= Categories(nameCategory: name, amount: 0))
.amount += amount;
}
You're essentially trying to get an aggregate value from a list, which is what List.fold is meant to help with.
Here's an example of how you might use it:
class Category {
final String name;
int amount;
Category({required this.name, required this.amount});
String toString() => "Category(name: $name, amount: $amount)";
}
void main() {
final categories = [
Category(
name: 'Book',
amount: 20
),
Category(
name: 'Book',
amount: 40
),
Category(
name: 'Food',
amount: 20
),
Category(
name: 'Food',
amount: 15
),
];
/**
* Here is where the aggregation is done
*/
final List<Category> aggregated = categories.fold([], (list, item) {
try {
// Check whether the category is already in the aggregate
final existingCategory = list.firstWhere((c) => c.name == item.name);
// Category is already in the list, so just add the amount of the current item.
existingCategory.amount += item.amount;
return list;
} catch (_) {
// The category has not yet been added - so add it here
list.add(item);
return list;
}
});
print(aggregated);
}
I've changed your category class a bit for simplicity, but the principle should be the same. You can read more about the fold function here: https://api.dart.dev/stable/2.13.4/dart-core/Iterable/fold.html
A pretty straightforward method is by using the groupBy function provided by the collection.dart package.
import 'package:collection/collection.dart';
groupBy<Categories, String>(list, (c) => c.nameCategory).values.map(
(list) => list.reduce(
(a, b) => new Categories(a.nameCategory, a.amount + b.amount)
)
);

AWS RDS Data API executeStatement not return column names

I'm playing with the New Data API for Amazon Aurora Serverless
Is it possible to get the table column names in the response?
If for example I run the following query in a user table with the columns id, first_name, last_name, email, phone:
const sqlStatement = `
SELECT *
FROM user
WHERE id = :id
`;
const params = {
secretArn: <mySecretArn>,
resourceArn: <myResourceArn>,
database: <myDatabase>,
sql: sqlStatement,
parameters: [
{
name: "id",
value: {
"stringValue": 1
}
}
]
};
let res = await this.RDS.executeStatement(params)
console.log(res);
I'm getting a response like this one, So I need to guess which column corresponds with each value:
{
"numberOfRecordsUpdated": 0,
"records": [
[
{
"longValue": 1
},
{
"stringValue": "Nicolas"
},
{
"stringValue": "Perez"
},
{
"stringValue": "example#example.com"
},
{
"isNull": true
}
]
]
}
I would like to have a response like this one:
{
id: 1,
first_name: "Nicolas",
last_name: "Perez",
email: "example#example.com",
phone: null
}
update1
I have found an npm module that wrap Aurora Serverless Data API and simplify the development
We decided to take the current approach because we were trying to cut down on the response size and including column information with each record was redundant.
You can explicitly choose to include column metadata in the result. See the parameter: "includeResultMetadata".
https://docs.aws.amazon.com/rdsdataservice/latest/APIReference/API_ExecuteStatement.html#API_ExecuteStatement_RequestSyntax
Agree with the consensus here that there should be an out of the box way to do this from the data service API. Because there is not, here's a JavaScript function that will parse the response.
const parseDataServiceResponse = res => {
let columns = res.columnMetadata.map(c => c.name);
let data = res.records.map(r => {
let obj = {};
r.map((v, i) => {
obj[columns[i]] = Object.values(v)[0]
});
return obj
})
return data
}
I understand the pain but it looks like this is reasonable based on the fact that select statement can join multiple tables and duplicated column names may exist.
Similar to the answer above from #C.Slack but I used a combination of map and reduce to parse response from Aurora Postgres.
// declarative column names in array
const columns = ['a.id', 'u.id', 'u.username', 'g.id', 'g.name'];
// execute sql statement
const params = {
database: AWS_PROVIDER_STAGE,
resourceArn: AWS_DATABASE_CLUSTER,
secretArn: AWS_SECRET_STORE_ARN,
// includeResultMetadata: true,
sql: `
SELECT ${columns.join()} FROM accounts a
FULL OUTER JOIN users u ON u.id = a.user_id
FULL OUTER JOIN groups g ON g.id = a.group_id
WHERE u.username=:username;
`,
parameters: [
{
name: 'username',
value: {
stringValue: 'rick.cha',
},
},
],
};
const rds = new AWS.RDSDataService();
const response = await rds.executeStatement(params).promise();
// parse response into json array
const data = response.records.map((record) => {
return record.reduce((prev, val, index) => {
return { ...prev, [columns[index]]: Object.values(val)[0] };
}, {});
});
Hope this code snippet helps someone.
And here is the response
[
{
'a.id': '8bfc547c-3c42-4203-aa2a-d0ee35996e60',
'u.id': '01129aaf-736a-4e86-93a9-0ab3e08b3d11',
'u.username': 'rick.cha',
'g.id': 'ff6ebd78-a1cf-452c-91e0-ed5d0aaaa624',
'g.name': 'valentree',
},
{
'a.id': '983f2919-1b52-4544-9f58-c3de61925647',
'u.id': '01129aaf-736a-4e86-93a9-0ab3e08b3d11',
'u.username': 'rick.cha',
'g.id': '2f1858b4-1468-447f-ba94-330de76de5d1',
'g.name': 'ensightful',
},
]
Similar to the other answers, but if you are using Python/Boto3:
def parse_data_service_response(res):
columns = [column['name'] for column in res['columnMetadata']]
parsed_records = []
for record in res['records']:
parsed_record = {}
for i, cell in enumerate(record):
key = columns[i]
value = list(cell.values())[0]
parsed_record[key] = value
parsed_records.append(parsed_record)
return parsed_records
I've added to the great answer already provided by C. Slack to deal with AWS handling empty nullable character fields by giving the response { "isNull": true } in the JSON.
Here's my function to handle this by returning an empty string value - this is what I would expect anyway.
const parseRDSdata = (input) => {
let columns = input.columnMetadata.map(c => { return { name: c.name, typeName: c.typeName}; });
let parsedData = input.records.map(row => {
let response = {};
row.map((v, i) => {
//test the typeName in the column metadata, and also the keyName in the values - we need to cater for a return value of { "isNull": true } - pflangan
if ((columns[i].typeName == 'VARCHAR' || columns[i].typeName == 'CHAR') && Object.keys(v)[0] == 'isNull' && Object.values(v)[0] == true)
response[columns[i].name] = '';
else
response[columns[i].name] = Object.values(v)[0];
}
);
return response;
}
);
return parsedData;
}

AWS Lambda and Dynamo db: How to filter the result of scan by multiple parameters?

I am new to AWS and dynamo. I working on my project with React.js front-end and AWS (Gateway API, Lambda, Dynamo) backend.
This is my app location:
https://www.alphaux.com
After I click "Get Hint", I receive server response. If I click on a keywords - these keywords will be added to the list of GET params for the request like:
topic=blah&keywords=blah1,blah2,blah3
Here are the details of my problem:
In my Lambda:
..
const docClient = new AWS.DynamoDB.DocumentClient({region: 'us-west-2'});
exports.handler = async (event) => { ..
from GET I am receiving the following params:
const topicName = event.queryParams.topic="React";
const keywords = event.queryParams.topic.keywords="blah1,blah2,blah3";
..some code here converts keywords string into array:
const keywordsArray = [blah1,blah2,blah3];
In dynamodb they exist in the following way:
[ { "S" : "javascript" }, { "S" : "programming" }, { "S" : "React" } ]
My Primary partition key is: id (Number)
I have tried different ways and approaches, used scan and query - nothing works. I am stuck..
I have tried the following approach:
const listToObjectMappings = () => {
let x = {};
/* keywords hardcoded for now: */
const keywords = ["javascript", "React"];
keywords.map(item => x[':' + item] = item)
return x
}
let mappings = listToObjectMappings()
let joined = Object.keys(mappings).join();
var params2 = {
TableName : "my-little-table",
FilterExpression: 'topic = :topic and #keywords IN (' + joined + ')',
ExpressionAttributeNames: {
'#keywords' : 'keywords'
},
ExpressionAttributeValues:{
":topic" : "React"
}
};
var params = {
TableName: "my-little-table",
FilterExpression: "#topic = :topic",
ExpressionAttributeNames: {
"#topic": "topic"
},
ExpressionAttributeValues: {
":topic": "React"
}
};
let result;
try {
/* scan DB */
result = await docClient.scan(params).promise();
}
catch(ex) {
result = ex;
}
When I use "scan", the result is always empty [] if I am trying to use "keywords".
It works only with bare minimum like:
const params = {
TableName : currentTable,
FilterExpression:'topic = :topic',
ExpressionAttributeValues:{
":topic" : requestedTopic
}
};
..which gives me all records based on requestedTopic.
If I am using "query" it complains that my key name ("id") is too short and has to be at least 3 chars long.
I am stuck and gracefully asking for your help!
Thank you!
If you're trying to match the topic and any one of the keywords then use something like this:
const params = {
TableName: 'mytable',
FilterExpression: '#tp = :tp AND (contains(#kw, :kw1) OR contains(#kw, :kw2))',
ExpressionAttributeNames: {
'#tp': 'topic',
'#kw': 'keywords',
},
ExpressionAttributeValues: {
':tp': 'React',
':kw1': 'react',
':kw2': 'react-router',
},
};
If you're trying to match the topic and all of the keywords then use something like this:
const params = {
TableName: 'mytable',
FilterExpression: '#tp = :tp AND contains(#kw, :kw1) AND contains(#kw, :kw2)',
ExpressionAttributeNames: {
'#tp': 'topic',
'#kw': 'keywords',
},
ExpressionAttributeValues: {
':tp': 'React',
':kw1': 'react',
':kw2': 'react-router',
},
};

How to use if condition in Karate

Suppose I have the following Json response
[
{
id: 1,
name: "John",
password: "JohnsPassword54",
},
{
id: 2,
name: "David",
password: "DavidsPassword24",
}
]
Then how can I extract the array with name David to do further validation?
e.g. I want to say if name == David then save the id
Well done :) Mastering Json-Path is key to get the most out of Karate !
Just for the sake of demo, here is another option, using the get keyword to get the first element out of the array returned, as Json-Path wildcard searches always return an array:
* def response =
"""
[
{
id: 1,
name: "John",
password: "JohnsPassword54"
},
{
id: 2,
name: "David",
password: "DavidsPassword24"
}
]
"""
* def userId = get[0] response $[?(#.name == 'David')].id
* match userId == 2
I found the solution in the Json expression evaluation -
def user = $..[?(#.name == 'David')]
Then I can use the following -
def userId = user[0].id

Search for Substring in several fields with MongoDB and Mongoose

I am so sorry, but after one day researching and trying all different combinations and npm packages, I am still not sure how to deal with the following task.
Setup:
MongoDB 2.6
Node.JS with Mongoose 4
I have a schema like so:
var trackingSchema = mongoose.Schema({
tracking_number: String,
zip_code: String,
courier: String,
user_id: Number,
created: { type: Date, default: Date.now },
international_shipment: { type: Boolean, default: false },
delivery_info: {
recipient: String,
street: String,
city: String
}
});
Now user gives me a search string, a rather an array of strings, which will be substrings of what I want to search:
var search = ['15323', 'julian', 'administ'];
Now I want to find those documents, where any of the fields tracking_number, zip_code, or these fields in delivery_info contain my search elements.
How should I do that? I get that there are indexes, but I probably need a compound index, or maybe a text index? And for search, I then can use RegEx, or the $text $search syntax?
The problem is that I have several strings to look for (my search), and several fields to look in. And due to one of those aspects, every approach failed for me at some point.
Your use case is a good fit for text search.
Define a text index on your schema over the searchable fields:
trackingSchema.index({
tracking_number: 'text',
zip_code: 'text',
'delivery_info.recipient': 'text',
'delivery_info.street': 'text',
'delivery_info.city': 'text'
}, {name: 'search'});
Join your search terms into a single string and execute the search using the $text query operator:
var search = ['15232', 'julian'];
Test.find({$text: {$search: search.join(' ')}}, function(err, docs) {...});
Even though this passes all your search values as a single string, this still performs a logical OR search of the values.
Why just dont try
var trackingSchema = mongoose.Schema({
tracking_number: String,
zip_code: String,
courier: String,
user_id: Number,
created: { type: Date, default: Date.now },
international_shipment: { type: Boolean, default: false },
delivery_info: {
recipient: String,
street: String,
city: String
}
});
var Tracking = mongoose.model('Tracking', trackingSchema );
var search = [ "word1", "word2", ...]
var results = []
for(var i=0; i<search.length; i++){
Tracking.find({$or : [
{ tracking_number : search[i]},
{zip_code: search[i]},
{courier: search[i]},
{delivery_info.recipient: search[i]},
{delivery_info.street: search[i]},
{delivery_info.city: search[i]}]
}).map(function(tracking){
//it will push every unique result to variable results
if(results.indexOf(tracking)<0) results.push(tracking);
});
Okay, I came up with this.
My schema now has an extra field search with an array of all my searchable fields:
var trackingSchema = mongoose.Schema({
...
search: [String]
});
With a pre-save hook, I populate this field:
trackingSchema.pre('save', function(next) {
this.search = [ this.tracking_number ];
var searchIfAvailable = [
this.zip_code,
this.delivery_info.recipient,
this.delivery_info.street,
this.delivery_info.city
];
for (var i = 0; i < searchIfAvailable.length; i++) {
if (!validator.isNull(searchIfAvailable[i])) {
this.search.push(searchIfAvailable[i].toLowerCase());
}
}
next();
});
In the hope of improving performance, I also index that field (also the user_id as I limit search results by that):
trackingSchema.index({ search: 1 });
trackingSchema.index({ user_id: 1 });
Now, when searching I first list all substrings I want to look for in an array:
var andArray = [];
var searchTerms = searchRequest.split(" ");
searchTerms.forEach(function(searchTerm) {
andArray.push({
search: { $regex: searchTerm, $options: 'i'
}
});
});
I use this array in my find() and chain it with an $and:
Tracking.
find({ $and: andArray }).
where('user_id').equals(userId).
limit(pageSize).
skip(pageSize * page).
exec(function(err, docs) {
// hooray!
});
This works.