Flutter: Filter products by categories in the app level? - database

I am currently trying to develop an app in which products are categorically displayed in a separate screen or class with ListView.builder ().
I have to select / favor a category or sub-category so that I can see products in the list view. I see nothin in the screen if i don't select one or more categorys OR subcategorys. I can also favor different categories and in the list view I see the products that match the favorite product. If I have favored a subcategory, I should only see in the list view the products that see in this favored subcategory and not the superordinate categories.
If I prefer a higher category, all products of the subcategories should be shown in the list view.
But I'm worried about the performance. My database will run on Firebase. Is firestore more suitable for this? I also read that relational databases are more suitable for such things. However, I have never worked with it and I want the favorites not only to be saved on the smartphone. I would like the favorites to be called up when the user logs in to the app with another phone.
My question is more of a structural question. Is it better for the performance if there is a Category class in which all higher and lower categories each have a list with the products and which are then merged in the list view (if different categories are selected, of course)?
I mean, if I list all the products in a single list and filter them afterwards in the code (at the app level), it is totally unperforming, right?
Do I have to have a class category and a separate subcategory class? How would you go about it? I have total chaos in my brain
class Product:
import 'package:flutter/material.dart';
class Product {
final String id;
final String title;
final List<String> imagesPath;
final String description;
final Color categoryColor;
Product({
#required this.id,
#required this.title,
#required this.imagesPath,
#required this.description,
#required this.categoryColor,
});
}
class Category:
import 'package:flutter/material.dart';
import '../models/Product.dart';
class Category {
final String title;
final Color color;
bool isFavourite;
final List<Product> products;
Category({#required this.title, #required this.color, this.isFavourite = false, this.products});
}
List<Category> categories = [
Category(
title: 'Automobile',
color: Colors.lightBlue,
isFavourite: false,
),
];
I no longer know which would be more correct in terms of how I should go on.
Thanks :)

I suggest using Cloud Firestore as it provides query functionalities that Firebase Realtime Database does not.
You can check this similar answer I've posted here where I've demonstrated querying Firestore data and filtering displayed data based from the selected item.

Related

Use two completely different classes as one

I have very stupid question about design patterns: let's say we have two classes Post and Product, for each of them we have different table in the DB, and they have nothing in common with each other, so we can't create base class for them. Some Posts even contains Products. And here's what we should do with them:
Somehow store Post and Product instances in the DB, pack them in one array(using C++, if it matters) when user requests news feed from the next item, send it to the client, and receive and unpack on the client side(using Java).
Next, we have to show both Post and Product in the one list(such as news feed on the Facebook).
Also, we can share Post or Product with our friends using chat. So we can send Post or Product as an attachment of the message(consequently, we should to store id of sent Post or Product in the column attached_item of the messages table in the DB on the server side).
So, what design pattern would be best here? How should I implement the Post and Product classes?
It is a very broad question, but here is a skeleton of what you could you, just to give you some ideas:
// An interface containing methods specific to objects you can list
interface Listable {}
// An interface containing methods specific to objects you can share
interface Shareable {}
// An interface containing methods specific to objects you can send
interface Sendable {}
class Post implements Listable, Shareable, Sendable {
List<Product> products;
}
class Product implements Listable, Shareable, Sendable {
}
class ListManager {
public void addToList(Listable element) { }
}
class ShareManager {
public void share(Shareable element) { }
}
class SendManager {
public void send(Sendable element) { }
}
You could then use Post and Product interchangeably this way:
Post post = new Post();
Product product = new Product();
ListManager listManager = new ListManager();
listManager.addToList(post);
listManager.addToList(product);
ShareManager shareManager = new ShareManager();
shareManager.share(post);
shareManager.share(product);
SendManager sendManager = new SendManager();
sendManager.send(post);
sendManager.send(product);
Regarding the database representation, as suggested fusiled in his comment, just stick them in 2 separate tables. With a mapping table in between to link the products to their post.
EDIT
Regarding the issue with the MESSAGES table
You could add a new mapping table MESSAGE_ATTACHED_ITEM with columns messageId, postId, productId. Only set a value to the relevant colum when attaching an item to a message
Or an other option would be to have an ATTACHED_ITEM table with an id only.
And have Post and Product tables to have a foreign key to this table Id.
you can then stick this attachedItemId into your attached_item column
I think the solution could be simpler than you think. Why don't you ust use a common Java-like interface and hide the implementation details?
Just implement a common interface with the methods you need. Supposing this common interface is called EntityInterface:
public class Post implements EntityInterface {};
public class Product implements EntityInterface {};
Then when you want to handle these classes, you treat them as an EntityInterface object:
EntityInterface myNewPost = new Post();
EntityInterface myNewProduct = new Product();
//Now you see myNewProduct and myNewPost as EntityInterface objects
These code fragments are in Java, but use virtual functions in C++ and you get the same.

How to dynamize cucumber value and pass that into the login page

How to dynamize cucumber value and pass that into the login page, for example:
If I use Adam in the cucumber scenario then it should automatically use adam login details and other information and if i use another name it should use that person's information. So i do not have to manually enter it in every step defination. How Can i achieve it?
Scenario: Add an item to shopping bag to place the order using mastercard
Given that "Adam" is logged in to his account
When he searches and adds an item from "men" section to his shopping bag
Then he can place the order
export class LoginUser implements Task {
static called(name: string): LoginUser {
return new LoginUser(name);
}
performAs(actor: PerformsTasks): PromiseLike<void> {
return actor.attemptsTo(
Click.on(homePageElementsMap.lnk_login),
Enter.theValue('test#test.com').into(loginPageElementsMap.txt_login_email),
Enter.theValue('password111').into(loginPageElementsMap.txt_login_pwd),
Click.on(loginPageElementsMap.btn_login)
);
}
constructor(private name: string) {
}
}
disclaimer: this is a java answer, I misread the tag. I am sure you can something similar for js.
For our tests we have a variety of users as well and we use a java class with userdata for this, set up as maps.
We pass the value to a static method public Map<String, String> getUserData(String username) which contains a switch for the variety of users we have, each user is given a map of data we want to use in the tests. The users each have a private Map in the class containing login information.
Of course, there are more scalable ways, this one just gives us the flexibility of a single public getUserData(userName) and behind this we can do with the storage whatever we want.
Short answer: static java code containing user information for a variety of usernames.
Is this the only way to do it? - http://docs.behat.org/en/v2.5/guides/1.gherkin.html

Google App Engine NDB repeated property additional info

For example: I have an Article model with a repeated "title" property that stores translations in different languages of the original title:
class Article(ndb.Model):
title = ndb.StringProperty(repeated=True)
How can I store, besides the title property, the language code of the title, so I can get specific versions of the title, something like this:
en_title = article.title['en']
It is important to have the same property name since I don't know in what language the article title will be queried by.
You can use repeated structure property:
class Title(ndb.Model):
title = ndb.StringProperty()
lang = ndb.StringProperty()
class Article(ndb.Model):
titles = ndb.StructuredProperty(Title, repeated=True)
Are you querying on the titles or languages? If not, you can use PickleProperty or JsonProperty to store a dict.

"Unload" lazy loaded entities

i have an application with a derby database and use eclipselink as the persistence api.
Say i have a gui with a list of teams. Each team has a number of players on it. The relationship in the team class looks like this:
#OneToMany(mappedBy = "team", fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
private List<player> players = new ArrayList<player>():
and the player class like this:
#ManyToOne(targetEntity = Team.class)
#JoinColumn(name = "teamID", nullable = false, referencedColumnName = "ID")
private Team team;
So i now start my application and it fills a list with all existing teams:
public List<Team> getTeams()
{
TypedQuery<Team> query = em.createQuery("SELECT t FROM Team t", Team.class);
List<Team> teams = query.getResultList();
return teams;
}
All is working right so far, only the teams are loaded, not the players. Say i now open a table with the players of a team by selecting a team and exectue the command for this. The table is filled with:
team.getPlayers();
So now all the players of this team are loaded, cause they are now needed.
But after i close the table they remain loaded, but i would like to "unload" them again so that they don't remain in memory - how would i do this?
If you want to get rid of managed entities from its context you can call EntityManager.clear() method (calling EntityManager.flush() before). This operation, however, removes all managed entities, which is not necessarily what you want, since this might cause additional database hits.
If you are lucky and you can use JPA 2.0 there is a better option: EntityManager.detach(Object) method, which is removing given object from persistence context.

Playframework Siena Filtering and Ordering

This is my first question on any of these websites so pardon my unprofessionalism.
I use playframework with SIENA module (with GAE) and I came accross the following problem:
Given 3 entities:
public class Meeting extends Model{
#Id
public Long id;
public String place;
#Owned
Many<MeetingUser> users;
.
.
.
}
public class User extends Model{
#Id
public Long id;
public String firstName;
public String lastName;
#Owned
Many<MeetingUser> meetings;
.
.
.
}
public class MeetingUser extends Model{
#Id
public Long id;
public Meeting meeting;
public User user;
.
.
.
public User getUser(){
return Model.all(User.class).filter("id", user).get();
}
public Meeting getMeeting(){
return Model.all(Meeting.class).filter("id", meeting).get();
}
}
For instance I am listing a meeting and all their users:
public static void meetingInfo(Long meetingId){
Meeting meeting = Models.all(Meeting.class).filter("id",meetingId);
List<MeetingUser> meetingusers = meeting.asList();
List<User> users = new ArrayList<User>();
for(MeetingUser mu: meetingusers){
users.add(mu.getUser());
}
render(users);
}
This is done(is there any better way here?) however when it comes to filtering (especially dynamic filtering for many many fields) I can not use the Query's filter method on the MeetingUser as I need to filter on a MeetingUser's field's field (firstName). The same problem arise for ordering. I need the solution for both problems.
I hope my problem is clear and I appreciate any kind of help here.
Remember that you are in GAE which is a NoSQL DB.
So you can't do Join request as in RDBMS.
Yet, this is not really the pb you have so this was just to be sure you are aware of it ;)
So if you want to find the person having given firstname in a given meeting, can you try the following:
List<MeetingUser> meetingusers = meeting.users.asQuery().filter("firstname", "XXX");
(you can also order)
Nevertheless, knowing that you can't join, remember that you can't write a query searching for a meeting in which there are users whose firstname is XXX as it would require some joins and it doesn't exist in GAE. In this case, you need to change your model following NoSQL philosophy but this is another subject
regards
Let's try to give a way to do what you want...
Your relation is a Many-to-Many which is always the worst case :)
You want to filter Meeting by User's firstname.
It requires a join request which is not possible in GAE. In this case, you must change your model by denormalizing it (sometimes use redundancy also) and manage the join by yourself. Actually, you must do the job of the RDBMS by yourself. It seems overkill but in fact, it's quite easy. The only drawback is that you must perform several requests to the DB. NoSQL means No Schema (& No Join) so there are a few drawbacks but it allows to scale and to manage huge data load... it depends on your needs :)
The choice you did to create the MeetingUser which is a "joined" table and a kind of denormalization is good in GAE because it allows to manage the join yourself.
Solution:
// fetch users by firstname
List<User> users = users.all().filter("firstName", "John").fetch();
// fetch meetingusers associated to these users (verify the "IN" operator works because I didn't use that for a long time and don't remember if it works with this syntax)
List<MeetingUser> meetingusers = MeetingUser.all().filter("user IN", users);
// now you must fetch the whole meeting because in MeetingUser, only the Meeting ID is stored (other fields are Null or O)
List<Meeting> meetings = new ArrayList<Meeting>()
for(MeetingUsers mu:meetingusers) {
meetings.add(meetingusers.meeting);
}
// use the batch feature to fetch all objects
Meeting.batch(Meeting.class).get(meetings);
// you have your meetings
Hope this helps!

Resources