My firebase data looks like these:
"worldwide" : [{
"key1" : {
"movie_id": 100,
"release_date": 1524182400000,
"description": "Cool movie here"
},
"key2" : {
"movie_id": 101,
"release_date": 1525046400000,
"description": "Plot is cool"
}
}]
"europe" : [{
"key1" : {
"movie_id": 100,
"release_date": 1516798528489,
"description": "Cool movie here"
},
"key3" : {
"movie_id": 102,
"release_date": 1525046400000,
"description": "Cool plot"
}
}]
Note: Both lists are inside a man list called releases
I've been trying for the past hours to query my data in java/android so that both data in both list join together to make one complete list with the movies ordered by release_date (which are in milliseconds) and for the duplicate entries I want the release_date information in the Europe array to take priority, so if the movie_id is in both list and it has a different release date in the worldwide array and the Europe array, I want the entry in the Europe array to be saved in in the complete list. For example, "movie_id": 100 appears in both list. Thank you.
My java code:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = null; // I don't know how to structure my query
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot movie: dataSnapshot.getChildren()) {
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Any tips would be appreciated, like I'd like to hear if there's any better method to accomplish what I want.
First and foremost, you need to make sure that your database has the correct .indexOn rules. This will ensure that you can query/sort your data.
Next, you can add the Query to the database reference:
firebase::database::Query query =
reference.GetReference("worldwide").OrderByChild("release_date");
Finally, Read up on the Sorting/Query from the documentation.
To merge the two lists, just run two queries and add the movies into a concurrent list. Then sort the list.
There is no construct in Firebase to read data from both lists with one query. This means that you will have to:
either use two listeners (one on worldwide and one on europe) and merge the results from those listeners in the client.
or use a single listener at the node above worldwide and europe and then iterate over the resulting snapshot.
The latter is simpler in code, but might be less efficient.
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot movie: dataSnapshot.getChild("europe").getChildren()) {
System.out.println(movie.getKey()+": "+movie.getChild("movie_id").getValue());
}
for (DataSnapshot movie: dataSnapshot.getChild("worldwide").getChildren()) {
System.out.println(movie.getKey()+": "+movie.getChild("movie_id").getValue());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw new databaseError.toException();
}
});
Related
I am new in firebase, I want to sort data, by timestamp and my database is below, here key is timestamp
My code for retrieving data is below
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("MainDoor");
Query dataOrderedByKey = myRef.orderByChild("{pushId}/key");
dataOrderedByKey.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, MyListData> value = ((HashMap<String, MyListData>) dataSnapshot.getValue());
Here i am getting value is not by order of key
I am getting data like below which is not in sort order
Data in a Map is by definition not sorted. So when you call dataSnapshot.getValue(), all information about the order of the items in the DataSnapshot is list.
To maintain the order, use a data structure that supports that, such as a list, and extract the individual items in the correct order by looping over DataSnapshot.getChildren().
So something like:
dataOrderedByKey.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
System.out.println(snapshot.getKey());
MyListData value = snapshot.getValue()
}
}
...
Also you can get data from firebase in sorted order . Refer my answer at Sort Firebase data in ascending/Descending Order
You want to sort by date, right? Try it
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("MainDoor");
myRef.orderByChild('date').addChildEventListener(new ChildEventListener() {
// implement the ChildEventListener methods as documented above
});
Because of the way JavaScript objects work, the ordering of data in the JavaScript object returned by val() is not guaranteed to match the ordering on the server nor the ordering of child_added events. That is where forEach() comes in handy. It guarantees the children of a DataSnapshot will be iterated in their query order.
// Assume we have the following data in the Database:
{
"users": {
"ada": {
"first": "Ada",
"last": "Lovelace"
},
"alan": {
"first": "Alan",
"last": "Turing"
}
}
}
// Loop through users in order with the forEach() method. The callback
// provided to forEach() will be called synchronously with a DataSnapshot
// for each child:
var query = firebase.database().ref("users").orderByKey();
query.once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
// key will be "ada" the first time and "alan" the second time
var key = childSnapshot.key;
// childData will be the actual contents of the child
var childData = childSnapshot.val();
});
});
I have a firebase database that is loaded via Async, and I can verify that all data exists in the correct nodes, but for some reason I can't figure out how to call for the data stored in the particular node.
I've tried .addChildEventListener and .addValueEventListener, but nothing seems to allow for my global object to be loaded with the details at the particular node.
Here's a quick snapshot of json looks like for each node.
{
"movies" : {
"297802" : {
"movieBackdrop" : "/5A2bMlLfJrAfX9bqAibOL2gCruF.jpg",
"movieFavorite" : 0,
"movieID" : 297802,
"movieLanguage" : "en",
"movieOverview" : "Once home to the most advanced civilization on Earth, the city of Atlantis is now an underwater kingdom ruled by the power-hungry King Orm. With a vast army at his disposal, Orm plans to conquer the remaining oceanic people -- and then the surface world. Standing in his way is Aquaman, Orm's half-human, half-Atlantean brother and true heir to the throne. With help from royal counselor Vulko, Aquaman must retrieve the legendary Trident of Atlan and embrace his destiny as protector of the deep.",
"moviePopularity" : 116,
"moviePosterPath" : "/5Kg76ldv7VxeX9YlcQXiowHgdX6.jpg",
"movieReleaseDate" : "2018-12-07",
"movieTitle" : "Aquaman",
"movieVoteAverage" : 6.8,
"movieVoteCount" : 3668
},
"299536" : {
"movieBackdrop" : "/bOGkgRGdhrBYJSLpXaxhXVstddV.jpg",
"movieFavorite" : 0,
"movieID" : 299536,
"movieLanguage" : "en",
"movieOverview" : "As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his goal is to collect all six Infinity Stones, artifacts of unimaginable power, and use them to inflict his twisted will on all of reality. Everything the Avengers have fought for has led up to this moment - the fate of Earth and existence itself has never been more uncertain.",
"moviePopularity" : 109,
"moviePosterPath" : "/7WsyChQLEftFiDOVTGkv3hFpyyt.jpg",
"movieReleaseDate" : "2018-04-25",
"movieTitle" : "Avengers: Infinity War",
"movieVoteAverage" : 8.3,
"movieVoteCount" : 11448
},
I've created my Firebase Database with the movieID being the key value, rather than the generated values, since my ids will always be unique.
Now when I try to get the snapshot stored as my object via the below method, I keep getting a null error pointing to my object currentMovie when I try to extrapolate some of the objects data to update the UI. I know that when I am checking for .equalTo(String.valueOf(movieID) - it is passing a value that correlates to a valid value that should match up correctly, but I keep getting the null error.
mFirebaseDatabase = FirebaseDatabase.getInstance();
mMovieDatabaseReference = mFirebaseDatabase.getReference().child("movies");
Query movieQuery = mMovieDatabaseReference.orderByChild("movieID").equalTo(String.valueOf(movieID));
movieQuery.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
currentMovie = dataSnapshot.getValue(Movie.class);
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Any thoughts or ideas on why I'm having so much difficulty here?
You're comparing strings and integers.
In your JSON it shows that movieID is a numeric value:
"movieID" : 297802
In the code you do:
mMovieDatabaseReference.orderByChild("movieID").equalTo(String.valueOf(movieID))
So that means you're comparing integers and strings, which always returns false. The solution is to compare numbers with numbers:
mMovieDatabaseReference.orderByChild("movieID").equalTo(movieID)
I wanted to retrieve filtered data from db according to extra_Cat value like 31
I am able to retrieve full data easily but unable to put filter in it
Note: I have checked almost every solution, If duplicate please reply then tag duplicate
my code is
DBConnection dbConnection=new DBConnection();
postRef=dbConnection.database.getReference("Data");
postRef.child("extra_Cat").orderByKey().equalTo("*31*").limitToLast(500).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
long as= dataSnapshot.getChildrenCount();
Log.d("Data", String.valueOf(as));
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
}
});
and JSON is
"32161" : {
"author_name" : "Talented+Desk",
"cat_ID" : "%2A7%2A",
"cat_name" : "%E0%A4%96%E0%A5%87%E0%A4%B2",
"content" : "A4%B5A4%A8%E0%A4%BF%E0%A4%AF%E0%A4%AE+%E0%A4%B9%E0%A5%88%E0%A4%82%7C%E2%80%9D%3C%2Fp%3E%0A",
"extraCat" : [ "*31*", "*14*" ],
"fea_image" : "https%3A%2F%2Fwww.talentedindia.co.in%2Fwp-content%2Fuploads%2F2018%2F03%2Faajeevan-pratibandh-Steve-Smith.jpg",
"post_comment" : "0%A4%BF%E0%A4%AF%E0%A5%8B%E",
"post_date" : "2018-03-26",
"post_id" : "32161",
"post_slug_name" : "kangaroos-protest-against-less-punishment",
"post_status" : "publish",
"post_time" : "10%3A45%3A40",
"post_video" : "",
"slider_image1" : "",
"slider_image2" : "",
"slider_image3" : "",
"slider_image4" : "",
"title" : "%E0%A4%94%B8%E0%A4%9C%E0%A4%BE+%E0%A4%AA%E0%A4%B0+%E0%A4%B5%E0%A4%BF%E0%A4%B0%E0%A5%8B%E0%A4%A7"
},
You cannot create a query based on values that exist within an array. As I see in your database, extraCat is an array which contains 2 values, *31* and *14*.
In order to solve this, you need to change your database structure a little bit. So your extraCat node should look like this:
extraCat
|
--- "*31*": true
|
--- "*14*": true
As you can see, the extraCat node the is now a Map. The corresponding query should look like this:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query query = rootRef.child("Data")
.orderByChild("extra_Cat/*31*")
.equalsTo(true)
.limitToLast(500)
.addValueEventListener(/* ... */)
First you are using wrong reference path. The current you are using is Data/extra_cat. As I see in your Firebase structure it should be Data/32343/extraCat.
You can't use .child("extra_Cat").orderByKey().equalTo("*31*") because the *31* is not of the extra_Cat keys value. The value is in the list.
Hi I have 2 arrays like
phonenumber[1,2,3]
amount[10,20,30]
I need to store the data in a single document like
field1: 1
field2: 10
The code I tried is
I took the object like
**
public class Pojo {
String invitee;
Map<Integer,Integer>phoneAmount;
public Pojo(String invitee, Map<Integer, Integer> phoneAmount)
{
this.invitee = invitee;
this.phoneAmount=phoneAmount;
}
}**
And in another class
Map<int[], int[]> phoneAmount = new HashMap<>();
phoneAmount.put(phonenumber,amount);
db.collection("Split").document("invitees").set(phoneAmount).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "DocumentSnapshot successfully written!");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Error writing document", e);
}
});
It shows error like
java.lang.RuntimeException: Could not serialize object. Maps with non-string keys are not supported
at com.google.android.gms.internal.zzejw.zza(Unknown Source)
at com.google.android.gms.internal.zzejw.zza(Unknown Source)
at com.google.android.gms.internal.zzejw.zzbp(Unknown Source)
From the official documentation:
Although Cloud Firestore can store arrays, it does not support querying array members or updating single array elements.
This approach is one that I personally don't recommend it to be used. One of the many reasons also Firebase recommends against using arrays is that it makes the security rules impossible to write.
However, you can still model this kind of data by leveraging the other capabilities of Cloud Firestore.
Let's take an example. Suppose you have a database which look like this:
{
title: "My Book",
categories: [
"science",
"computer science",
"technology"
]
}
You need to know that if you want to query for all books that are part of the "science" category, using this data structure, there is no way to perform this query.
To solve this, you can consider an alternative data structure, where each category is the key in a map and all values are true.
{
title: "My Book",
categories: {
"science": true,
"computer science": true,
"technology": true
}
}
And to query your database you can use this query:
db.collection("books")
.whereEqualTo("categories.science", true)
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {/* ... */});
For your particular case, you can use a database structure that looks like this:
{
title: "phonenumber",
categories: {
"12345": true,
"67890": true,
"43215": true
}
}
To query, please use the following code:
db.collection("phonenumbers")
.whereEqualTo("categories.12345", true)
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {/* ... */});
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.
I am trying to retrieve the Restaurant Name data from Firebase and output them in individual lines on ListView. I created a sample of the data which only consists of numbers(strings).
Retrieving the data seems fine as I could output them line by line in console, but my Hashmap is saving everything into the same "node" or "field"
Can anyone help me understand what I did wrong?
#Override
public void onDataChange(DataSnapshot Snapshot) {
int x = 1;
//Do some stuff once
for (DataSnapshot RestNames : Snapshot.getChildren()) {
name = RestNames.getValue().toString();
//System.out.println(name);
map.put(x, name);
x=x+1;
}
System.out.println(map);
Items.add(map);
System.out.println(Items);
listView.setAdapter(mgadapter);
}
The Output in the console is as follows :
{8=3456, 11=9, 9=34567, 5=3, 3=3, 4=4, 10=0, 1=1, 7=345, 6=34, 2=2}
Android emulator shows the same value for every single row.
I want to display each value on a separate row.
Thank you!
EDIT: SNIPPET OF JSON
{
"Eat": {
"Name": {
"-Jy3yehAkgqhg4knlxx_": "1",
"-Jy3yjQT2AxtZMqD2kov": "2",
"-Jy3yk96Mo5MKOEEzviJ": "3",
"-Jy3yksamL08R0BckxNZ": "4",
"-Jy5JBJYZUTxZQtmdDmi": "3",
"-Jy5JIXT_lDZrUOkF3T1": "34",
"-Jy5JJ0oMqGrs2vfFge2": "345",
"-Jy5JJTyET830PYOT3yA": "3456",
"-Jy5JJu-jDGMDXncWDKf": "34567",
"-Jy5JVejdsUtggM8vBoi": "0",
"-Jy5JbwEoWrKAi6XIVQY": "9"
}
}
}
Since we're missing some code in your snippet, I completed it an ran it locally:
Firebase ref = new Firebase("https://stackoverflow.firebaseio.com/32367022/Eat/Name");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
int x = 1;
Map<Integer,Object> map = new HashMap<Integer, Object>();
for (DataSnapshot child: snapshot.getChildren()) {
String name = child.getValue().toString();
System.out.println(name);
map.put(x, name);
x=x+1;
}
System.out.println(map);
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
This prints out the following for me:
1
2
3
4
3
34
345
3456
34567
0
9
{1=1, 2=2, 3=3, 4=4, 5=3, 6=34, 7=345, 8=3456, 9=34567, 10=0, 11=9}
The first lines show the output from inside the for loop. The last lines shows the HashMap.
I use the most basic of Java classes, and this behavior seems correct to me.
I expect that the System.out.println(name); inside the for loop will display the same output as above for you, because the Firebase SDK handles ordering there.
If the order in the loop is correct, either your map or your Items object changes the order. It is impossible to say without seeing the types of these.
But in general, the approach above is how you should troubleshoot this problem: isolate it to a single object/class and then either fix what's wrong with that class (if it's your code) or replace it with a class that works for your use-case (if it comes from a library).
Update: I created a minimal app that shows the numbers in the correct order in a list view in this Github repo.