I'm using Firebase for data storage on an Android project, and using the Firebase Java API to deal with data. I'm not sure I'm doing it as efficiently as possible, though, and I'd like some advice on best practices for retrieving and formatting data. My Firebase repository looks something like this....
-POLLS
NUMPOLLS - 5
(pollskey) - NAME - Poll1
NUMELECTIONS - 2
ELECTIONS
(electionskey) - NAME - Election1
NUMNOMINATIONS - 2
NUMVOTERS - 2
NUMBERTOELECT - 1
VOTERS - (votesrkey) - NAME - Charles
NUMBER - (678) 333-4444
.
.
.
(voterskey) - ...
NOMINATIONS - (nominationskey) - NAME - Richard Nixon
NUMBEROFVOTES - 2
.
.
.
(nominationskey) - ...
.
.
.
(electionskey) - ...
.
.
.
(pollskey) - ...
So, for example here I'm trying to get all data out of a poll to list poll name, it's election names, and the candidate names and number of votes for each election. I get the POLLS level DataSnapshot during the OnCreate() function of my main activity like this...
private static final Firebase polls = pollsFirebase.child("Polls");
protected void onCreate(Bundle savedInstanceState) {
polls.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot child : snapshot.getChildren()) {
if (!child.getName().equals("NumPolls")) {
createPollTableAndHeaders(child);
}
}
}
});
}
Then I proceed to read out the individual pieces of data I need by successively calling getValue() on DataSnapshots, and checking the keys of the resulting HashMaps...
private void createPollTableAndHeaders(DataSnapshot poll) {
String pollName = "";
int numPolls;
Object p = poll.getValue();
if (p instanceof HashMap) {
HashMap pollHash = (HashMap) p;
if (pollHash.containsKey("Name")) {
pollName = (String) pollHash.get("Name");
}
if (pollHash.containsKey("Elections")) {
HashMap election = (HashMap) pollHash.get("Elections");
Iterator electionIterator = election.values().iterator();
while (electionIterator.hasNext()) {
Object electionObj = electionIterator.next();
if (electionObj instanceof HashMap) {
HashMap electionHash = (HashMap) electionObj;
if (electionHash.containsKey("Name")) {
String electionName = (String) electionHash.get("Name");
}
}
};
}
}
This seems like a pretty tedious way to drill down through the data structure, and I'm wondering if there's a better way.
I've seen the getValue(java.lang.Class<T> valueType) method in the documentation, but haven't been able to get it to work in my case, since I'm working with composed objects and not just containers for primitive types. How does the function know what Firebase data to assign to which member variables of a model object? Does it match Firebase key names with member variables, and therefore do these have to be exactly the same, with case sensitivity? How would that deal with Firebase generated key names like produced when pushing to a List? How to you construct model objects for composed objects?
The getValue(java.lang.Class valueType) method follows the same rules as the jackson object mapping library (it's what we use internally: http://wiki.fasterxml.com/JacksonInFiveMinutes). So, your Java classes must have default constructors (no arguments) and getters for the properties that you want assigned (https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/DataSnapshot.html#getValue(java.lang.Class)).
In short, yes, the key names in Firebase must match the member variables.
For an example using composite objects, including a list, see AndroidDrawing. Specifically, the Segment class contains a list of Point instances. There is one catch using lists of data generated with the .push() method. Since the key names generated are Strings so that they can be unique across clients, they deserialize the Maps rather than Lists. However, if you iterate over dataSnapshot.getChildren() they will be returned in order.
In addition, if you don't want to deserialize into a HashMap, you can use the child() method on DataSnapshot. For instance:
String pollName = poll.child("Name").getValue(String.class);
DataSnapshot elections = poll.child("Elections");
for (DataSnapshot election : elections.getChildren()) {
String electionName = election.child("Name").getValue(String.class);
}
In this example, any values that don't exist will be returned as null.
Hope that helps!
public T getValue(Class valueType)
1.The class must have a default constructor that takes no arguments
2.The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their default value when an instance is deserialized
Check it from:
this source It'll help you
detail
Related
My spring-boot application is generating GraphQL queries, however I want to compare that query in my test.
So basically I have two strings where the first one is containing the actual value and the latter one the expected value.
I want to parse that in a class or tree node so I can compare them if both of them are equal.
So even if the order of the fields are different, I need to know if it's the same query.
So for example we have these two queries:
Actual:
query Query {
car {
brand
color
year
}
person {
name
age
}
}
Expected
query Query {
person {
age
name
}
car {
brand
color
year
}
}
I expect that these queries both are semantically the same.
I tried
Parser parser = new Parser();
Document expectedDocument = parser.parseDocument(expectedValue);
Document actualDocument = parser.parseDocument(actualValue);
if (expectedDocument.isEqualTo(actualDocument)) {
return MatchResult.exactMatch();
}
But found out that it does nothing since the isEqualTo is doing this:
public boolean isEqualTo(Node o) {
if (this == o) {
return true;
} else {
return o != null && this.getClass() == o.getClass();
}
}
I know with JSON I can use Jackson for this purpose and compare treenodes, or parsing it into a Java object and have my own equals() implementation, but I don't know how to do that for GraphQL Java.
How can I parse my GraphQL query string into an object so that I can compare it?
I have recently solved this problem myself. You can reduce the query to a hash and compare the values. You can account for varied query order by utilizing a tree structure. You can take advantage of the QueryTraverser and QueryReducer to accomplish this.
First you can create the QueryTraverser, the exact method for creating this will depend on your execution point. Assuming you are doing it in the AsyncExecutor with access to the ExecutionContext the below code snippet will suffice. But you can do this in instrumentation or the data fetcher itself if you so choose;
val queryTraverser = QueryTraverser.newQueryTraverser()
.schema(context.graphQLSchema)
.document(context.document
.operationName(context.operationDefinition.name)
.variables(context.executionInput?.variables ?: emptyMap())
.build()
Next you will need to provide an implementation of the reducer, and some accumulation object that can add each field to a tree structure. Here is a simplified version of an accumulation object
class MyAccumulation {
/**
* A sorted map of the field node of the query and its arguments
*/
private val fieldPaths = TreeMap<String, String>()
/**
* Add a given field and arguments to the sorted map.
*/
fun addFieldPath(path: String, arguments: String) {
fields[path] = arguments
}
/**
* Function to generate the query hash
*/
fun toHash(): String {
val joinedFields = fieldPaths.entries
.joinToString("") { "${it.key}[${it.value}]" }
return HashingLibrary.hashingfunction(joinedFields)
}
A sample reducer implementation would look like the below;
class MyReducer : QueryReducer<MyAccumulation> {
override fun reduceField(
fieldEnvironment: QueryVisitorFieldEnvironment,
acc: MyAccumulation
): MyAccumulation {
if (fieldEnvironment.isTypeNameIntrospectionField) {
return acc
}
// Get your field path, this should account for
// the same node with different parents, and you should recursively
// traverse the parent environment to construct this
val fieldPath = getFieldPath(fieldEnvironment)
// Provide a reproduceable stringified arguments string
val arguments = getArguments(fieldEnvironment.arguments)
acc.addFieldPath(fieldPath, arguments)
return acc
}
}
Finally put it all together;
val queryHash = queryTraverser
.reducePreOrder(MyReducer(), MyAccumulation())
.toHash()
You can now generate a repdocueable hash for a query that does not care about the query structure, only the actual fields that were requested.
Note: These code snippets are in kotlin but are transposable to Java.
Depending on how important is to perform this comparison you can inspect all the elements of Document to determine equality.
If this is to optimize and return the same result for the same input I would totally recommend just compare the strings and kept two entries (one for each string input).
If you really want to go for the deep compare route, you can check the selectionSet and compare each selection.
Take a look at the screenshot:
You can also give EqualsBuilder.html.reflectionEquals(Object,Object) a try but it might inspect too deep (I tried and returned false)
I am wondering weather there is a better solution to my problem.
Better in the sense that not every object of the class Segment has to create a new database object.
I am trying to keep only one database in my program because the database is very big and I am sure there is a more efficient solution to this.
The Database holds objects of the class SegmentInformetion in a List. Each Object contains many informations each Segment object needs for its instantiation.
The Layer Class contains a List of Segments. The Layers Constructor contains an array with IDs. Every Segment will get its Information from the Database depending on the ID with which it is calling the Database.
Database {
List<SegmentInformation> segInfoList;
public SegmentInformation getSegInfos( int id ){
return segInfoList.get(id);
}
}
Layer{
List<Segments> segmentList;
public Layer( int[] segmentIDs ){
for (int i : segmentIDs){
segmentList.add( new Segment( segmentIDs[i] ) );
}
}
}
Segment{
double value1;
//....
double valuenN;
public Segment(int sID){
Database db = new Database();
SegmentInformation info = db.getSegInfos( sID );
value1 = info.getValue1();
//....
valueN = info.getValueN();
}
}
I am trying to avoid a global static variable which contains the Database.
Any suggestions for a more suitable way to instantiate all the Segment objects?
Use a Singleton to contain all the Segment objects:
In software engineering, the singleton pattern is a software design
pattern that restricts the instantiation of a class to one "single"
instance. This is useful when exactly one object is needed to
coordinate actions across the system. The term comes from the
mathematical concept of a singleton.
https://en.wikipedia.org/wiki/Singleton_pattern
I have a problem with one functionality in my spring app. I have 2 tables in the same database, both contains the same type of data (id,title,description and date). And I can get the data from one table but don't know how to insert into 2nd table.
In my #Service layer i can get the data from table A. But dont know how to convert into another class object (both classes contain the samne data)
Injected JpaRepositories
private TasksRepository theTasksRepository;
private TasksRepositoryArchive theTasksRepositoryArchive;
And there's code to get the object from table A (TasksRepository - JpaRepository)
public Tasks findById(int theId) {
//Check if value is null or not null
Optional<Tasks> result = theTasksRepository.findById(theId);
Tasks theTask = null;
if (result.isPresent())
{
//if value is not null
theTask = result.get();
}
else
{
//if value is null
throw new RuntimeException("Task with given ID couldn't be found " +theId );
}
return theTask;
}
1) Define 2 entities, one for each table. To copy data, create an instance of the 2nd type and, copy properties, save. To copy properties there are many ways: you cann call each getter and setter manually, you can use some libraries like Dozer or MapStruct. Don't forget to set ID to null.
2) If you want to have an archive of changes, use libraries that help to implement it. For instance, consider using Enverse.
I'm POSITIVE that my title for this topic is not appropriate. Let me explain. The purpose of this is to duplicate a "Profile" application, where I have a profile and so would you. We both have our own followers and in this example, we both follow each other. What this method is needed to return is a cross reference based on whom you follow that I do not. I need this method to return to me a recommended Profile object that I do not already have in my array. Right now I'm having a difficult time with one line of code within a particular method.
One of my classes is a Set class that implements a SetInterface (provided by my professor) and also my Profile class that implements a ProfileInterface which was also provided. In my code for the Profile class, I have the following object: private Set<ProfileInterface> followBag = new Set<ProfileInterface>(); which utilizes the Array bag methods from my Set class with the ProfileInterface methods I've made.
Here is the method (not complete but can't move further without my problem being explained):
public ProfileInterface recommend(){
Set<ProfileInterface> recommended;
ProfileInterface thisProfile = new Profile();
for(int index = 0; index < followBag.getCurrentSize(); index++){
Set<ProfileInterface> follows = followBag[index].toArray();
for(int followedFollowers = 0; followedFollowers < follows.getCurrentSize(); followedFollowers++) {
if()
//if Profile's do not match, set recommended == the Profile
}
}
return recommended;
}
The purpose of this method is to parse through an array (Profile as this example) and then take each of those sub-Profiles and do a similar action. The reason for this much like "Twitter", "Facebook", or "LinkedIn"; where each Profile has followers. This method is meant to look through the highest Profiles follows and see if those subProfiles have any followers that aren't being followed by the highest one. This method is then meant to return that Profile as a recommended one to be followed. This is my first dealing with Array Bag data structures, as well as with generics. Through "IntelliJ", I'm receiving errors with the line Set<ProfileInterface> follows = followBag[index].toArray();. Let me explain the reason for this line. What I'm trying to do is take "my" profile (in this example), and see who I'm following. For each followed profile (or followBag[index]) I wish to see if followBag[index][index] == followBag[index] and continue to parse the array to see if it matches. But, due to my confusion with generics and array bag data structures, I'm having major difficulties figuring this out.
I'd like to do the following:
//for all of my followers
//look at a particular followed profile
//look at all of that profile's followers
//if they match one of my followers, do nothing
//else
//if they don't match, recommend that profile
//return that profile or null
My problem is that I do not know how to appropriately create an object of a Profile type that will allow me to return this object
(in my method above, the line Set<ProfileInterface> follows = followBag[index].toArray();)
I'm trying to make an index of my Profile set to an object that can later be compared where my difficulties are. I'd really appreciate any insight into how this should be done.
Much appreciated for all help and Cheers!
When you do:
Set<ProfileInterface> follows = followBag[index].toArray();
you're trying to use Set as Array. But you can't.
Java will not allow, because Set and Array are different classes, and Set does not support [] syntax.
That is why you get error. For usefollowBag as Array you have to convert it:
ProfileInterface[] profileArray = followBag.toArray(new ProfileInterface[followBag.size()]);
for(int i=0; i<profileArray.length; i++){
ProfileInterface profile = profileArray[i];
//do what you would like to do with array item
}
I believe, in your case, you don't need assign Set object to generic Array at all. Because you can enumerate Set as is.
public class Profile {
private Set<ProfileInterface> followBag = new HashSet<Profile>();
...
public Set<ProfileInterface> recommended(){
Set<ProfileInterface> recommendSet = new HashSet<ProfileInterface>();
for(Profile follower : followBag){
for(Profile subfollower : follower.followBag){
if(!this.followBag.contains(subfollower)){
recommendSet.add(subfollower);
}
}
}
return recommendSet;
}
}
I also added possibility of returning list of recommended profiles, because there is may be several.
I am working on an android app that loads in a list of students to display in a list based activity. There are two components to the app. There is a server which responds via xml with the list of current active students and a database on the app end which stores theses students with some details (name,age etc). I would like a way to sync these two data sources. When the app starts, I would like to check against the xml to see if students on the server were added/deleted and update the db accordingly.
I would be parsing the xml list into a student object at login. Is there any way to store/retrieve an entire object into an android supported db so I can do a direct comparison to see what to update/delete? It would end up being something like
if (serverStudent[0].name == dbStudent[0].name)
//overwrite dbStudent object with serverStudent fields
What is the most efficient/lightweight way to achieve object persistance and then comparison in Android?
Here's a method I have used in the past:
Anytime an object in the database is changed, use a timestamp column to store that time. When the app connects on startup, simply check each timestamp in the app db against the timestamp in the server db for each object. If the timestamps match, do nothing. If the timestamps don't match, retrieve the updated record from the server. Make sure you're using a detail enough timestamp (usually down to milli- or micro- seconds).
The nice thing about timestamps is that if you don't want the server data to override the app data, you could look at which is newer and keep that object if they've both been edited. Just adding some additional thoughts!
You can do something like this -
public class StudentRecord {
Vector<StudentData> studentDatas;
public StudentRecord()
{
studentDatas = new Vector<StudentData>();
}
public Vector<StudentData> getRecords() {
return studentDatas;
}
public void setRecords(Vector<StudentData> records) {
this.studentDatas = records;
}
public class StudentData
{
String name,Rollno;
public String getRollno() {
return Rollno;
}
public void setRollno(String rollno) {
Rollno = rollno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
When you get the vector object studentDatas you can do something like this -
for(Object object : record.getRecords())
{
data = (StudentData)object;
data.getRollno();
data.getName();
}
Check out these libraries:
http://www.datadroidlib.com/
https://github.com/octo-online/robospice
I believe both offer solutions for your situation.
Or you can roll your own solution... Basically you will want to create a service or asynctask to do the syncing, in your student object you can create a constructor that you can pass an id to and have it pull the appropriate record from your local db then make a comparison method that will update if newer information is available.
I'm not sure i understood your question correctly.But as far as i understand i would do something like this.
In server side send send Json array which holds json student objects.
In android side create similer Student class and override equals
method as you want.
Then for each student check with equals method whether they are
equals or not and take action accordingly.
If you want to make faster search in students object array then apply
hash map instead of arrays.