AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / user-11820228

Kiran's questions

Martin Hope
Kiran
Asked: 2025-04-07 22:15:15 +0800 CST

Como combinar respostas usando merge() e from() do RxJS

  • 6

Preciso fazer nchamadas http (definidas pelo usuário). As URLs são geradas programaticamente a partir das entradas do usuário. Cada mês deve ser consultado separadamente, dependendo ndo intervalo de datas selecionado pelo usuário. No exemplo abaixo, desejo consultar 1 ano de dados, então o conjunto de URLs ficaria assim:

[
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202301&sql=SELECT * from `EPD_202301` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202302&sql=SELECT * from `EPD_202302` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202303&sql=SELECT * from `EPD_202303` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202304&sql=SELECT * from `EPD_202304` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202305&sql=SELECT * from `EPD_202305` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202306&sql=SELECT * from `EPD_202306` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202307&sql=SELECT * from `EPD_202307` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202308&sql=SELECT * from `EPD_202308` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202309&sql=SELECT * from `EPD_202309` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202310&sql=SELECT * from `EPD_202310` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202311&sql=SELECT * from `EPD_202311` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5",
    "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202312&sql=SELECT * from `EPD_202312` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5"
]

Gostaria que os resultados fossem combinados em uma matriz de dados. Gostaria que cada resposta fosse preenchida na matriz assim que chegasse.

Fiz um curso de RxJS para iniciantes e descobri que ele merge()é o mais adequado para isso. No entanto, o curso diz para fazer o seguinte:

import { merge } from 'rxjs';
import { ajax } from 'rxjs/ajax';

const url1 = "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202301&sql=SELECT * from `EPD_202301` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5";
const url2 = "https://opendata.nhsbsa.net/api/3/action/datastore_search?resource_id=EPD_202302&sql=SELECT * from `EPD_202302` WHERE BNF_CODE = '0410030C0AAAFAF' AND PRACTICE_CODE = 'Y03641' LIMIT 5";

const arr = [];
const observer = {
    next: (x) => arr.push(x),
    complete: () => console.log(arr),
}

const merged$ = merge(
    ajax.getJSON(url1),
    ajax.getJSON(url2),
);

merged$.subscribe(observer);

Isso atende às minhas necessidades, mas não posso especificar explicitamente cada URL. Não sei quantas serão, então elas são armazenadas em uma matriz.

Então descobri que isso from()poderia ajudar:

from(urls).pipe(
    merge((url: any) => this.getDatastoreSearchMonthly(url))
);

Entretanto, estou recebendo um erro de TypeScript:

Argument of type 'Observable<unknown>' is not assignable to parameter of type 'OperatorFunction<string, DatastoreSearch[]>'.
  Type 'Observable<unknown>' provides no match for the signature '(source: Observable<string>): Observable<DatastoreSearch[]>'.ts(2345)
No overload matches this call.
  The last overload gave the following error.
    Argument of type '(url: string) => Observable<unknown>' is not assignable to parameter of type 'number | ObservableInput<unknown> | SchedulerLike'.ts(2769)
nhs-api.service.ts(76, 19): Did you mean to call this expression?
merge.d.ts(8, 25): The last overload is declared here.

Meu serviço completo:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { from, map, merge, Observable } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { DatastoreSearch, DatastoreSearchSql } from 'src/app/types/nhs-api/epd';
import * as moment from 'moment';

const baseUrl = 'https://opendata.nhsbsa.net/api/3/action/datastore_search';
type Options = {
    startDate: moment.Moment,
    endDate: moment.Moment,
    practiceCode: string,
    bnfCode: string,
}

@Injectable({
    providedIn: 'root'
})
export class NhsApiService {

    constructor(private http: HttpClient) { }

    public getDatastoreSearch(options: string): Observable<DatastoreSearch> {
        const url = `${baseUrl}?${options}`;
        return this.http.get<DatastoreSearch>(url);
    }

    public getDatastoreSearchSql(resourceId: string, sql: string): Observable<DatastoreSearchSql> {
        const url = `${baseUrl}?resource_id=${resourceId}&sql=${sql}`;
        return this.http.get<DatastoreSearchSql>(url);
    }

    private getDatastoreSearchMonthly(url: string): Observable<DatastoreSearch> {
        return this.http.get<DatastoreSearch>(url);
    }

    private getUrls(options: Options): string[] {
        // Ensure first day of month is selected
        const startDate = options.startDate.startOf('month');
        const endDate = options.endDate.startOf('month');

        const urls = [];

        const includeSearchTerm = (key: string, field: string) => options[key] ? `${field} = '${options[key]}' AND ` : '';
        const removeJoiningTerm = (sql: string, term: string) => sql.endsWith(term) ? sql.substring(0, sql.length - term.length).trim() : sql;

        const getSql = (resourceId: string): string => {
            const tableName = '`' + resourceId + '`';
            let sql = `SELECT * from ${tableName} WHERE `;
            sql += includeSearchTerm('bnfCode', 'BNF_CODE');
            sql += includeSearchTerm('practiceCode', 'PRACTICE_CODE');
            sql = sql.trim();
            sql = removeJoiningTerm(sql, 'AND');
            sql = removeJoiningTerm(sql, 'WHERE');
            sql = `${sql} LIMIT 5`
            return sql;
        }

        for (const m = startDate; m.isSameOrBefore(endDate); m.add(1, 'month')) {
            const dt = m.format('YYYYMM');
            const resourceId = `EPD_${dt}`;
            const sql = getSql(resourceId);
            const url = `${baseUrl}?resource_id=${resourceId}&sql=${sql}`;
            urls.push(url);
        }

        console.log(urls);

        return urls;
    }

    public getMonthlyData(options: Options): Observable<DatastoreSearch[]> {
        const urls = this.getUrls(options);

        return from(urls).pipe(
            merge((url: string) => ajax.getJSON(url))
        );
    }
}

E o componente que o chama:

import { Component, OnInit, signal } from '@angular/core';
import { MomentDateAdapter } from '@angular/material-moment-adapter';
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
import { FormGroup, NonNullableFormBuilder } from '@angular/forms';
import { MONTH_YEAR_FORMATS } from 'src/app/config/dates';
import { DatastoreSearch } from 'src/app/types/nhs-api/epd';
import { Observable } from 'rxjs';
import { NhsApiService } from 'src/app/services/nhs-api/nhs-api.service';
import * as moment from 'moment';

@Component({
    selector: 'app-nhs-api-scratch',
    templateUrl: './scratch.component.html',
    styleUrls: ['./scratch.component.scss'],
    providers: [
        { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] },
        { provide: MAT_DATE_FORMATS, useValue: MONTH_YEAR_FORMATS },
    ],
})
export class ScratchComponent implements OnInit {

    public form!: FormGroup;

    public data$: Observable<DatastoreSearch[]> = new Observable();

    readonly panelOpenState = signal(false);

    constructor(
        private fb: NonNullableFormBuilder,
        private readonly service: NhsApiService,
    ) { }

    public ngOnInit(): void {
        this.form = this.fb.group({
            practiceCode: this.fb.control('Y03641'),
            bnfCode: this.fb.control('0410030C0AAAFAF'),
            startDate: this.fb.control(moment('2023-01-01')),
            endDate: this.fb.control(moment('2023-12-01')),
        });
    }

    public onSubmit() {
        this.data$ = this.service.getMonthlyData(this.form.value);
    }
}

angular
  • 2 respostas
  • 45 Views

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve