Retrieve multiple data in recycler view using FirebaseRecyclerOptions - java

I am using FirebaseRecyclerOptions in calling the database, however, I cannot get all of the data in the database. Here is the structure of the database: database structure the yellow underline is the user id (UID) and below is another node that contains the data that I want to retrieve in the RecyclerView.
Here is a snippet of the code
FirebaseRecyclerOptions<RegisterParking> options =
new FirebaseRecyclerOptions.Builder<RegisterParking>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("RegParkingArea"), RegisterParking.class)
.build();
voPListAdapter = new VoPListAdapter(options);
recyclerView.setAdapter(voPListAdapter);

When you're passing the following two arguments to the setQuery() method:
.setQuery(FirebaseDatabase.getInstance().getReference().child("RegParkingArea"), RegisterParking.class)
It means that the adapter expects to render on the screen RegisterParking objects. If you take a closer look at your database schema, under the RegParkingArea node, you can find UIDs and not RegisterParking objects. The objects that you want to display in the RecycerView exist under each UID. So when reading the data from the database, the Firebase-UI library tries to map each child under the above reference into an object of type RegisterParking, which is actually not possible since the UIDs are strings.
So if you're allowed to change the database schema, then you should either denormalize the data, basically copying the data under another node, or change the actual data into:
db-root
|
--- RegParkingArea
|
--- $pushedId
|
--- uid: "4u9h...XrP2"
|
--- //other fields.
What I have basically done, I have removed a level from the database tree. If you'll use this schema, then you can leave the code as it is and everything will work perfectly fine.
One more thing to note is that if you need to get all parking of a particular user, then you can use the following query:
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
Query queryByUid = db.child("RegParkingArea").orderByChild("uid").equalTo(uid);

Related

Save button deletes previous data in firebase

I am new to android studio and firebase. I am trying to save a list of people to firebase like this. Idea is that the logged in user should be able to save information about some people.
String userId = user.getCurrentUser().getUid();
databaseReference.child("users").child(userId).child("savedPersons").child("name").setValue(nameTxt);
databaseReference.child("users").child(userId).child("savedPersons").child("surname").setValue(surnameTxt);
databaseReference.child("users").child(userId).child("savedPersons").child("gender").setValue(genderTxt);
databaseReference.child("users").child(userId).child("savedPersons").child("ageTxt").setValue(ageTxt);
It does not surprise me that it deletes the previous saved person when i save another one but i don't know how to save all of them. I have this in my firebase but i need multiple saved users. How do i do it ?
Firebase screenshot
If you want to save multiple people in a list in the database, you'll want to call push:
String userId = user.getCurrentUser().getUid();
DatabaseReference newRef = databaseReference.child("users").child(userId).child("savedPersons").push(); // 👈
newRef.child("name").setValue(nameTxt);
newRef.child("surname").setValue(surnameTxt);
newRef.child("gender").setValue(genderTxt);
newRef.child("ageTxt").setValue(ageTxt);
This will create a new child node under savedPersons each time you call push(). To learn more on this, see the Firebase documentation on appending data to a list.
Note that calling setValue for each property is wasteful, and may lead to unexpected behavior down the line. I recommend putting all values in a map, and then adding them all with one call to setValue:
Map<String, Object> values = new Map<>();
values.put("name", nameTxt);
values.put("surname", surnameTxt);
values.put("gender", genderTxt);
values.put("ageTxt", ageTxt);
newRef.setValue(values);

I need to get a query of children of undetermined parents

I am making a SearchView in the search bar to filter all processes that started or ended within a certain date.
I need to get a query of nodes inside processes and codes.
Here is my data structure and what I need to query:
I'm using this for the codes as an example:
//path of all posts
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("codes");
//get all data from this ref
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot ds: snapshot.getChildren()) {
String hola = Objects.requireNonNull(ds.getValue()).toString();
if (ds.hasChild("process")) {
for (DataSnapshot dsa: ds.getChildren()) {
System.out.println("result"+dsa);
/* if (!isEmpty(Objects.requireNonNull(dsa.child("ended").getValue()).toString())) {
System.out.println("result: "+dsa.child("ended").getValue().toString());
}
*/
}
But I need to obtain the node of other children, preferably without changing the data structure:
I have a FirebaseRecyclerOption where everything is loaded, and I need to only show the holders filtered from the SearchView.
If you're allowed to change the database schema, a more convenient way of storing the data would be to have a flattened structure like this:
Firebase-root
|
--- codes
|
--- $pushedId
|
--- code: 17240
|
--- proces: "Cajones"
|
--- user: "Jose Anton"
|
--- started: longNumberForStarted
|
--- ended: longNumberForEnded
Things I recommend:
Don't use sequential numbers as keys in the database. Use the unique random IDs that are generated by the push() method.
Don't store dates as strings, rather store them as timestamps.
In this way, you'll be able to filter the results as needed. And since you're using timestamps you'll be able to use startAt() or endAt() if you need.
Due to the formatting of the date in the string, it will not be possible to filter or sort the data on the server side. If it was formatted "yyyy.MM.dd a les HH:mm:ss" it would still be possible because they would be in order of magnitude, but arranged this way I can only imagine you reading all the nodes and reordering in a local list ( I don't think it's a good idea).
My suggestion is that you replace the format of this time field to something like a TIMESTAMP from the firebase itself with the server time or if they are custom times, convert them and re-store them.
If you do, you can create custom filters and order them on the server itself, as needed, using orderByChild(), orderByKey(), orderByValue(), limitToFirst(), limitToLast(), startAt(), startAfter(), endAt (), endBefore() and equalTo().

How to insert user current user details to another node in Firebase?

I am inserting a data in my Request Node in Firebase database in Android using this,
public void submitRequest(View v) {
Request myUserInsertObj = "Pending";
rootReference.child("Request").child("Pending").child(firebaseuser.getUid()).setValue
(myUserInsertObj);
}
This is my Request Class.
Public class Request{
public String request_status;
public Request(String request_status){
this.request_status = request_status;
}
Request()
}
I found in firebase documentation that I can use firebaseuser.getDisplayName to get the current logged in user's name. But where will the .getDisplayName get the user's name since I created my own login form and user registration in my app.
Question 2:
If I do this, is this possible? Because I want to put a name in requesting guest node so that when I retrieve it in my HTML web admin panel the data will be easier to read.
rootReference.child("Request")
.child("Pending")
.child(firebaseuser.getUid())
.setValue(myUserInsertObj + firebaseuser.getDisplayName);
If so what should I add in my Request Class?
Question 3.
How do I add timestamp I know timestamp is very important in data insertion on every system.
I found in firebase documentation that I can use firebaseuser.getDisplayName to get the current logged in user's name.
Yes, that correct. Calling getDisplayName() on a FirebaseUser object:
Returns the main display name of this user from the Firebase project's user database.
Regarding the second part of your question:
But where will the .getDisplayName get the user's name since I created my own log in form and user registration in my app.
As explained above, getDisplayName() is getting you the name that is coming from the authentication process. If you want to get the user name from your custom user object then you should first get the user object from the database and use it where it is needed.
Because I want to put a name in the request node so that when I retrieve it in my HTML web admin panel the data will be easier to read.
If you want to add the name in your node, you should pass the display name to the child() method and not to the setValue(). Your code should look like this:
rootReference.child("Request")
.child("Pending")
.child(firebaseuser.getUid() + "_" + firebaseuser.getDisplayName())
.setValue(myUserInsertObj);
This code will generate a child that might look like this:
Firebase-root
|
--- Request
|
--- Pending
|
--- SxbVg0...uobvk1_Theodore
|
--- //user details
DatabaseReference class has 4 overloaded setValue() methods but none of this methods allow you to pass an object along with a String as arguments.
Question 3. How do I add timestamp I know timestamp is very important in data insertion on every system.
This is how you add and get the timestamp that you were talking about.

Querying on Collection attribute in Corda

I'm trying to search value inside Corda unconsumed states on a collection Field.
I'm able to search on String field using -
Field uniqueAttributeName = MySchema.PersistentIOU.class.getDeclaredField("fieldname");
CriteriaExpression uniqueAttributeEXpression = Builder.equal(uniqueAttributeName, "valueToSearch");
QueryCriteria customCriteria = new QueryCriteria.VaultCustomQueryCriteria(uniqueAttributeEXpression);
result = rpcOps.vaultQueryByCriteria(customCriteria, MyState.class).getStates();
Above worked fine when "fieldname" is String but I have another field which is List and I'm not sure how to search inside List for a specific value.
Please assist.
After a quick chat with #Roger3cev, we think the best way is to amend your ORM wrapper such that you have a parent - child relationship between the state and the list of fields you want to have in that list. Once you do this, you can use the JDBC connection available to you to query against the child state and then use the relationship to the parent to get the Corda state.

How to store all user activites in a website..?

I have a web application build in Django + Python that interact with web services (written in JAVA).
Now all the database management part is done by web-services i.e. all CRUD operations to actual database is done by web-services.
Now i have to track all User Activities done on my website in some log table.
Like If User posted a new article, then a new row is created into Articles table by web-services and side by side, i need to add a new row into log table , something like "User : Raman has posted a new article (with ID, title etc)"
I have to do this for all Objects in my database like "Article", "Media", "Comments" etc
Note : I am using PostgreSQL
So what is the best way to achieve this..?? (Should I do it in PostgreSQL OR JAVA ..??..And How..??)
So, you have UI <-> Web Services <-> DB
Since the web services talk to the DB, and the web services contain the business logic (i.e. I guess you validate stuff there, create your queries and execute them), then the best place to 'log' activities is in the services themselves.
IMO, logging PostgreSQL transactions is a different thing. It's not the same as logging 'user activities' anymore.
EDIT: This still means you create DB schema for 'logs' and write them to DB.
Second EDIT: Catching log worthy events in the UI and then logging them from there might not be the best idea either. You will have to rewrite logging if you ever decide to replace the UI, or for example, write an alternate UI for, say mobile devices, or something else.
For an audit table within the DB itself, have a look at the PL/pgSQL Trigger Audit Example
This logs every INSERT, UPDATE, DELETE into another table.
In your log table you can have various columns, including:
user_id (the user that did the action)
activity_type (the type of activity, such as view or commented_on)
object_id (the actual object that it concerns, such as the Article or Media)
object_type (the type of object; this can be used later, in combination with object_id to lookup the object in the database)
This way, you can keep track of all actions the users do. You'd need to update this table whenever something happens that you wish to track.
Whenever we had to do this, we overrode signals for every model and possible action.
https://docs.djangoproject.com/en/dev/topics/signals/
You can have the signal do whatever you want, from injecting some HTML into the page, to making an entry in the database. They're an excellent tool to learn to use.
I used django-audit-log and I am very satisfied.
Django-audit-log can track multiple models each in it's own additional table. All of these tables are pretty unified, so it should be fairly straightforward to create a SQL view that shows data for all models.
Here is what I've done to track a single model ("Pauza"):
class Pauza(models.Model):
started = models.TimeField(null=True, blank=False)
ended = models.TimeField(null=True, blank=True)
#... more fields ...
audit_log = AuditLog()
If you want changes to show in Django Admin, you can create an unmanaged model (but this is by no means required):
class PauzaAction(models.Model):
started = models.TimeField(null=True, blank=True)
ended = models.TimeField(null=True, blank=True)
#... more fields ...
# fields added by Audit Trail:
action_id = models.PositiveIntegerField(primary_key=True, default=1, blank=True)
action_user = models.ForeignKey(User, null=True, blank=True)
action_date = models.DateTimeField(null=True, blank=True)
action_type = models.CharField(max_length=31, choices=(('I', 'create'), ('U', 'update'), ('D', 'delete'),), null=True, blank=True)
pauza = models.ForeignKey(Pauza, db_column='id', on_delete=models.DO_NOTHING, default=0, null=True, blank=True)
class Meta:
db_table = 'testapp_pauzaauditlogentry'
managed = False
app_label = 'testapp'
Table testapp_pauzaauditlogentry is automatically created by django-audit-log, this merely creates a model for displaying data from it.
It may be a good idea to throw in some rude tamper protection:
class PauzaAction(models.Model):
# ... all like above, plus:
def save(self, *args, **kwargs):
raise Exception('Permission Denied')
def delete(self, *args, **kwargs):
raise Exception('Permission Denied')
As I said, I imagine you could create a SQL view with the four action_ fields and an additional 'action_model' field that could contain varchar references to model itself (maybe just the original table name).

Categories

Resources