Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Different subscription behaviour for mongo collections #1939

Open
mattiLeBlanc opened this issue Jul 23, 2018 · 5 comments
Open

Different subscription behaviour for mongo collections #1939

mattiLeBlanc opened this issue Jul 23, 2018 · 5 comments

Comments

@mattiLeBlanc
Copy link

mattiLeBlanc commented Jul 23, 2018

If was playing with my subscription of a mongo collection, doing search on a third party api that resulted in inserting records in my mongo collection. However, I noticed that I didn't see my subscription working in my template when I trigger the mongo insert while using one method, but it did work with another method.

Again for me this is confusing, what is the best practice and/or is this behaviour on purpose?

This subscription auto updates when I add new records manually or trigger the api that inserts mongo records:

export class PodcastSearchComponent implements OnInit {
  episodeSubscription: Subscription;
  episodes$: Observable<Episode[]>;

  constructor(
  ) {}

  ngOnInit() {
     this.episodeSubscription = MeteorObservable.subscribe( 'episodes' ).subscribe();
    this.episodes$ = Episodes.find();
);

This option looks a bit weird, since you setup a subscription, but we don't use a subject (rxjs) and then we just seem to bind Episodes.find(), which is a rxjs mongo observable collection at this time, to the episodes$ observable.

The second method:
This subscription DOESN'T auto update, only loads one time on page load:

export class PodcastSearchComponent implements OnInit {
  episodes$: Observable<Episode[]>;

  constructor(
  ) {}

  ngOnInit() {
    this.episodes$ = MeteorObservable.subscribe( 'episodes' ).pipe( switchMap( () => Episodes.find() ) );

I ran into the second method in one of the examples and it looked elegant, but it has some different behaviour than the first method.
I would have expected this to work since the RxJS Mongo observable collection that was setup. However it doesn't autorun, or detect changes in my situation.

Should I also use the second method for setting up a subscription?

I hope my questions aren't annoying, I am re-exploring Meteor after 2 years of absence (just pure angular 4 during that time) and I really want it to work with Angular 6.

***Update: at one point I thought it had something to do with ChangeDetectionStrategy.OnPush but it didn't matter turning that off.

@ardatan
Copy link
Collaborator

ardatan commented Aug 4, 2018

Try to use this way;
Subscription is triggered once it's ready, and the collection observable is independently triggered by Meteor's tracker.
Please let me know if it is fixed or still occured

ngOnInit(){
  this.episodesSubscription = MeteorObservable.subscribe('episodes').subscribe(() => {
     this.episodes$ = Episodes.find();
  })
}
ngOnDestroy(){
  if(this.episodesSubscription){
    this.episodesSubscription.unsubscribe();
  }
}

@mattiLeBlanc
Copy link
Author

I moved my subscription to a service, since I want a singleton watching the episode change and then call the redux action, which is using an @effect that calls the getAll function returning the episodes.
When I use the Autorun, I can manually add and remove items to mongo and the list will update.
When I use your slightly altered suggestion (not assigning it episodes$) it doesn't autorun. It could be because I am not assigning it the observable episodes$.

@Injectable()
export class EpisodesService {

  episodeSubscription: Subscription;

  constructor(
    private store: Store<fromStore.PodcastsState>,
  ) {
  //   this.episodeSubscription = MeteorObservable.subscribe('episodes').subscribe(() => {
  //     Episodes.find().fetch();
  //     this.store.dispatch( new fromStore.LoadEpisodes() );
  //  })

    this.episodeSubscription = MeteorObservable.subscribe( 'episodes' ).subscribe();
    MeteorObservable.autorun().subscribe(() => {
      // triger autorun
      Episodes.find().fetch();
      this.store.dispatch( new fromStore.LoadEpisodes() );
    });
  }

  getAll(): Observable<Episode[]> {
    return of( Episodes.find().fetch() );
  }

}

@ardatan
Copy link
Collaborator

ardatan commented Aug 4, 2018

Maybe you should try mergeMap or somehow.
Or you can use Tracker.autorun and Meteor.subscribe to get data inside autorun callback and trigger redux without dealing with RxJS.

@mattiLeBlanc
Copy link
Author

hmm, it doesn't help that I don't entirely know what I am doing.
This seems to be the only one that works

 this.episodeSubscription = MeteorObservable.subscribe( 'episodes' ).subscribe();
 MeteorObservable.autorun().subscribe(() => {
      // triger autorun
      Episodes.find().fetch();
      this.store.dispatch( new fromStore.LoadEpisodes() );
    });

Adding a mergeMap in a pipe() after the subscription didn't make it reRun.
Only the Episodes.find().fetch() inside the autorun triggers a rerun and then does a dispatch of my action.

@mattiLeBlanc
Copy link
Author

@ardatan can I ask you something off topic: Do you think Angular, Meteor and NGRX is a bit of overkill?
I could do the whole state management in Mongo right? Then the client mini-mongo would be the same as an NgRX Store with pubsub etc.

I though NGRX was the way to go, but I hear a lot of people in the react world mention graphql instead of redux.
Would it be better for me to look at Apollo?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants