I'm currently new to Firebase.
I put a key in-->> user->answer->key->true
and then I used this :
Firebase re = New Firebase(blabla..user->answer);
refLoadId_Question_Question.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> newPost = (Map<String, Object>) dataSnapshot.getValue();
System.out.println("Id_question1: " + dataSnapshot.getValue());
System.out.println("Id_question1: " + dataSnapshot.getChildren().toString());
list_id_question.add(dataSnapshot.getKey());
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
I receive : Id_question1: {-Ja3RTtq5DMGIdVF9-pC=true} in dataSnapsho.getValue();
my Question is it Possible to get key Value from Object type in java? I want to get this value :-Ja3RTtq5DMGIdVF9-pC
anyone Please help?
Thanks..
You need to iterate over the children:
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
System.out.println(childSnapshot.getKey());
}
Alternatively you could also listen for children, instead of the entire answer object:
refLoadId_Question_Question.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot childSnapshot) {
System.out.println(childSnapshot.getKey());
}
}
The latter is going to be simpler when you start to deal with data synchronization instead of just just pulling down the initial data.
Say you have two people using your application:
the first user is viewing a question and (for the sake of this example) its two answers
the second user is providing a third answer to the same question
Initially the first user will download the question and the two answers. Then when the second user provide a third answer, your initial code will (likely) re-download all three answers. The second example will only be called for the new answer.
I'm Currently used this code to get the ID.
but I didn't try it if the ID question is more than one
if (dataSnapshot.getValue() != null) {
Map<String, Object> newPost = (Map<String, Object>) dataSnapshot.getValue();
String ID_Question = newPost.keySet().toString().replace("[", "");
ID_Question = ID_Question.replace("]", "");
System.out.println("Id_question1: " + ID_Question);
list_id_question.add(ID_Question);
}
Related
I am working on an app for a hotel, which enables hotel management to report and view concerns and issues. I am using Android and Firebase for this app.
Here is the database structure of a reported concern:
To minimize data download and optimize speed, I am adding "Active" and "Resolved" nodes in the database, like below:
Now, the hotel wants me to add the function to create an Excel report of concerns closed/resolved within the past month. For this, I will be attaching a Single Value Event Listener on the "resolved" node, get keys of resolved concerns, then for each key, fetch data from "allConcerns" node, store each node's data into an ArrayList of String. After which I will use this JSON to Excel API for Android to create Excel file.
I am able to access keys of resolved concerns with this code:
DatabaseReference resolvedReference = FirebaseDatabase.getInstance().getReference()
.child(getApplicationContext().getResources().getString(R.string.concerns))
.child(getApplicationContext().getResources().getString(R.string.resolved));
final ArrayList<String> keys = new ArrayList<>();
resolvedReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
//Getting keys of all resolved concerns in keys arraylist here
for (DataSnapshot ds : snapshot.getChildren()){
keys.add(ds.getValue(String.class));
}
//Storing JSON data in this arraylist
final ArrayList<String> data = new ArrayList<>();
for(int i = 0; i<keys.size() ; ++i){
String key = keys.get(i);
//Getting data of each concern here
FirebaseDatabase.getInstance().getReference().child(getApplicationContext().getResources().getString(R.string.allConcerns))
.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
String type = snapshot.child("type").getValue().toString();
Log.i("Type", type);
if(type.equals("0")) {
SafetyConcernClass s = snapshot.getValue(SafetyConcernClass.class);
Log.i("Snapshot of key", s.toString());
data.add(s.toString());
}
else{
GembaWalkClass g = snapshot.getValue(GembaWalkClass.class);
Log.i("Snapshot of key", g.toString());
data.add(g.toString());
}
Proof proof = snapshot.child("proof").getValue(Proof.class);
Log.i("Proof", proof.toString());
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
//Issue I am facing is here
Log.i("Data size", String.valueOf(data.size()));
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
The real issue here is while logging data.size(). Since Firebase is asynchronous, FOR loop ends before data is fetched and entered into the data ArrayList, hence it gives me a size of 0. And since no data is fetched, I can't create an Excel file.
My question is, how can I make sure I am proceeding to log data.size() ONLY after data of respective resolved concerns is stored in the ArrayList?
The typical approach is to keep a counter or a countdown latch to track how many of the concern snapshots you've already downloaded. Once the counter reaches keys.size() you know that you're done.
Also see Setting Singleton property value in Firebase Listener
You should write your method
addListenerForSingleValueEvent
using AsyncTask or Kotlin coroutines
and in onPostExecute() of AsyncTask, you can proceed to further action.
I am learning how realtime databases work, so be patient.
To better explain my doubt, I take an image showing the relevant part of the realtime database
https://prnt.sc/p0wmvs
All I want is the best way to update the field "name" of a record "grps".
The starting point is the "usrs" table where I can reference
mFD.getReference("usrs/"+user.getUid()+"/asAdm/grps/"+grpId)
My function to update "name" of group name
public void editGroupFromUser(long grpID, Group group, final DataStatus dataStatus) {
DatabaseReference mFRUser = mFirebaseDatabase.getReference(
"usrs/"+user.getUid()+"/asAdm/gprs/"+grpID
);
mFRUser.child("grp").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String groupKey = (String) dataSnapshot.getValue();
DatabaseReference mFRGroup = mFirebaseDatabase.getReference("grps");
mFRGroup.child( groupKey ).setValue(group).addOnSuccessListener(aVoid -> {
dataStatus.DataIsUpdated();
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
The need to receive the group key to then send the group update. This does not seem efficient at all.
Also, the need to send the user Uid key when the user is identified in firebase does not seem safe at all.
Is there any better way to do this?
I have structure for database in this manner
-... location
-... messages
-... id1_id2
-... id3_id4
-... id5_id6
.
.
.
How can I access a object in messages where I just know id1 which is the key.
TIA.
Change your database to this:
Messages
userid1
userid2
message: hello
then to retrieve message, do this:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Messages").child(userid1);
ref.addListenerForSingleValueEvent(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot){
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String messages=ds.child("message").getValue().toString();
}
}
});
Try this one
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("location/messages");
ref.addListenerForSingleValueEvent(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot){
for (DataSnapshot ds : dataSnapshot.getChildren()) {
if(ds.getKey().contains("bob")){
//Do something with the date
break;
}
}
}
});
Suppose your structure is like this:
You can do something like this, this will grab all nodes from messages that start with id1:
String id1 = "id1";
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("messages");
ref.orderByKey().startAt(id1).endAt(id1 + "\uf8ff").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snap : dataSnapshot.getChildren()) {
Log.d("SNAP", snap.getValue(String.class));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I took the idea from the javascript implementation, but it also worked in Android, I've run a test on my device/database. Note that this method will work to grab data that starts with the given id.
EDIT:
The idea of querying firebase data that contains a certain string is discussed in this official post. Also, this question as well. The bottom line is that the api doesn't support these types of queries, the approach I mentioned above is the closest you can get of implementing a "SQL LIKE" in firebase. Currently, there's no way of searching for strings that END with another string. The endAt doesn't mean the string ends with id1, but rather that the range of values I want to retrieve finishes at (id1 + "\uf8ff"), that means any string starting with id1.
Your options are either change the schema or grab all messages and search locally (the suggestions of the other two answers).
I'm using Firebase in my Android Project. I have a ValueEventListener and it keeps on getting the old value even the node is already modified by other devices. It seems like it is disregarding the updates made by other devices.
Here's my code:
ValueEventListener listener = destinationDatabaseReference.child(somestring)
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.getValue()==null)
{
}
else
{
//here I keep on getting the old value
string value = (long) dataSnapshot.child("someString").getValue();
}
}
use the query like this:-
Query query = mDatabase.getReference().child("posts").orderByChild("date").limitToLast(1);
query.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if(dataSnapshot!=null){
String notific = String.valueOf(dataSnapshot.getValue());
Log.d("key",dataSnapshot.getKey());
Log.d("title",String.valueOf(dataSnapshot.child("title").getValue()));
Log.d("content",String.valueOf(dataSnapshot.child("content").getValue()));
}
}
Thanks guys for all the help. I tried your suggestions but it did not work for me :(
However, I found this link and I would like to share just in case someone needs it.
For this kind of issue, you have to use Transaction Operations. Please see related useful links below:
Updating firebase data in several devices by Transaction Operations
Similar Question with Working Answer
Try to use a final reference like this:
URL url = new URL(yourURL);
final Firebase root = new Firebase(url.toString());
root.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) DataSnapshot dataSnapshot) {
if(dataSnapshot.getValue()==null)
{
}
else
{
//here I keep on getting the old value
string value = (long) dataSnapshot.child("someString").getValue();
}
}
this is my first time asking question on stackoverflow.
I'll just go straight to the point, I'm currently developing an application which involve creating a chat room using firebase, I found this
https://www.youtube.com/watch?v=uX6_w6yhj4E
and decided to follow him. Everything was going smoothly until i finish the code and tries to run it. Everything functioned as expected except the send button that was suppose to display my message in the chat room. My send button didn't respond even though i tap on it. I can't seem to find the problem.
Here is my code for the chat_room:
public class Chat_Room extends AppCompatActivity {
private Button btn_send_msg;
private EditText input_msg;
private TextView chat_conversation;
private String user_name, room_name;
private DatabaseReference root;
private String temp_key;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_room);
btn_send_msg = (Button) findViewById(R.id.btn_send);
input_msg = (EditText) findViewById(R.id.msg_input);
chat_conversation = (TextView) findViewById(R.id.textview);
user_name = getIntent().getExtras().get("user_name").toString();
room_name = getIntent().getExtras().get("room_name").toString();
setTitle(" Room - "+room_name);
root = FirebaseDatabase.getInstance().getReference().child(room_name);
btn_send_msg.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
Map<String,Object> map = new HashMap<String, Object>();
temp_key = root.push().getKey();
root.updateChildren(map);
DatabaseReference message_root = root.child(temp_key);
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("name",user_name);
map2.put("msg",input_msg.getText().toString());
//message_root.updateChildren(map2);
message_root.setValue(map2);
}
});
root.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
append_chat_conversation(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
append_chat_conversation(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private String chat_msg, chat_user_name;
private void append_chat_conversation(DataSnapshot dataSnapshot){
Iterator i = dataSnapshot.getChildren().iterator();
while (i.hasNext()){
chat_msg = (String) ((DataSnapshot)i.next()).getValue();
chat_user_name = (String) ((DataSnapshot)i.next()).getValue();
chat_conversation.append(chat_user_name +" : "+chat_msg+"\n");
}
}
}
Let me know if I did something wrong or if the information provided was not enough, really appreciate for the help as I'm still a rookie in both android studio and firebase. Thanks in advance.
Welcome to stack!! :)
Update only updates data, if there is not data to update in the database then nothing will happen.
Your first update will do nothing.
Map<String,Object> map = new HashMap<String, Object>();
temp_key = root.push().getKey();
root.updateChildren(map);
The map is empty and nothing will be updated because, well, the map is empty.
The second update, will also do nothing and this is why
DatabaseReference message_root = root.child(temp_key);
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("name",user_name);
map2.put("msg",input_msg.getText().toString());
message_root.updateChildren(map2);
Here you made a reference to the child with the push key. Push keys are unique and no two push keys will ever be the same. So when you make a databaseReference to the 'message_root'. That Database reference does not exist at that point. So the attributes, "name" and "msg" do not exist in the database reference and therefore cannot be updated.
That is why you see nothing. To fix it, try this
//message_root.updateChildren(map2);
message_root.setValue(map2);
Instead of updating the message_root. Set the value instead. You have to set the value because the message_root does not exist and by calling setting value you set its existence if that makes sense.
[EDIT]
Try confirming that at least something can be posted to your database.
In your on create method create a map and push that map to your database.
If nothing is reflected, I can only assume that one of two things has happened. You have set up Firebase incorrectly(have you added your google-services json) or your security rulesare set to only alound writes from authenticated users.Make sure your security rules are open. I think the security rules are the most likely cause.
Go to the Firebase console. Go to the database and click on Rules. Make sure your rules look like this.
{
"rules": {
".read": true,
".write": true
}
}
Copy and pase those rules and post them in directly.