How to implement a Delete Observer in Object Box - java

I am using ObjectBox as storage in my app which data are coming through socket connection and stored directly. An observer with a paginated query is used in fragment and applies data changes to recyclerview. The problem is how to know if an entry has been deleted from ObjectBox, get notified in the fragment, and remove it from recyclerview.

The basic approach is outlined in the data observer docs: you create a Query on which you can observe to react to data changes:
Query<Task> query = taskBox.query().equal(Task_.complete, false).build();
query.subscribe(subscriptions)
.on(AndroidScheduler.mainThread())
.observer(data -> updateUi(data));

Related

Update "from" part of a Apache Camel JPA route

I have a Apache Camel route between two JPA endpoints:
from("jpa://Data").to("jpa://DataConverted");
I basically want to do two things: fetch and copy data from my Data entity table to a similar dataConverted entity table in another database, and mark my Data entities with data.hasBeenCopied(true), only after successfully copying it though.
My route looks as follows:
from("jpa://Data").process(ex -> {
Data data = ex.getIn().getBody(Data.class);
DataConverted dataConverted = convertData(data);
ex.getMessage().setBody(dataConverted);
})
.recipientList(constant("direct:DataConverted","direct:updateFlag")).end();
from("direct:DataConverted").to("jpa://DataConverted").end;
from("direct:updateFlag").process(ex -> {
DataConverted dataConverted = ex.getIn().getBody(DataConverted.class);
var originalData = myDao.getData(dataConverted.getId());
originalData.setHasBeenCopied(true);
}).to("jpa://Data).end();
This runs without error, however it isn't setting the flag in my original database!
What did work was to call data.setHasBeenCopied(true); in the first process directly after from("jpa://Data") - however, this means that the flag is already set and if something happens with the copy process (e.g. the target database isn't available) the route will crash but the flag will stay set for that one data entity.
Note that I haven't called transacted() on my route as that didn't work out for me (multiple interfering transactions were opened).
Any idea how to proceed? Is Camel unable to update existing data via .to()? I can add my Camel configurations of the endpoints and such if needed, but it would probably get a bit long.

How to replace whole SQL table data frequently?

I have a Spring application that runs a cron on it. The cron every few minutes gets new data from external API. The data should be stored in a database (MySQL), in place of old data (Old data should be overwritten by new data). The data requires to be overwritten instead of updated. The application itself provides REST API so the client is able to get the data from the database. So there should not be situation that client sees an empty or just a part of data from database because there is an data update.
Currently I've tried deleting whole old data and insert new data but there is a place that a client gets just a part of the data. I've tried it via Spring Data deleteAll and saveAll methods.
#Override
#Transactional
public List<Country> overrideAll(#NonNull Iterable<Country> countries) {
removeAllAndFlush();
List<CountryEntity> countriesToCreate = stream(countries.spliterator(), false)
.map(CountryEntity::from)
.collect(toList());
List<CountryEntity> createdCountries = repository.saveAll(countriesToCreate);
return createdCountries.stream()
.map(CountryEntity::toCountry)
.collect(toList());
}
private void removeAllAndFlush() {
repository.deleteAll();
repository.flush();
}
I also thought about having a temporary table that gets new data and when the data is complete just replace main table with temporary table. Is it a good idea? Any other ideas?
It's a good idea. You can minimize the downtime by working on another table until it's ready and then switch tables quickly by renaming. This will also improve perceived performance by the users because no record needs to be locked like what happens when using UPDATE/DELETE.
In MySQL, you can use RENAME TABLE if you don't have triggers on the table. It allows multiple table renaming at once and it works atomically (i.e. transaction - if any error happens, no change is made). You can use the following for example
RENAME TABLE countries TO countries_old, countries_new TO countries;
DROP TABLE countries_old;
Refer here for more details
https://dev.mysql.com/doc/refman/5.7/en/rename-table.html

How make complex query with FirestoreRecyclerAdapter?

I'm developing an Android app and I need to make a complex query on my Firestore database and create a FirestoreRecyclerAdapter. To create the adpater I need a FirestoreRecyclerOptions object that take in input the whole query. Reading the documentation, I can't use in my query the methods whereGreaterThan, whereLessThan, oderBy, etc, on different parameters. For example, how can I get users from db who have age greater than/less than AND who have weight greater than/less than?
For example the document's structure in my firestore database is:
Users --->UserID--->userName(String)
--->userAge(number)
--->userHeight(number)
--->userWeight(number)
FirebaseFirestore db;
db = FirebaseFirestore.getInstance();
RecyclerView recyclerView;
recyclerView = (RecyclerView)findViewById(R.id.recyclerViewID);
.
.
.
Query query = db.collection("Users").//the complex query that i need
FirestoreRecyclerOptions<User> options = new FirestoreRecyclerOptions.Builder<User>()
.setQuery(query, User.class)
.build();
adapter = new UsersAdapter(options, this);//get in input options and the context
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
Edit: A possible solution in my last comment to answer 1
There are some query limitations when it comes to Firestore:
Query limitations
Cloud Firestore does not support the following types of queries:
Queries with range filters on different fields, as described in the previous section.
So you cannot query your database on range filters using whereGreaterThan() and whereLessThan() methods on different properties and pass it to an adapter.
Edit:
A possible solution for this issue would be to filter your records client side twice. First query the database using the first property and second using the second property. Unfortunately you cannot achieve this in a single go.
Edit2:
The solution would be to query the database using the first query, get the corresponding elements, query the database again using the second query and get the corresponding elements and then merge the results client side. Now the elements from the database were filtered twice. Pass a list of that elements to an adapter and that's it. Note, when using this solution you cannot use the Firebase-UI library anymore but this how you can get your items filtered twice.

Parse server : Adding Search filter to a Parse ListView in Android

I'm trying to add a search ListView with Parse api. But I could not add can anyone tell me how to add it ? (It is a typical ListView just fetching some text from parse).
Try the parse query adapter. It's an easy adapter for getting parse queries into a list.
If you want to filter a query you have already pulled from the server then you could save all the results to the local datastore and then query that to save the amount of downloads required.
https://github.com/ParsePlatform/ParseUI-Android/wiki/ParseQueryAdapter

How do I make sure I fetch data from api ONLY ONCE

I have an a few cards inflated, I fetch data from a website's api and insert it in the database and get back the first 3 rows with a seeAll option button to add fragmentB with the whole rows inflated from the databse. inside fragmentB I fetch the same from the same website just to make sure it was fetched and inserted in the database. is there a way to check before trying to fetch the api again?
better explanation:
This is the main layout, there are few other card below this one
this is the fragment opened when I press See all
so once the application opens i fetch the api and inflate the main layout, when I add the new fragment I want to check if the link was fetched instead of just fetching it once its created
Without seeing any of your code... :
Save the data within an object you defined such as
private apiData recievedData = null;
Whenever you attempt to recieve data, you'll first check if the object is null.
if(recievedData == null)
{
recievedData = getDataFromAPI();
}
return recievedData; //will return previously retrieved data if not null
It may be better to first check the database and if the record's exists then do not fetch it from the server. Also, is there any reason of again fetching the data in FragmentB when you have already fetched it in FragmentA. Anyways, try to first check the database for the record and if the record doesn't exist then fetch it from API.

Categories

Resources