I have two streams:
Stream<List<Order>> stream1 = pendingStream();
Stream<List<Order>> stream2 = preparingStream();
I'm trying to use StreamZip from the package:async/async.dart package to merge the streams like so...
Stream<List<Order>> getData() {
Stream<List<Order>> stream1 = pendingStream();
Stream<List<Order>> stream2 = preparingStream();
return StreamZip([stream1, stream2]);
}
However it won't compile. Saying:
The element type 'Stream<List<Order>>' can't be assigned to the list type 'Stream<Order>'.
From what I understand StreamZip should accept the two streams? What am I dong wrong?
You are creating a StreamZip<T> which will emit a List<T> of each event of its merged streams as you can refer in the documentation.
Each of your merged streams emit a List<Order> type, so that means that you will create a merged stream that will emit a List of List.
Basically, you only need to change your return type from Stream<List<Order>> to Stream<List<List<Order>>>.
Related
Is there a function like groupBy (from rxjs) in fs2?
I'd like to use it to covert stream of messages to stream of streams with messages from each chat depends on message's chatId.
Example in rxjs:
function chats(messages$: Observable<Message>): Observable<GroupedObservable<number, Message>> {
return messages$.pipe(groupBy((m) => m.chatId));
}
What does emit.forEach() do? From what I understand, it takes a stream but how does the ui rebuild itself and what is the onData parameter? I want to return a stream of data for a client matrix sdk
on<StartMatrixEventSubmitted>((event, emit) async {
emit(MatrixLoadingState());
await repo.getAllRooms().then((value) async {
await emit.forEach(
value.onSync.stream,
onData: (value2) {
print('data');
return MatrixSuccuClientState(rooms: value.rooms);
},
);
this.myRooms = value.rooms;
emit(MatrixClientSynced());
});
});
Here's the description of what emit.forEach does in the docs:
Subscribes to the provided stream and invokes the onData callback when
the stream emits new data and the result of onData is emitted.
Basically, it's the same as a List's .map() method. Each and every data (element) in the list will be converted into another value. Eg: Object to String
emit.forEach takes two values: the stream it has to listen to and the onData function. It will listen to all of the values emitted by the stream and convert them into another value (In this case MatrixSuccuClientState).
Think of value2 in onData: (value2) as the "element[index] in a list". The value2 is the currently emitted value of the stream. I think what you're looking for is:
onData: (currentlyEmittedValue) => MatrixSuccuClientState(rooms: currentlyEmittedValue.rooms),
I'd suggest understanding Streams in flutter before moving on to bloc. I suggest watching this video. After that, you could learn how bloc works in this dev page
I have 2 Firestore streams where the 2nd one depends on the 1st one. I want to emit new models that depend on data from both streams.
In pseudocode you can think of it in a following way:
// 1st stream emits some device data
final streamA = client.device(id: 0); // Stream<DeviceData>
// 2nd stream emits some metadata for the above device type
final streamB = client.deviceMetadata(type: device.type); // Stream<DeviceMetadata>
// and finally I want to receive stream of combined device (device data + metadata)
final combinedObject = Device.from(deviceData, deviceMetadata);
However, I cannot find an effective way of mapping a stream onto another stream while accessing the value from the source stream. For instance with .map() I would like to write:
return client.device('deviceId')
.map((device) => client.deviceMetadata(type: device.type))
.map((deviceMetadata) => Device.from(???, deviceMetadata));
The problem is of course that I don't know how to access device in the second map().
What stream transformation or rxdart extension I could use to achieve that?
Ok, after some tweaking I think I've found a solution
// get the initial stream
final deviceStream = client.device(id: id);
// create new stream depending on the first one
final deviceTypeStream = deviceStream.flatMap( // make sure to flatten the stream so that it's not Stream<Stream<..>>
(device) => client.deviceMetadata(type: device.type),
);
// use withLatestFrom to capture the latest value from the deviceTypeStream
// and create desired object out of that
return deviceTypeStream.withLatestFrom<DeviceData, Device>(
deviceStream,
(deviceType, device) => Device(device, deviceType),
);
You can use the rxdart library to combine multiple streams into one stream https://pub.dev/documentation/rxdart/latest/rx/CombineLatestStream-class.html
I'm very new to Kafka Stream API.
I have a KStream like this:
KStream<Long,String> joinStream = builder.stream(("output"));
The KStream with records value look like this:
The stream will be updated every 1s.
I need to build a Rest API that will be calculated based on the value profit and spotPrice.
But I've struggled to get the value of the last record.
I am assuming that you mean the max value of the stream when you say the last value as the values are continuously arriving. Then you can use the reduce transformation to always update the output stream with the max value.
final StreamsBuilder builder = new StreamsBuilder();
KStream<Long, String> stream = builder.stream("INPUT_TOPIC", Consumed.with(Serdes.Long(), Serdes.String()));
stream
.mapValues(value -> Long.valueOf(value))
.groupByKey()
.reduce(new Reducer<Long>() {
#Override
public Long apply(Long currentMax, Long v) {
return (currentMax > v) ? currentMax : v;
}
})
.toStream().to("OUTPUT_TOPIC");
return builder.build();
And in case that you want to retrive it in a rest api i suggest to take a look at Spring cloud + Kafka streams (https://cloud.spring.io/spring-cloud-stream-binder-kafka/spring-cloud-stream-binder-kafka.html) that you can exchange messages to spring web.
I'm obviously misunderstanding how StreamGroup.merge works or how stream works or both!. I have two streams that are querying the same field in firestore. And I'm using merge to make one stream called mergedStream. This is used in a streamBuilder to serve up to the app.
Here's my code:
Stream<List<Order>> stream1({Order order}) {
return _service.collectionStream(
path: APIPath.orders(),
queryBuilder: (query) =>
query.where('orderStatus', isEqualTo: 'Pending'),
builder: (documentSnapshot) => Order.fromFirebase(documentSnapshot));
}
Stream<List<Order>> stream2({Order order}) {
return _service.collectionStream(
path: APIPath.orders(),
queryBuilder: (query) =>
query.where('orderStatus', isEqualTo: 'Preparing'),
builder: (documentSnapshot) => Order.fromFirebase(documentSnapshot));
}
and the merged stream I use for my stream builder:
Stream<List<Order>> mergedStream() {
final s1 = preparingStream();
final s2 = pendingStream();
return StreamGroup.merge([s2, s1]);
}
Switching the order [s2, s1] changes the stream shown. And as the page loads I momentarily see the other stream but it disappears and the other stream appears..How can I merge the streams...?
EDIT: I'm adding the flutter tag because reading around it might be a problem with StreamBuilder
EDIT: This has helped a bit:(link in comments, And was just a proof of concept that the streams merged) But the stream searchResult() doesn't update when there's a state changes in one of he streams...You have to refresh the browser. (Flutter web)
Stream<List<Order>> searchResult() {
List<Stream<List<Order>>> streamList = [stream1(), stream2()];
var x = Rx.merge(streamList).scan<List<Order>>((acc, curr,i) {
return acc ?? <Order>[]
..addAll(curr);
});
//this test shows that the stream gets contents from both query streams
// x.map((convert){ convert.documents.forEach((f){print(f.data["name"]);});}).listen(print);
return x;
}
StreamGroup.merge merge the streams into an unified streams, but it doesn't merge the content of each one, so what you see in fact is the content of stream1 or stream2 coming one after the other.
I would recommend using StreamZip which combines the contents of the 2 streams and then emmits it as a new value (The first list contains the first value emitted by each stream, the second contains the second value, and so on).
Stream<List<List<Order>>> mergedStream() {
final s1 = preparingStream();
final s2 = pendingStream();
return StreamZip([s2, s1]);
}
//This will give you a List with all the emmited values of each stream, in this case a List of List<Order>
If you want to use the package Rx I would recommend ZipStream or CombineLatestStream
import 'package:rxdart/rxdart.dart';
Stream<List<Order>> get combineList{
final s1 = preparingStream();
final s2 = pendingStream();
return ZipStream.zip2<<List<Order>>, <List<Order>>, <List<Order>>>(
s1, s2, (firstOrder, secondOrder) => <Order>[...firstOrder, ...secondOrder]); //here you combine both in a list
}
The difference between Zip and Combine is that Zip waits for all the inner streams to emit before doing the operation (first emmited value of s1 and first of s2, and so on) whereas combine doesn't care about the order, if you emit one of s1 and 3 of s2 then it will do [s1.1, s2.1] [s1.1, s2.2] ...