2017-08-19 2 views
1

J'ai un tableau d'objets à partir duquel je dois passer chaque objet séparément en méthode asynchrone (le processus derrière est géré avec Promise puis reconverti en Observable via Observable.fromPromise(...) - ceci Il est nécessaire d'utiliser cette méthode car la même méthode est utilisée dans le cas où un seul objet est transmis à tout moment, le processus enregistre les objets dans la base de données. Par exemple, voici un tableau d'objets:RxJS Mapper un tableau pour observer et retourner à un objet simple dans un tableau

[ 
    { 
    "name": "John", 
    ... 
    }, 
    { 
    "name": "Anna", 
    ... 
    }, 
    { 
    "name": "Joe",, 
    ... 
    }, 
    { 
    "name": "Alexandra", 
    ... 
    }, 
    ... 
] 

Maintenant, j'ai la méthode appelée insert which qui insère dans la base de données objet. La méthode store de l'instance de base de données renvoie l'ID nouvellement créé. A la fin, l'objet initial est copié et mappé avec son nouvel identifiant:

insert(user: User): Observable<User> { 
    return Observable.fromPromise(this.database.store(user)).map(
    id => { 
     let storedUser = Object.assign({}, user); 
     storedUser.id = id; 
     return storedUser; 
    } 
); 
} 

Cela fonctionne bien dans le cas où j'insère un objet unique. Cependant, je voudrais ajouter le support pour l'insertion de plusieurs objets qui appellent simplement la méthode pour une insertion simple. À l'heure actuelle c'est ce que j'ai, mais il ne fonctionne pas:

insertAll(users: User[]): Observable<User[]> { 
    return Observable.forkJoin(
    users.map(user => this.insert(user)) 
); 
} 

La méthode insertAll est l'insertion d'utilisateurs comme prévu (ou quelque chose d'autre a rempli la base de données avec les utilisateurs que), mais je ne reçois pas de réponse retour de celui-ci. Je déboguais ce qui se passe et semble que forkJoin obtient la réponse juste du premier utilisateur mappé, mais d'autres sont ignorés. Abonnement à insertAll ne fait rien, aussi il n'y a pas d'erreur, soit par l'intermédiaire de catch sur insertAll ou via le deuxième paramètre de souscrire à insertAll.

Je suis à la recherche d'une solution où le Observable (en insertAll) émettraient retour un tableau de nouveaux objets avec les utilisateurs sous cette forme:

[ 
    { 
    "id": 1, 
    "name": "John", 
    ... 
    }, 
    { 
    "id": 2, 
    "name": "Anna", 
    ... 
    }, 
    { 
    "id": 3, 
    "name": "Joe",, 
    ... 
    }, 
    { 
    "id": 4, 
    "name": "Alexandra", 
    ... 
    }, 
    ... 
] 

Je serais très heureux pour toute suggestion pointant dans la bonne direction. Merci d'avance!

+2

ne vois aucune erreur évidente. Il semble que seule la première promesse se résout. Êtes-vous sûr que la base de données supporte plusieurs promesses concurrentes? Que se passe-t-il si vous l'essayez simplement avec des promesses et «Promise.all»?(De plus, dans votre premier extrait de code, vous créez un 'storedUser', mais renvoyez' user' au lieu de 'storedUser'.) – cartant

+0

Merci pour cette suggestion, heureusement, il n'y a pas de problème avec les promesses concurrentes. Il y avait une faute de frappe dans cet exemple que j'ai corrigé maintenant. – user1257255

Répondre

2

Pour convertir un tableau en observable, vous pouvez utiliser Rx.Observable.from(array).

Pour convertir d'observable en tableau, utilisez obs.toArray(). Notez que cela retourne une observable d'un tableau, donc vous devez toujours .subscribe(arr => ...) pour le sortir.

Cela dit, votre code avec forkJoinest-il correct? Mais si vous ne voulez essayer from, écrire le code comme ceci:

insertAll(users: User[]): Observable<User[]> { 
    return Observable.from(users) 
    .mergeMap(user => this.insert(user)) 
    .toArray() 
); 
} 

Un autre plus rx comme façon de le faire serait d'émettre des valeurs telles qu'elles complète, et ne pas attendre tous comme forkJoin ou toArray Est-ce que. Nous pouvons omettez simplement le toArray de l'exemple précédent et nous l'avons obtenu:

insertAll(users: User[]): Observable<User> { 
    return Observable.from(users) 
    .mergeMap(user => this.insert(user)) 
); 
} 

Comme @cartant mentionné, le problème pourrait ne pas être dans Rx, il pourrait être votre base de données ne prend pas en charge les connexions multiples. Dans ce cas, vous pouvez remplacer le mergeMap avec concatMap pour faire Rx envoyer seulement 1 demande concurrente:

insertAll(users: User[]): Observable<User[]> { 
    return Observable.from(users) 
    .concatMap(user => this.insert(user)) 
    .toArray() // still optional 
); 
} 
+0

Merci! Quand j'ai changé 'forkJoin' en' from' et 'mergeMap' +' toArray' les choses ont commencé à fonctionner comme prévu. – user1257255