0
votes
this.groupChatsSub = CEChats.find({
    group: {$in: groupIds}
})
.mergeMap(list => Observable.from(list))
.flatMap((chat: any)=> {
    return this.findLastChatMessage(chat._id, chat.lastMessage).map(lmsgsub=> {
        console.log('lmsgsub', lmsgsub)
        if(lmsgsub) {
            chat.lastMessage = lmsgsub;
            chat.unseen = !lmsgsub.seenBy.some((x)=>x==this.user._id);
            if(chat.unseen) {
                this.groupChatUnseen++;
            }
        } else {
            chat.unseen = false;
        }
        return chat;
    })
})
// .map((sub)=> {
//   console.log(sub);
//   return sub;
// })
.mergeAll();

I'm trying to get my observable pipe to work correctly.

The Find returns an array from my database

I mergeMap to make the array into an observable array so I can access each of the objects in the array in the next step.

I then flatMap to process each of the array items that are passed in, which calls another function which returns an observable, when that and I do what I need to do to the single object.

The commented out map prints all of the single objects correctly as I expect.

I then try to mergeAll the single objects back into one array again (this doesn't seem to work).

How can I get all of the objects back into an array? And shout i be using any other types of maps in place of the flatMap? (concatMap and mergeMap both seem to do exactly the same thing when I add it instead of the flatMap)

~edit

After using Picci's answer from below I changed it to this which seems to be working quite well.

this.groupChatsSub = CEChats.find({
    group: {$in: groupIds}
})
.mergeMap(listChats => {
    console.log('listy chats', listChats)
    let myArrayOfChats = [];
    let myArrayOfObservables = new Array<any>();
    for (let chat of listChats) {

        console.log('IN TEH FOR EACH');
        myArrayOfChats.push(chat);
        myArrayOfObservables.push(
            this.findLastChatMessage(chat._id, chat.lastMessage).map(lmsgsub=> {

                console.log('lmsgsub', lmsgsub)
                if(lmsgsub) {
                chat.lastMessage = lmsgsub;
                chat.unseen = !lmsgsub.seenBy.some((x)=>x==this.user._id);
                if(chat.unseen) {
                    this.groupChatUnseen++;
                }
                } else {
                chat.unseen = false;
                }
            });
        );
    };
    return Observable.combineLatest(myArrayOfObservables).map(()=> myArrayOfChats);
})
1

1 Answers

1
votes

I assume that eventually you want to have an Observable that emits the array once all the findLastChatMessage have been executed.

If this is the case, I would try something along these lines

this.groupChatsSub = CEChats.find({
    group: {$in: groupIds}
})
.mergeMap(list => {
   const myArrayOfChats = [];
   const myArrayOfObservables = new Array<Observables>();
   for (let chat of list) {
     myArrayOfObservables.push(this.findLastChatMessage(chat._id, chat.lastMessage).map(lmsgsub=> {
        myArrayOfChats.push(chat);
        console.log('lmsgsub', lmsgsub)
        if(lmsgsub) {
            chat.lastMessage = lmsgsub;
            chat.unseen = !lmsgsub.seenBy.some((x)=>x==this.user._id);
            if(chat.unseen) {
                this.groupChatUnseen++;
            }
        } else {
            chat.unseen = false;
        }
     });
     return Observable.combineLatest(myArrayOfObservables).map(() => myArrayOfChats);
   }
})

The whole idea is to create an array of Observables and than, via the combineLatest operator, obtain one Observable that emits once all the Observables contained in the array of Observables have emitted.

The last map operator is used to return the array of chats.

DISCLAIMER: I am not totally sure that the code is correct since I did not build a real test but simply assembled the concepts that I think are relevant

PS: flatMap has been renamed as mergeMap, so the 2 operators are the same