Recently started using rxJava in one of my projects. There are several demoes out there showcasing the use of retrofit and its observables for display but can somebody show an example of doing this with our own database.
I tried it myself ref: this question
But am unable to think of a way to properly combine all the generated object observables into a list that can be updated inside the adapter in one go. toList seems to terminate the observable after the first run, thus can't be used directly.
Thanks!
To observe changes to a SQLite database using RxJava you can use SQLBrite.
To query the table users you can use:
Observable<Query> users = db.createQuery("users", "SELECT * FROM users");
users.subscribe(new Action1<Query>() {
#Override public void call(Query query) {
Cursor cursor = query.run();
// TODO parse data...
}
});
You will also receive notifications for updates/inserts as long as you are subscribed.
The code sample is from the documentation on github.
Related
I will first say that I am a firmware developer trying to make a web interface for a personal project. My question might be basic as this is my first web interface with a database. I have searched quite a bit on how to achieve what I am trying to do without success, so I suspect I am not approaching this the right way, but here it is:
Basically I have a device pushing data to a firebase realtime database :
the push function generates an unique Id for me automatically which is nice...
Now In my flutter interface, I want to display the latest entry on a widget so I am using the onChildAdded functionnality of flutterfire:
ref.onChildAdded.listen((DatabaseEvent event) {
print(event.snapshot.key);
print(event.snapshot.value);
});
My first issue is that this function is triggered for all the child at first before waiting for new ones which is unnecessary and could be a problem when I begin to have a lot of data. Is there a way to simply get the latest sample and still get an event when one is added? (I still want to keep the old data to be able to make charts with them)
My second problem is the format of the received data:
{
-Mx2PCeptLf2REP1YFH0: {
"picture_url": "",
"time_stamp": "2022-02-28 21:56:58.502005",
"temperature": 27.71,
"relative_humidity": 42.77,
"eco2": 691,
"tvoc": 198,
"luminosity": 4193,
"vpd": 1.71
}
}
before using the put method, I didn't have the automatically generated ID so I was able to cast this as a Map<String, dynamic> and use the data like this in my widget:
Text(snapshot.data!["temperature"].toString())
but now the added nesting with the generated id is giving me a headache as I can't seem to figure out how to simply get the data.
So if anyone could help me to always get the single latest data when subscribing to a collection and how to access that data within my State of my StatefulWidget that would be much appreciated!
My first issue is that this function is triggered for all the child at first before waiting for new ones which is unnecessary and could be a problem when I begin to have a lot of data.
The Firebase Realtime Database synchronizes the state of the path/query that you listen to. So it doesn't just fire an event on onChildAdded for new data, but also for any existing data that you request. There is (intentionally) no way to change that behavior.
So your options here are limited:
You can remove the data that your application has processed, so that it doesn't get passed to the clients again. That means you essentially implement a message-passing mechanism on top of Firebase's data-synchronization semantics.
You can use a query to only request a certain subset of the child nodes at a path. For example, if you remember the latest key that you've received, you can get data from there on with ref.orderByKey().startAt("-Mx2LastKeyYouAlreadySaw").
Since this comes up regularly, I recommend also checking:
How can I setup Firebase to observe only new data?
How to get only updated data Firebase
How to fetch only latest specific data from Firebase?
and more from these search results
My second problem is the format of the received data:
The screenshot of your database shows two keys, each of which has a single string value. The contents of that value may be JSON, but the way they are stored is just a single string.
If you want to get a single property from the JSON, you either have to:
Decode the string back into JSON with jsonDecode.
Fix the problem at the source by storing the data as proper JSON, rather than as a string.
Firebase Realtime Database Overrides my Data at a location even when I use .push() method. The little-concrete knowledge I have about writing to Firebase Realtime database is that writing to Firebase real time database can be done in few several ways. Two of the most prominent are the
set() and 2. push() method.
The long story short, push() is used to create a new key for a data to be written and it adds data to the node.
So fine, firebase has being co-operating with me in my previous projects but in this, I have no idea what is going on. I have tried different blends of push and set to achieve my goal but no progress so far.
In the code below, what I want to achieve is 2 things, write to a location chatUID, message and time only once, but write severally '-MqBBXPzUup7czdG2xCI' all under the same node "firebaseGeneratedId1" ->
A better structure is below.
Help with code. Thanks.
UPDATE
Here is my code
The writers reference
_listeningMsgRef = _msgDatabase
.reference()
.child('users')
.child(userId)
.child('chats')
.child(chatUIDConcat);
When a user hits sendMessage, here is the function called
void sendMessage() {
_messageController.clear();
var timeSent = DateTime.now().toString();
//Send
Map msgMap = {
'message': msg,
'sender': userId,
'time': timeSent,
'chatUID': chatUIDConcat
};
//String _key = _listeningMsgRef.push().key;
_listeningMsgRef.child(chatUIDConcat).set().whenComplete(() {
SnackBar snackBar = const SnackBar(content: Text('Message sent'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
DatabaseReference push = _listeningMsgRef.child(chatUIDConcat).push().set(msgMap);
});
}
The idea about the sendMessage function, is to write
chatUID:"L8pacdUOOohuTlifrNYC3JALQgh2+q5D38xPXVBTwmwb5Hq..."
message: "I'm coming"
newMessage: "true"
sender: "L8pacdUOOohuTlifrNYC3JALQgh2"
When it is complete, then push new nodes under the user nodes.
EDIT:
I later figured out the issue. I wasn't able to achieve my goal because I was a bit tensed while doing that project. The issue was I was wanted to write new data into the '-MqBBXPzUup7czdG2xCI' node without overwriting the old data in it.
The solution is straight forward. I just needed to ensure I wrote data in that node as new nodes under it. Nothing much, thanks
Frank van Puffelen for your assistance.
Paths in Firebase Realtime Database are automatically created when you write any data under then, and deleted when you remove the last data under them.
So you don't need to first create the node for the chat room. Instead, it gets auto-created when you write the first message into it with _listeningMsgRef.child(chatUIDConcat).push().set(msgMap)
I have came across a requirement where i want axon to wait untill all events in the eventbus fired against a particular Command finishes their execution. I will the brief the scenario:
I have a RestController which fires below command to create an application entity:
#RestController
class myController{
#PostMapping("/create")
#ResponseBody
public String create(
org.axonframework.commandhandling.gateway.CommandGateway.sendAndWait(new CreateApplicationCommand());
System.out.println(“in myController:: after sending CreateApplicationCommand”);
}
}
This command is being handled in the Aggregate, The Aggregate class is annotated with org.axonframework.spring.stereotype.Aggregate:
#Aggregate
class MyAggregate{
#CommandHandler //org.axonframework.commandhandling.CommandHandler
private MyAggregate(CreateApplicationCommand command) {
org.axonframework.modelling.command.AggregateLifecycle.apply(new AppCreatedEvent());
System.out.println(“in MyAggregate:: after firing AppCreatedEvent”);
}
#EventSourcingHandler //org.axonframework.eventsourcing.EventSourcingHandler
private void on(AppCreatedEvent appCreatedEvent) {
// Updates the state of the aggregate
this.id = appCreatedEvent.getId();
this.name = appCreatedEvent.getName();
System.out.println(“in MyAggregate:: after updating state”);
}
}
The AppCreatedEvent is handled at 2 places:
In the Aggregate itself, as we can see above.
In the projection class as below:
#EventHandler //org.axonframework.eventhandling.EventHandler
void on(AppCreatedEvent appCreatedEvent){
// persists into database
System.out.println(“in Projection:: after saving into database”);
}
The problem here is after catching the event at first place(i.e., inside aggregate) the call gets returned to myController.
i.e. The output here is:
in MyAggregate:: after firing AppCreatedEvent
in MyAggregate:: after updating state
in myController:: after sending CreateApplicationCommand
in Projection:: after saving into database
The output which i want is:
in MyAggregate:: after firing AppCreatedEvent
in MyAggregate:: after updating state
in Projection:: after saving into database
in myController:: after sending CreateApplicationCommand
In simple words, i want axon to wait untill all events triggered against a particular command are executed completely and then return to the class which triggered the command.
After searching on the forum i got to know that all sendAndWait does is wait until the handling of the command and publication of the events is finalized, and then i tired with Reactor Extension as well using below but got same results: org.axonframework.extensions.reactor.commandhandling.gateway.ReactorCommandGateway.send(new CreateApplicationCommand()).block();
Can someone please help me out.
Thanks in advance.
What would be best in your situation, #rohit, is to embrace the fact you are using an eventually consistent solution here. Thus, Command Handling is entirely separate from Event Handling, making the Query Models you create eventually consistent with the Command Model (your aggregates). Therefore, you wouldn't necessarily wait for the events exactly but react when the Query Model is present.
Embracing this comes down to building your application such that "yeah, I know my response might not be up to date now, but it might be somewhere in the near future." It is thus recommended to subscribe to the result you are interested in after or before the fact you have dispatched a command.
For example, you could see this as using WebSockets with the STOMP protocol, or you could tap into Project Reactor and use the Flux result type to receive the results as they go.
From your description, I assume you or your business have decided that the UI component should react in the (old-fashioned) synchronous way. There's nothing wrong with that, but it will bite your *ss when it comes to using something inherently eventually consistent like CQRS. You can, however, spoof the fact you are synchronous in your front-end, if you will.
To achieve this, I would recommend using Axon's Subscription Query to subscribe to the query model you know will be updated by the command you will send.
In pseudo-code, that would look a little bit like this:
public Result mySynchronousCall(String identifier) {
// Subscribe to the updates to come
SubscriptionQueryResult<Result> result = QueryGateway.subscriptionQuery(...);
// Issue command to update
CommandGateway.send(...);
// Wait on the Flux for the first result, and then close it
return result.updates()
.next()
.map(...)
.timeout(...)
.doFinally(it -> result.close());
}
You could see this being done in this sample WebFluxRest class, by the way.
Note that you are essentially closing the door to the front-end to tap into the asynchronous goodness by doing this. It'll work and allow you to wait for the result to be there as soon as it is there, but you'll lose some flexibility.
I am starting out with the Axon framework and hit a bit of a roadblock.
While I can load individual aggregates using their ID, I can’t figure out how to get a list of all aggregates, or a list of all aggregate IDs.
The EventSourcingRepository class only has load() methods that return one aggregate.
Is there a way to all aggregate (IDs) or am I supposed to keep a list of all aggregate IDs outside of axon?
To keep things simple I am only using an InMemoryEventStorageEngine for now.
I am using Axon 3.0.7.
First off I'm was wondering why you would want to retrieve a complete list of all the aggregates from the Repository.
The Repository interface is set such that you can load an Aggregate to handle commands or to create a new Aggregate.
Asking the question you have, I'd almost guess you're using it for querying purposes rather than command handling.
This however isn't the intended use for the EventSourcingRepository.
One reason you'd want this I can think about, is that you want to implement an API call to publish a command to all Aggregates of a specific type in your application.
Taking that scenario then yes, you need to store the aggregateId references yourself.
But concluding with my earlier question: why do you want to retrieve a list of aggregates through the Repository interface?
Answer Update
Regarding your comment, I've added the following to my answer:
Axon helps you to set up your application with event sourcing in mind, but also with CQRS (Command Query Responsibility Segregation).
That thus means that the command and query side of your application are pulled apart.
The Aggregate Repository is the command side of your application, where you request to perform actions.
It thus does not provide a list-of-aggregates, as a command is an expression of intent on a aggregate. Hence it only requires the Repository user to retrieve one aggregate or create one.
The example you've got that you need of the list of Aggregates is the query side of your application.
The query side (your views/entities) is typically updated based on events (sourced through events).
For any query requirement you have in your application, you'd typically introduce a separate view tailored to your needs.
In your example, that means you'd introduce a Event Handling Component, listening to your Aggregate Events, which update a Repository with query models of your aggregate.
The EventStore passed into EventSourcingRepository implements StreamableMessageSource<M extends Message<?>> which is a means of reaching in for the aggregates.
Whilst doing it the framework way with an event handling component will probably scale better (depending on the how its used / the context), I'm pretty sure the event handling components are driven by StreamableMessageSource<M extends Message<?>> anyway. So if we wanted to skip the framework and just reach in, we could do it like this:
List<String> aggregates(StreamableMessageSource<Message<?>> eventStore) {
return immediatelyAvailableStream(eventStore.openStream(
eventStore.createTailToken() /* All events in the event store */
))
.filter(e -> e instanceof DomainEventMessage)
.map(e -> (DomainEventMessage) e)
.map(DomainEventMessage::getAggregateIdentifier)
.distinct()
.collect(Collectors.toList());
}
/*
Note that the stream returned by BlockingStream.asStream() will block / won't terminate
as it waits for future elements.
*/
static <M> Stream<M> immediatelyAvailableStream(final BlockingStream<M> messageStream) {
Iterator<M> iterator = new Iterator<M>() {
#Override
public boolean hasNext() {
return messageStream.hasNextAvailable();
}
#Override
public M next() {
try {
return messageStream.nextAvailable();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Didn't expect to be interrupted");
}
}
};
Spliterator<M> spliterator = Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED);
Stream stream = StreamSupport.stream(spliterator, false);
return (Stream)stream.onClose(messageStream::close);
}
I'm following along the with the basic AngularFire2 docs, and the general format seems to be:
const items = af.database.list('/items');
// to get a key, check the Example app below
items.update('key-of-some-data', { size: newSize });
My confusion is that in the source code, it seems as though calling database.list() grabs all the data at the listed url (line 114 here)
Can anyone help clarify how that works? If it does indeed grab all the data, is there a better way of getting a reference without doing that? Or should I just reference each particular URL individually?
Thanks!
When you create an AngularFire2 list, it holds an internal Firebase ref - accessible via the list's public $ref property.
The list is an Observable - which serves as the interface for reading from the database - and includes some additional methods for writing to the database: push, update and remove.
In the code in your question, you are only calling the update method and are not subscribing to the observable, so no data is loaded from the database into memory:
const items = af.database.list('/items');
// to get a key, check the Example app below
items.update('key-of-some-data', { size: newSize });
It's only when a subscription to the observable is made that listeners for value and the child_... events are added to the ref and the list builds and maintains an internal array that's emitted via the observable. So if you are only calling the methods that write to the database, it won't be loading any data.
The AngularFire2 object is implemented in a similar manner.