Converting SQLite query to Firebase database query - android

I developed this app for my senior project and used SQLite and stored everything locally. I want to convert everything to Firebase now but there aren't that many tutorials out there, at least for what I'm trying to do. My question is how would I go about converting a query like the below to a Firebase database query?
public ArrayList<String> getAllBeautyItems() {
itemsList.clear();
dbHelper.getReadableDatabase();
ArrayList<String> itemNames = new ArrayList<>();
String[] tableColumns = new String[]{
Constants.ITEM_NAME, Constants.CATEGORY
};
String whereClause = Constants.CATEGORY + "=?";
String[] whereArgs = new String[]{
"beauty"
};
Cursor result = db.query(Constants.ITEMS_TABLE_NAME, tableColumns, whereClause, whereArgs,
null, null, null, null);
if (result.moveToFirst()) {
do {
itemNames.add(result.getString(result.getColumnIndex(Constants.ITEM_NAME)));
} while (result.moveToNext());
}
result.close();
return itemNames;
}
and then in a fragment I'm calling a setName, so how do I get the result of that query and apply it like in the below?
private ArrayList<Items> refreshData() {
dbItems.clear();
final ArrayList<String> itemNames = adapter.getAllBeautyItems();
ArrayList<String> itemImages = adapter.getAllBeautyImages();
ArrayList<Integer> itemPrices = adapter.getAllBeautyPrices();
ArrayList<String> itemDescriptions = adapter.getAllBeautyDescriptions();
ArrayList<String> itemLocations = adapter.getAllBeautyLocations();
ArrayList<String> itemLats = adapter.getAllBeautyLats();
int totalItems = adapter.getTotalBeautyItems();
String formattedItems = Utils.formatNumber(totalItems);
totalItemsText.setText("Total Items: " + formattedItems);
ArrayList<Items> items = new ArrayList<>();
for (int i = 0; i < itemNames.size(); i++) {
Items item = new Items();
item.setItemName(itemNames.get(i));
item.setItemImage(itemImages.get(i));
item.setItemPrice(itemPrices.get(i));
item.setItemDescription(itemDescriptions.get(i));
item.setItemLocation(itemLocations.get(i));
item.setLatLocation(itemLats.get(i));
items.add(item);
}
return items;
}

First of all, I wanna recommend you this: https://firebase.googleblog.com/2013/10/queries-part-1-common-sql-queries.html
It's a tutorial that show you how yo make typical SQL queries in Firebase, BUT, like the owner says:
While this post still contains some useful and relevant information, we have released advanced query functionality which solves a lot of the problems this post discusses.
So, now, I will tell you the basic query that may solve your problem.
As I see, you have a table about Items, and you are doing a SELECT where that item's Category is beauty.
I will assume that you already know how data is stored in Firebase, so I'm not making us lose time explaining to you about the database tree.
Reading
You will need something like:
Query query = FirebaseDatabase.getInstance().getReference()
.child("items")
.orderByChild("Category")
.equalTo("beauty");
This, after attaching the listener to it, will search in the items tree, those items where the value of its category child, is beauty. The logic here is:
FirebaseDatabase.getInstance().getReference() -> Go to the main node
.child("items") -> Go to the Items node
.orderByChild("Category") -> Order them by its Category child
.equalTo("beauty") -> Look only at those with the "beauty" value
You will always need to do an orderBy*() to append an equalTo() and mimic the WHERE clause.
And, in your listener you will have something like:
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
List<Item> list = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Item item = snapshot.getValue(Item.class);
list.add(item);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//
}
};
query.addValueEventListener(eventListener);
And, since all Firebase connections are async, you will need a calback method to return the list after the for.
Writing
Now, for the upload, you will need a DatabaseReference, instead of a Query, like:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("items");
And all you need to do is:
ref.push().setValue(item); -> For a random ID
ref.child(key).setValue(item); -> For an specific ID (key)

Related

I need to add a value to an array field in a cloud firestore document

I want to add values to array in Firestore document and get them back as list or array.
This is my code , and it just replace the array value at 0 index , and i made a list and added the value it return boolean .
FirebaseFirestore db = FirebaseFirestore.getInstance();
final DocumentReference doc = db.collection("RoomInformation").document(model.getRoomAdmin());
db.collection("RoomInformation").document(model.getRoomAdmin()).update(freshUser).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
doc.update("onlineUsers" , Arrays.asList("user" , facebookUserName)).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
new OurToast().myToast(view.getContext() , facebookUserName + " Join The Room");
}
});
}
}
As seen in the offical documentation regarding arrays:
Although Cloud Firestore can store arrays, it does not support querying array members or updating single array elements.
Taking the following code snippet as an example:
public class ArrayPost {
String title;
String[] categories;
public ArrayPost(String title, String[] categories) {
this.title = title;
this.categories = categories;
}
}
ArrayPost myArrayPost = new ArrayPost("My great post", new String[]{
"technology", "opinion", "cats"
});
We see that using the data structure above, there is no way to perform this query.
One more thing to note, although Cloud Firestore can store arrays, this is an anti-pattern. One of the many reasons Firebase recommends against using arrays is that it makes the security rules impossible to write. I recomand you consider an alternative data structure, where each category is the key in a map and all values are true. Please take a look at this example:
public class MapPost {
String title;
Map<String,Boolean> categories;
public MapPost(String title, Map<String,Boolean> categories) {
this.title = title;
this.categories = categories;
}
}
Map<String, Boolean> categories = new HashMap<>();
categories.put("technology", true);
categories.put("opinion", true);
categories.put("cats", true);
MapPost myMapPost = new MapPost("My great post", categories);
Edit 13 Aug 2018:
According to the updated documentation regarding array membership, now it is possible to filter data based on array values using whereArrayContains() method. A simple example would be:
CollectionReference citiesRef = db.collection("cities");
citiesRef.whereArrayContains("regions", "west_coast");
This query returns every city document where the regions field is an array that contains west_coast. If the array has multiple instances of the value you query on, the document is included in the results only once.

Sorting Database list android by likes

I am building recipes app. I have page in my app that retrieves all the recipes from the database on Firebase into ListView. Each Recipe has these variables:
public String key;
public String uid;
public String title;
public String type;
public String ingredients;
public String instructions;
public int likes;
Here's the function that retrieves all the data :
//Retrieve Data from database
public void retriveData() {
database.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
recipes = new ArrayList<Recipe>();
for(DataSnapshot data : dataSnapshot.getChildren()) {
Recipe r = data.getValue(Recipe.class);
recipes.add(r);
}
allRecipeAdapter = new AllRecipeAdapter(AllRecipeActivity.this,0,0,recipes);
lv.setAdapter(allRecipeAdapter);
}
}
}
Now i want to create another screen that also has a ListView and i would like to sort the Recipes by nubmer of likes and then enter the top 10 recipes into the ListView.
I searched on Google i found the function OrderByValue but i can't figure out how to use it i realized how to works but i can't implement this to my project.
Gaƫtan Maisse and KLHauser gave you solutions that work in pure client-side code. Here's an alternative that uses Firebase Database queries, which means the ordering and filtering happen on the server:
// assuming that database refers to the list of all recipe
Query topRecipes = database.orderByChild("likes").limitToLast(10);
topRecipes.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
recipes = new ArrayList<Recipe>();
for(DataSnapshot data : dataSnapshot.getChildren()) {
Recipe r = data.getValue(Recipe.class);
// add the recipe to the front of the list
recipes.add(0, r);
}
allRecipeAdapter = new AllRecipeAdapter(AllRecipeActivity.this,0,0,recipes);
lv.setAdapter(allRecipeAdapter);
}
}
Since Firebase queries always sort items in ascending order, the query takes the last 10 items - those are the ones with the highest like count. To reverse those items, the code inserts each item to the from of the list, instead of appending them to the end.
You can sort your list using a Comparator and then get a sublist of 10 first elements before displaying it in the ListView:
Comparator<Recipe> likesOrderComparator = new Comparator<Recipe>() {
public int compare(Recipe recipe1, Recipe recipe2) {
return recipe1.likes < recipe2.likes ? -1 : recipe1.likes == recipe2.likes ? 0 : 1;
}
};
Collections.sort(recipes, likesOrderComparator);
List<Recipe> topTenRecipes = recipes.subList(0, 9);
// Now display topTenRecipes in a ListView
Java7:
Collections.sort(list, new Comparator<Recipe>() {
#Override
public int compare(Recipe r1, Recipe r2) {
if (r1.getLikes() > r2.getLikes())
return 1;
if (r1.getLikes() < r2.getLikes()
return -1;
return 0;
}
});
Java8 (using lambda):
recipes.stream()
.sorted((r1, r2) -> Integer.compare(r1.getLikes(),
r2.getLikes()))

Objectify: delete entire row by id

I need to check if a field contains specific String, and if it does - delete the entire row by id.
This code doesn't working:
Query<Bet> query = ofy().load().type(Movie.class);
for (Movie m : query) {
List<String> list = m.getActors();
String search = "Brad Pitt";
for (String str : list) {
if (str.trim().contains(search)) {
ofy().delete().type(Movie.class).id(m.getId()).now();
}
}
}
In this case (deleting all movies with Brad Pitt in it as an actor) you could delete the entity like this:
Query<Movie> query = ofy().load().type(User.class);
for (Movie m : query) {
List<String> list = m.getActors();
String search = "Brad Pitt";
for (String str : list) {
if (str.trim().contains(search)) {
ofy().delete().entity(m).now();
}
}
}
Not that i delete with delete().entity(...). Another option would be to delete by key like so delete().key(Key.create(Movie.class, idToRemove). The former does something quite similar but since you have the whole entity you don't need to complicate things. Also if you delete with entity(...) it will work when the entity has a #Parent whereas if you delete by key you'd have to additionally specify the ancestor in Key.create(ancestorKey, Movie.class, idToRemove).
I usually do multiple deletes like this:
Query<Movie> query = ofy().load().type(User.class);
List<Movie> toDelete = new ArrayList<>();
for (Movie m : query) {
List<String> list = m.getActors();
String search = "Brad Pitt";
for (String str : list) {
if (str.trim().contains(search)) {
toDelete.add(m);
}
}
}
ofy().delete().entities(toDelete).now();
Performing database operations in a loop is bad style and should be avoided if possible.
One more thing:
If you must delete an entity by id the line would look like this:
ofy().delete().type(Movie.class).id(idToDelete);
However, as i hinted at before, if your Movie class has a parent this will not work because you must always specify the whole key, thus with ancestor the line would look like this:
Key<MyParentClass> parent = Key.create(MyParentClass.class, myParentId);
ofy().delete().type(Movie.class).parent(parent).id(idToDelete);
which is equivalent to
ofy().delete().key(Key.create(Key.create(MyParentClass.class, myParentId), Movie.class, idToDelete));

Calling a function in certain intervals

I'm making an android app which displays the list of male and female from database with a user specified age. I almost managed to write the code
the below is my code as far as I made
public class UserList{
private ArrayList<String> maleList;
private ArrayList<String> femaleList;} //getter setter for Arraylists
// method to get data
public UserList getUserLists (Context context, String age){
public UserList userList = new UserList();
public ArrayList<String> maleList = new ArrayList<String>();
public ArrayList<String> femaleList = new ArrayList<String>();
db = dbhelper.getWritableDatabase();
Cursor cursor = db.rawQuery(
"select * from USER_INFO where AGE = ?", new String[]{age});
if(cursor != null)
{
if(cursor.moveToFirst())
{
do{
String user_id = cursor.getString(cursor.getColumnIndex("USER_NAME"));
String gender = cursor.getString(cursor.getColumnIndex("GENDER"));
if(gender.equalsIgnorease("MALE"))
maleList.add(user_id);
else
femaleList.add(user_id);
}while(cursor.moveToNext());
cursor.close();
}
}
userList.setMaleList(maleList);
userList.setFemaleList(femaleList);
return userList;
}
But now I need to call this function for getting data from database to cursor in certain intervals like after every 5 minutes. Please help me in doing that the age variale used is age.
You should implement a broadcast receiver and setup an alarm scheduled at regular interval.
There is a simple tutorial on how to do that here : alarm-manager-example

Sorting the contents of ArrayAdapter or ArrayList

I am working on android project and am making using of a ListView that retrieves data from the SQLite database.
I am making a dataset using an ArrayList and then adding this ArrayList into an ArrayAdapter.
When the data is being retrieved from the database, I am telling SQLite to do the sorting so everything is in alphabetical order when it is added into the ListView. At certain times, the information will be added dynamically to to the ListView without it requiring to re-fetch everythin from the database again. However, I want to keep everything in alphabetical order.
How would I do this, do I sort the DataSet and then call the notifyDataSet Changes or do I do the sort directly on the ArrayAdapter. I've looked into performing the sort on the ArrayAdapter but this wants an argument that uses a Comparator but not sure what this is and can't find any working examples that may be of any help for what I want to achieve.
Below is the code that populates the array and sets the list adapter
ArrayList<Spanned> passwords = managePasswordList.getPasswordList();
if (passwords != null && passwords.size() > 0)
{
passwordArrayAdapter = new ArrayAdapter<Spanned>(getActivity().getApplicationContext(),
android.R.layout.simple_list_item_activated_1, passwords);
setListAdapter(passwordArrayAdapter);
myListView.setTextFilterEnabled(true);
txtNoRecords.setVisibility(View.GONE);
}
else
{
txtNoRecords.setVisibility(View.VISIBLE);
}
I am then adding data to the dataset and refreshing the list view using the following
String company = Encryption.decrypt(passwords.get(i).company);
String username = Encryption.decrypt(passwords.get(i).username);
details = Html.fromHtml(company + "<br />" + "<small><font color=\"#767676\">" + username + "</b></small>");
passwords.add(details);
passwordArrayAdapter.notifyDataSetChanged();
Thanks for any help you can provide.
UPDATE 1
I've tried doing what Nick Bradbury suggested but I am having a problem with the comparator. I have the following code but I don't know where to go from here.
SQLiteDatabase myDb = null;
Cursor cursor = null;
ArrayList<Spanned> passwords = new ArrayList<Spanned>();
try
{
myDb = context.openOrCreateDatabase("PasswordManager", Context.MODE_PRIVATE, null);
cursor = myDb.rawQuery("SELECT * FROM password ASC", null);
while (cursor.moveToNext())
{
final String company = Encryption.decrypt(cursor.getString(2));
final String username = Encryption.decrypt(cursor.getString(4));
Spanned details = Html.fromHtml(company + "<br />" + "<small><font color=\"#767676\">" + username + "</b></small>");
passwords.add(details);
Collections.sort(passwords, new Comparator<Spanned>() {
public int compare(Spanned lhs, Spanned rhs) {
return 0;
}
});
}
}
catch (SQLiteException ex)
{
common.showBasicAlertDialog("Unfortunately something has gone wrong.\n\nWe will fix this as soon as we can", false);
Log.e("Database Error", ex.toString());
return null;
}
In the return statement I have no idea what to do, I've tried return lhs.compareTo but the lhs and rhs variables don't have the compareTo function so I have not got a clue what to do.
Here's a simple example of sorting an ArrayList using Comparator. In this example, the ArrayList is defined as:
public class StatusList extends ArrayList<Status>
A sort routine for this ArrayList could look like this:
public void sort() {
Collections.sort(this, new Comparator<Status>() {
#Override
public int compare(Status item1, Status item2) {
return item2.getDate().compareTo(item1.getDate());
}
});
}
Replace <Status> with whatever object your ArrayList contains, then change the comparison to compare the values of the object you wish to sort by.

Categories

Resources