I have a collection where I store user groups. Each group has a group name, group limit and an array of users ID's.
I wonder how the best way to retrieve one group details and then users details, like name, photo, etc.
Right now, I am doing two queries to the database. First retrieving the group data(name, etc), second getting a list of users who has in the user details the information of the group ID:
"syncDesp = a4sQ27xb1wuD2rhONU2K"
I'm afraid of calling the database to many times.
// Get Group details
Preferencias prefs = new Preferencias(view.getContext());
listenGroups = pFirestore.collection("syncDesps").document(prefs.getSyncDesp()).addSnapshotListener((documentSnapshot, e) -> {
if(e != null){
Log.i("dados erro", Objects.requireNonNull(e).getMessage());
}
if(documentSnapshot != null){
String nomeGrupo = Objects.requireNonNull(documentSnapshot.get("nomeGrupo")).toString();
textNomeGrupo.setText(nomeGrupo);
ArrayList membrosGrupo = (ArrayList) Objects.requireNonNull(documentSnapshot.get("syncDesp"));
}
});
// Get User Details
FirebaseFirestore grupoFire = FirebaseFirestore.getInstance();
grupoFire.collection("usuarios")
.whereEqualTo("syncDesp", prefs.getSyncDesp())
.addSnapshotListener((queryDocumentSnapshots, e1) -> {
listaUsuarios.clear();
if(e != null){
Log.i("dados erro", Objects.requireNonNull(e1).getMessage());
}
for(DocumentSnapshot usuarioSnapshot : Objects.requireNonNull(queryDocumentSnapshots).getDocuments()){
String idU = (usuarioSnapshot.get("id") == null) ? "" : Objects.requireNonNull(usuarioSnapshot.get("id")).toString();
String nomeUsuario = (usuarioSnapshot.get("nome") == null) ? "" : Objects.requireNonNull(usuarioSnapshot.get("nome")).toString();
String fotoUsuario = (usuarioSnapshot.get("imgUsuario") == null) ? "" : Objects.requireNonNull(usuarioSnapshot.get("imgUsuario")).toString();
UsuarioMeuGrupo usuarioMeuGrupo = new UsuarioMeuGrupo();//
usuarioMeuGrupo.setIdUsuario(idU);
usuarioMeuGrupo.setNome(nomeUsuario);
usuarioMeuGrupo.setFoto(fotoUsuario);
listaUsuarios.add(usuarioMeuGrupo);
}
adaptera.setOnItemClickRemoverListener(uMeuGrupo -> {
Log.i("dados uMeuGrupo Clic", uMeuGrupo.getNome());
});
adaptera.notifyDataSetChanged();
});
I wonder if I should query the group collection separately from the users collection or if there is a way of making only one function to retrieve data from both collections.
It's not possible to make a single query in Cloud Firestore span multiple collections. There is no join-like operation like you have in SQL. The only exception to this is collection group queries, which doesn't apply to your situation.
What you're doing right now is probably the best you can do with the database structure you have. If you want fewer queries, you'll have to do something to restructure your data to support that.
Related
How to get multiple documents from a Collection in firebase if we want to filter using not_in operator with a uniqueId list of documents.
I have a arrayList like this:
ArrayList<String> idList = new ArrayList();
idList.addAll(uniqueIdList);
// now idList have more than 500 uniqueId
Query query = db.collection("my_collection")
.whereEqualTo("status", "DONE")
.whereNotIn("uniqueId", idList)
.orderBy("uniqueId", Query.Direction.DESCENDING)
.orderBy("createdOn", Query.Direction.DESCENDING);
/* FIREBASE DOCUMENTATION SAYS
------------------------------
Use the in operator to combine up to 10 equality (==)
clauses on the same field with a logical OR */
If the idList object have more than 10 items. It crashes the android application due to FirestoreException.
So, should we not use where_not_in operator? But I have specific demand of this for the query.
So, if you want to query using where_not_in operator in Firebase then, you have to do some part from client side also. The query has a serious limitation. So here is a solution.
// Assume idList contains the uniqueId of documents that you don't want
// Assume status can be DONE or PENDING
// Assume list_objects is the ArrayList you have to pass to Recycler view or list view in your app
if (idList.size() > 0 && idList.size() <= 10) {
query = db.collection("my_collection")
.whereEqualTo("status", "DONE")
.whereNotIn("uniqueId", idList)
.orderBy("uniqueId", Query.Direction.DESCENDING)
.orderBy("createdOn", Query.Direction.DESCENDING);
// your on success code here
} else {
query = db.collection("my_collection")
.whereEqualTo("status", "DONE")
.orderBy("createdOn", Query.Direction.DESCENDING);
// here we are fetching all data where status is done
query.get().addOnCompleteListener(task -> {
if (task.isSuccessful()) {
List<Object> list_toRemove = new ArrayList<>();
list_objects = task.getResult().toObjects(ClassName.class);
for (int i = 0; i < list_objects.size(); i++) {
Object item = list_objects.get(i);
if (idList.contains(item.getUniqueId())) {
list_toRemove.add(list_objects.get(i));
}
}
list_objects.removeAll(list_toRemove);
}
}
// remove the data manually here and we are now good. There is no other way for now.
}
So this is a limitation in firebase, but if we look at the advantages of using firebase firestore DB then it's a trade off.
The rule is that if you cannot filter data using query then fetch with applying filters that are possible then again filter using the Collection Framework (if you are using Java). All things are possible in this DB.
i want to make a simple query, with multiple conditions
I use OrmLite to map entity object.
Now I want to search for an object into my table.
Supposing i have a Person entity that maps PERSON table, what I want to do is to initialize an object with some parameters and search it.
Suppose a function searchPerson(Person oPerson)
If i pass an object OPerson like this
Id = null
Name = John
Age = null
Sex = male
Is possible to write a query to reach that goal? Something like this pseudo-code
pers = (from p in db.Table<Person>()
where (if OPerson.Id !=null) p.Id==OPerson.Id}
AND {(if OPerson.Name !=null) p.Name.Contains(OPerson.Name)}
AND {(if condition) where-contion}
select p).ToList();
I know that i can do multiple query in this way
list=PersonDao.queryBuilder().where().eq("name",OPerson.name)
.and().eq("sex",OPerson.sex").query();
but I want also to check if the value exists
where (if OPerson.Id !=null) p.Id==OPerson.Id}
#ArghArgh is close but doesn't have the ANDs right. The problem is that the AND statements are conditional on whether there were any previous statements. I'd do something like:
QueryBuilder<Person, Integer> queryBuilder = dao.queryBuilder();
Where<Person, Integer> where = queryBuilder.where();
int condCount = 0;
if (oPerson.id != null) {
where.eq("id", oPerson.id);
condCount++;
}
if (oPerson.name != null) {
where.like("name", "%" + oPerson.name + "%");
condCount++;
}
...
// if we've added any conditions then and them all together
if (condCount > 0) {
where.and(condCount);
}
// do the query
List<Persion> personList = queryBuilder.query();
This makes use of the where.and(int) method which takes a number of clauses on the stack and puts them together with ANDs between.
I think that you must use the QueryBuilder.
Try something like this
QueryBuilder<Person, Integer> queryBuilder = PersonDao.queryBuilder();
// get the WHERE object to build our query
Where<Person, String> where = queryBuilder.where();
if(oPerson.Name!=null)
where.like("Name", "%"+oPerson.Name+"%");
// and
where.and();
if(Person.Sex!=null)
where.like("Sex", "%"+oPerson.sex+"%");
PreparedQuery<Person> preparedQuery = queryBuilder.prepare();
Than you can call it in this way
List<Person> list = PersontDao.query(preparedQuery);
I have these tables in an Android based application where I'm using OrmLite for the database management.
What I want to have an x number of array list depending on how many of the product type FOLDER I have.
So in this case I want to a list of products where the productId equals parentId.
So I want a list where
if(productType = FOLDER) {
if(productId = parentId){
//add product
}
}
Basically what I want to end up with, in this case three lists with each containing a list of products where parentId is the same for every product.
I've tried many things, and some works better than others, but a code I want to run actually throws a nullpointer.
DatabaseHelper dbHelper = getHelper();
List<Product> productsParents = null;
try {
Dao<Product, Integer> dao = dbHelper.getDao();
PreparedQuery<Product> prepQu = dao.queryBuilder().where()
.eq("parentId", dao.queryBuilder().selectColumns("productId").where()
.eq("productType", ProductType.FOLDER).prepare()).prepare();
productsParents = dao.query(prepQu);
} catch (SQLException e) {
...
}
This code isn't working because productParents returns null, and it does not do what I want, even though it's a slight hint. If someone know how to do this in code that would be sufficient also, or more likely a mix of java and ormlite.
Have you had a chance to RTFM around building queries? The ORMLite docs are pretty extensive:
http://ormlite.com/docs/query-builder
Your problem is that a prepared query cannot be an argument to the eq(...) method. Not sure where you saw an example of that form.
So there are a couple ways you can do this. The easiest way is to do a different query for each productType:
Where<Product, Integer> where = dao.queryBuilder().where();
where.eq("parentId", parentId).and().eq("productType", ProductType.FOLDER);
productsParents = where.query();
// then do another similar query again with ProductType.PRODUCT, ...
If you want to do just one query then you can get all products that match the parentId and then separate them using code:
Where<Product, Integer> where = dao.queryBuilder().where();
where.eq("parentId", parentId);
productsParents = where.query();
List<Product> productFolders = new ArrayList<Product>();
List<Product> productProducts = new ArrayList<Product>();
...
for (Product product : productsParents) {
if (product.getProductType() == ProductType.FOLDER) {
productFolders.add(product);
} else if (product.getProductType() == ProductType.PRODUCT) {
productProducts.add(product);
} else ...
}
I am extracting a database using query, what is the best practice to store the data temporarily. Currently i am using ArrayList to hold the data extracted, but i am thinking that might not be best design practice.
Thanks
Cursor cur5 = database2.rawQuery("select ID from Quote where EmoticonID=? and SubCategoryID=?" ,new String [] {Integer.toString(gcid), Integer.toString(scid)});
if(cur5.getCount()==0){
Log.i("TAG Screen3", "No Quotes ID found for Particular ID");
if (helper2 != null) {
helper2.close();
}
if (database2 != null) {
database2.close();
}
}else{
cur5.moveToFirst();
do {
quoteid.add(Integer.parseInt(cur5.getString(0)));
Log.i("TAG Screen3 Quote ID", (cur5.getString(0)));
} while (cur5.moveToNext());
if(cur5 != null){
cur5.close();
}
if (helper2 != null) {
helper2.close();
}
if (database2 != null) {
database2.close();
}
}
Well if you already have a database to get the data from, why not using that database as temp store. Just get the data from the database when you need it an skip the temporary storage.
If you still want to store it locally on your phone I suggest a local sqlite database for huge objects or POJO's. If you have primitive types of key-value pairs you should use SharedPreferences.
For more information see http://developer.android.com/guide/topics/data/data-storage.html.
Or give us some information about your data and what you intend to do:) That might help us in helping you ;)
I have two tables CustomerBalance and Customer which are bound with CustomerRefId field.
I want the CustomerBalance records that are lets say greater than 100 for a field balance of this tables. I also want to include into my results the name of the particular customer that fulfills that criteria. I created the following method that works!
public List<CustomerBalance> getCustomerBalanceFilter(String filterVal) {
try {
PreparedQuery<CustomerBalance> preparedQuery = mDbHelper.getCustomerBalanceDao().queryBuilder()
.where().gt(CustomerBalance.DB_COL_CUSTOMER_BALANCE, filterVal)
.prepare();
List<CustomerBalance> result = mDbHelper.getCustomerBalanceDao().query(preparedQuery);
for(CustomerBalance alert : result) {
PreparedQuery<Customer> getCustQuery = mDbHelper.getCustomerDao().queryBuilder()
.where().eq(Customer.DB_COL_CUSTOMER_REF_ID, alert.getCustomerID())
.prepare();
List<Customer> customer = mDbHelper.getCustomerDao().query(getCustQuery);
alert.setCustomer(customer.size() == 1 ? customer.get(0) : null);
}
return result;
} catch(Exception ex) {
return null;
}
}
This methods is working, is this the best way to write such a query? or is there a more appropriate approach?
One improvement to your query is to use ORMLite's SelectArg to pass in the customer-id instead of a new query each time. Something like:
...
List<CustomerBalance> result = mDbHelper.getCustomerBalanceDao()
.query(preparedQuery);
SelectArg custIdArg = new SelectArg();
PreparedQuery<Customer> getCustQuery = mDbHelper.getCustomerDao().queryBuilder()
.where().eq(Customer.DB_COL_CUSTOMER_REF_ID, custIdArg)
.prepare();
for (CustomerBalance alert : result) {
custIdArg.setValue(alert.getCustomerID());
List<Customer> customer = mDbHelper.getCustomerDao().query(getCustQuery);
alert.setCustomer(customer.size() == 1 ? customer.get(0) : null);
}
Here are the docs for SelectArg:
http://ormlite.com/docs/select-arg
FYI, there also is an UpdateBuilder, but I don't see an easy way to turn your code above into a single UPDATE statement.