0

I have next scenario:

if (username exists in database)
    throw new Error(msg1);
if (email exists in database)
    throw new Error(msg2);
insertNewPlayer(username, email, password);

My environment is nodejs with TypeScript and I am using RxJS and MongoDB driver for nodejs. And I wrote next code:

return Observable.fromPromise(this.players.findOne({username: username}))
    .mergeMap(data => {
        if(data) throw new Error("That username is taken!");
        return Observable.fromPromise(this.players.findOne({email: email}));
    })
    .mergeMap(data => {
        if(data) throw new Error("That email is taken!");
        return Observable.fromPromise(this.players.insert(playerData));
    })
    .map(result => this.createNewPlayerFromData(playerData))

Since I am using MongoDB driver for nodejs I need to use .fromPromise so I can "cast" it to Observable...

Is this the correct way to do this? Or is there any other way? (Do not worry about createNewPlayerFromData function, it's just transforms playerData object to object of type Player)

4
  • Just curious, can you combine the two findOne into one query (has this user name or has this email) or run them in parallel? Also, I will assume there are other operators after the last map because if you don't subscribe from the observable, it won't run past the this.players.findOne({username: username}) promise. Commented Jan 8, 2018 at 0:02
  • The code is fine I think, if you want to check username and email at the sametime you can use merge() in the case of any data return you can just return error. Need an error catcher too Commented Jan 8, 2018 at 2:23
  • @Tr1et Yeah I have subscribe in another function, this one just returns observable. However I thought of combining into single findOne but I need to know is username or email that is not unique, so I can show appropriate message to user. Commented Jan 8, 2018 at 15:22
  • @FanCheung that looks like a nice proposition I will see to try with merge, maybe the code will look like more prettier :D Commented Jan 8, 2018 at 15:23

2 Answers 2

1

Or the other similar way, but in a sequential order would be:

const username$ = Observable
  .fromPromise(this.players.findOne({username: username}))
  .switchMap(x => x ? of(x) : _throw('That username is taken.'));

const email$ = Observable
  .fromPromise(this.players.findOne({email: email}))
  .switchMap(x => x ? of(x) : _throw('That email is taken.'));

const insertData = (data) => Observable
  .fromPromise(this.players.insert(playerData));

const insertPlayer$ = Observable.zip(
  username$, email$, (username, email) => ({ username, email }))
  .switchMap(data => insertData(data));

insertPlayer$.subscribe(x => this.createNewPlayerFromData(x));
Sign up to request clarification or add additional context in comments.

Comments

0

I think you can use zip or combineLatest to accomplish the task above.

const username$ = Observable
  .fromPromise(this.players.findOne({username: username}));

const email$ = Observable
  .fromPromise(this.players.findOne({email: email}));

const insertData = (data) => Observable
  .fromPromise(this.players.insert(data));

Observable.zip(username$, email$, (username, email) => {
  if (!username) {
    throw new Error('That username is taken!');
  }

  if (!email) {
    throw new Error('That email is taken!');
  }

  return { username, email };
})
  .switchMap(data => insertData(data))
  .subscribe(x => {
     this.createNewPlayerFromData(x);
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.