Check duplicate data on Realtime Database with Java on Android Studio - java

I'm developing an app:
In my realtime database I have this structure
But some keys have the same data and it's a duplicate like this:
In my Android Studio project I code this function but only retrieve the data but no check the duplicates:
private void deleteIfAreDuplicateData() {
List<Order> orderList = new ArrayList<>();
FirebaseDatabase.getInstance().getReference(Common.ORDER_REF)
.orderByKey()
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
ArrayList<Object> numeroDeOrden = new ArrayList<>();
String datos;
String pagoFinal, tiempo, idUsuario, nombreUsuario;
boolean exists = false;
for (DataSnapshot orderSnapshot : dataSnapshot.getChildren()) {
Map<String, Object> model = (Map<String, Object>) orderSnapshot.getValue();
pagoFinal = String.valueOf(orderSnapshot.child("finalPayment").getValue());
tiempo = String.valueOf(orderSnapshot.child("orderTime").getValue());
idUsuario = String.valueOf(orderSnapshot.child("userId").getValue());
nombreUsuario = String.valueOf(orderSnapshot.child("userName").getValue());
datos = (String) orderSnapshot.getKey();
numeroDeOrden.add(datos);
for (int i = 0; i < numeroDeOrden.size(); i++) {
if (model.get("finalPayment").equals(pagoFinal) && model.get("orderTime").equals(tiempo)) {
exists = true;
}
}
}
if(exists)
{
Toast.makeText(getContext(), "Tienes ordenes repetidas ", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
How can I check for duplicate in the database and when I have the duplicates remove only one of the 2 values (?)

If you want to prevent duplicate values, use those values as the keys for the data. So in your case, if you want the combination of all property values to be unique, combine all of those values into a single string and use that as your key.
You'll want to remove or encode any characters that are not allowed in keys, so ., $, [, ], #, and /, from the key.
In addition, if the key becomes longer than the maximum key length of 768 characters, you'll want to reduce it down to size too with a hash function or by simply truncating the string. See my answer here for some more info on that: Firebase Error: First argument has a key path longer than 768 Bytes

You can have a list of your model saved in your activity (or typically in ViewModel as a static member):
pubic static List<Map<String, Object>> modelList;
Then for each change in data you can add only the new data to the model by checking if exists using contains() method:
for (DataSnapshot orderSnapshot : dataSnapshot.getChildren()) {
Map<String, Object> model = (Map<String, Object>) orderSnapshot.getValue();
if (!modelList.contains(model)) {
modelList.add(model);
// Add your rest of code for the incoming new/change of data
}
}

Related

Firebase dealing with nested data

Okay, say I've got the following FireBase database structure.
{
"2143" :
{
"Henk" : 6,
"message" : 1
}
}
With data being added as follows:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("2143/message");//Testing code, would later be replaced with a session variable and a username variable.
myRef.setValue(1);//Again, mere testing code which sets the 'message' key to have value 1. The actual code is currently lacking as the program isn't entirely functional yet.
I now want to put the players and their respective scores into a leaderboard on an android app in android studio. When I'm trying to put them into a hashmap using the following code:
String code = "2143"; //This is would be the SessionID, it's currently static for testing purposes.
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference(code);
HashMap<String, String> leaderboardMap = new HashMap<>();
...
myRef.orderByValue().addValueEventListener(new ValueEventListener()
{
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot)
{
leaderboardMap.put(dataSnapshot.getKey(), dataSnapshot.getValue().toString());
}
}
I get the following hashmap
key: 2143, value:{Henk=6, message=1}
However I expected the following:
key: Henk, value: 6
key: message, value: 1
Where's the error in my code, and how can I fix it?
You can convert the json string to HashMap and then use those values to display in leaderborad. Here is a function to convert json sring to map.
public static HashMap<String,String> jsonToMap(String t) throws JSONException {
HashMap<String, String> map = new HashMap<String, String>();
JSONObject jObject = new JSONObject(t);
Iterator<?> keys = jObject.keys();
while( keys.hasNext() ){
String key = (String)keys.next();
String value = jObject.getString(key);
map.put(key, value);
}
return map;
}

Why does my firebase database child return null?

I am working with firebase database and i was trying to get the value of a child using this code below and may System.out.println(MyCredit.toString()); is always returns null: Please see my firebase database
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Users");
ref.addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Get map of users in datasnapshot
CollectCredits((Map<String,Object>) dataSnapshot.getValue());
}
#Override
public void onCancelled(DatabaseError databaseError) {
//handle databaseError
}
});
private void CollectCredits(Map<String,Object> users) {
MyCredit = new ArrayList<>();
//iterate through each user, ignoring their UID
for (Map.Entry<String, Object> entry : users.entrySet()){
//Get user map
Map singleUser = (Map) entry.getValue();
//Get Credit field and append to list
MyCredit.add((Long) singleUser.get("Credit"));
Toast.makeText(MainActivityCustonlistViewnew.this, "Credit : " +String.valueOf(MyCredit), Toast.LENGTH_SHORT).show();
}
System.out.println(MyCredit.toString());
}
Try this:
private void CollectCredits(DataSnapshot dataSnapshot) {
MyCredit = new ArrayList<>();
//iterate through each dataSnapshot
for (DataSnapshot d1 : dataSnapshot.getChildren()){
MyCredit.add(d1.getValue());
}
}
Let me give you some suggestions, Try to check your firebase database path both the root and child path because some time you did everything correctly but the path you specified to your Database reference which is not referring to the correct path. So it can produce the same result what are getting right now.

How to loop through data in Map with Java

Fetched data from Firebase database and added as a Map object. now I need to loop through every key's value so I can get child data from it. here are my both Database structure and the code am using:
public void gettingStationDate() {
// Read from the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("station");
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
Log.e(TAG, "Value is: " + map);
assert map != null;
for (Map.Entry<String, Object> entry : map.entrySet()) {
Log.e("The Result", entry.getKey() + "/" + entry.getValue());
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});
}
this code give me the result as key, value like this : -LlRGuwBNe2-S_MHn2DW/{station_longitude=30.854333, station_name=الاصلاح الزراعى, station_latitude=29.313847, station_geohash=stjyy07mw14h} Now what i need to do is to get the inner values of the shown values , as statin_longitude , station_name etc..
Since each child node that you have is another JSON object, each value in your Map is another Map. And since all your values are strings, this time it's a Map<String,String>.
So to get the specific values, you'd do something like:
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
assert map != null;
for (Map.Entry<String, Object> entry : map.entrySet()) {
Log.i("The key", entry.getKey());
Map<String,String> values = (Map<String,String>) entry.getValue();
Log.i("station_name", map.get("station_name"));
}
}
It is more idiomatic to use the DataSnapshot's method to accomplish the same:
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot stationSnapshot: dataSnapshot.getChildren()) {
Log.i("The key", stationSnapshot.getKey());
Log.i("station_name", stationSnapshot.child("station_name").getValue(String.class));
}
}

Filter results by an Edit Text

In my ExploreFragment.java I have an EditText which basically allows the user to search country names that are stored in my Firebase Realtime Database.
What I want to achieve is, when the user types something in the EditText and then presses "submit" in their keyboard, it makes a query that retrieves every country which has the string they typed in their name, and get redirected to my fragment FilteredResultsFragment.java which displays the names of the countries retrieved. My fragment has a recycler view with an Adapter.
I haven't achieved this yet. I need to retrieve a List with the urls and a List with the names.
The query should look like this:
FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
Log.d("TAMANHO","size = "+paisEscolhido.size());
for (int i = 0; i<paisEscolhido.size(); i++) {
Log.d("CONTINETNE","size = "+paisEscolhido.get(i));
DatabaseReference paisNomeContinentes = mDatabase.getReference().child("paises");
Query queries = paisNomeContinentes.orderByChild("Continente").equalTo(paisEscolhido.get(i));
queries.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
List<String> imagemPaisList = new ArrayList<>();
List<String> nomePaisList = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String imagemPais = ds.child("Imagem").getValue(String.class);
String nomePais = ds.child("Nome").getValue(String.class);
imagemPaisList.add(imagemPais);
nomePaisList.add(nomePais);
}
int urlCount = imagemPaisList.size();
// int randomImage = new Random().nextInt(urlCount);
for (int i = 0; i < nomePaisList.size(); i++) {
Integer randomVariavel = new Random().nextInt(urlCount);
randomImagemPaisList.add(imagemPaisList.get(randomVariavel));
randomNomePaisList.add(nomePaisList.get(randomVariavel));
}
UPDATE
I've come up with this query:
FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
DatabaseReference paisNomeContinentes = mDatabase.getReference().child("paises");
Query queries = paisNomeContinentes.orderByChild("Nome").startAt("Po");
queries.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
List<String> imagemPaisList = new ArrayList<>();
List<String> nomePaisList = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String imagemPais = ds.child("Imagem").getValue(String.class);
String nomePais = ds.child("Nome").getValue(String.class);
imagemPaisList.add(imagemPais);
nomePaisList.add(nomePais);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
That should retrieve the Name of the country that starts with the value the user writes in my EditText but, when I write, for example "Po", it should give me "Portugal" and "Poland" but, instead, it gives me random images...
This is the data structure:
UPDATE V2
It actually gives me "Poland" and "Portugal" as the top results but it shows my more ImageView besides those two (and with random images too)...
If you want to use startAt() to filter your data you also have to use endAt() because startAt() works as a starting point for your query and not a filter. By adding \uf8ff (the last unicode character) behind your searchstring in endAt() you limit your query to get only the values that start with your searchstring:
Query queries = paisNomeContinentes.orderByChild("Nome").startAt("Po").endAt("Po" + "\uf8ff");
Just remember this will only get the items that start with the searchstring, not the items that contain the searchstring.

Getting a child's name as well as the value in Firebase Database

In my Firebase Database I have data laid out as such:
paidRecord[
John Smith: UNPAID
Bill Smith: PAID
Mary Smith: UNPAID
]
I am trying to create a String in my app that will display the paid status of all the people. At the moment all I have is a String that displays "UNPAID PAID UNPAID" but what I need is to display the users names as well.
Here is the function:
private void checkPaidStatus(){
paidString = "";
FirebaseDatabase.getInstance().getReference("Flats").child(flatID).child("Bills").child(itemSelected).child("paidRecord").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot != null){
Iterator<DataSnapshot> iterable = dataSnapshot.getChildren().iterator();
//this is the bit that needs to be changed to return properly xd good luck
for (Iterator<DataSnapshot> it = iterable; it.hasNext();){
DataSnapshot dataSnapshot1 = it.next();
paidString = paidString + "new" + dataSnapshot1.getValue(String.class);
textViewPaidStatus.setText(paidString);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
So, is there a way on Firebase Database to return not only the value assigned to a key, but the key itself as well?
Actually, your key is also available in your sub-DataSnapshot just you need to get like bellow
DataSnapshot dataSnapshot1 = it.next();
paidString = paidString + "new" + dataSnapshot1.getValue(String.class);
textViewPaidStatus.setText(paidString);
String mStrkey=dataSnapshot1.getKey()

Categories