Angular Firebase中如何关联原材料与原材料库存两个集合?
关联Firebase Realtime Database中原材料库存与原材料数据的解决方案
我需要将Firebase Realtime Database中的**Raw materials stock(原材料库存)集合与Raw materials(原材料)**集合关联,每个库存文档包含rawMaterialKey,要通过这个key获取对应原材料的名称、编码等数据,合并到库存列表中。尝试两小时未找到可行方案,熟悉SQL和NoSQL但未遇到过这类场景。
数据结构示例
原材料库存文档
{ "factoryKey": "34", "quantity": "34", "rawMaterialKey": "-NDNPe47CDTbjmwGgW_3" }
原材料文档
{ "key": "-NDNPe47CDTbjmwGgW_3", "code": "R34", "name": "RAW2001" }
现有Angular服务代码
import {Injectable, OnInit} from '@angular/core'; import {LocalStoreService} from '../local-store.service'; import {AngularFirestore} from '@angular/fire/compat/firestore'; import {Router} from '@angular/router'; import { RawMaterialStock } from '../../interfaces/raw-materials/raw-materiels-stock'; import {AngularFireDatabase, AngularFireList, AngularFireObject } from '@angular/fire/compat/database'; @Injectable({ providedIn: 'root', }) export class RawMaterialsStockService implements OnInit { rawMaterialsStocksRef: AngularFireList<any>; rawMaterialsRef: AngularFireList<any>; rawMaterialStockRef: AngularFireObject<any>; private dbPathStock = '/raw_material_stock'; private dbPathRawMaterials = '/raw_material'; constructor( private store: LocalStoreService, private router: Router, private afs: AngularFirestore, private db: AngularFireDatabase ) { this.rawMaterialsStocksRef = db.list(this.dbPathStock); this.rawMaterialsRef = db.list(this.dbPathRawMaterials); } ngOnInit(): void { } // Methods getRawMaterialStockList() { return this.rawMaterialsStocksRef.snapshotChanges(['child_added']) .subscribe(actions => { // WHAT SHOULD I DO HERE ???? }); } }
解决方案
Firebase Realtime Database没有SQL式的JOIN操作,需手动关联数据,以下是两种可行实现方式:
方式一:逐个查询关联(适合小数据集)
遍历库存列表,通过rawMaterialKey单独查询对应原材料数据,合并后返回:
import { Observable, forkJoin, map } from 'rxjs'; // 定义合并后的接口(若未定义) export interface RawMaterialStockWithDetails extends RawMaterialStock { rawMaterialCode?: string; rawMaterialName?: string; } // 修改服务中的方法 getRawMaterialStockList(): Observable<RawMaterialStockWithDetails[]> { return this.rawMaterialsStocksRef.snapshotChanges(['child_added']).pipe( map(stockActions => { // 转换库存数据,提取key和value const stockList = stockActions.map(action => ({ key: action.key, ...action.payload.val() })) as RawMaterialStock[]; // 为每个库存创建获取原材料的Observable const combinedObservables = stockList.map(stock => { return this.db.object(`${this.dbPathRawMaterials}/${stock.rawMaterialKey}`).valueChanges().pipe( map(rawMaterial => ({ ...stock, rawMaterialCode: rawMaterial?.['code'], rawMaterialName: rawMaterial?.['name'] })) ); }); // 并行获取所有关联数据 return forkJoin(combinedObservables); }), map(combinedResults => combinedResults) ); }
方式二:先缓存原材料映射(适合大数据集)
先获取所有原材料数据并创建key: 原材料对象的映射,再遍历库存完成关联,减少重复请求:
import { Observable, forkJoin, map } from 'rxjs'; // 复用上面定义的RawMaterialStockWithDetails接口 getRawMaterialStockList(): Observable<RawMaterialStockWithDetails[]> { // 同时获取库存列表和原材料列表 return forkJoin([ this.rawMaterialsStocksRef.snapshotChanges(['child_added']), this.rawMaterialsRef.snapshotChanges(['child_added']) ]).pipe( map(([stockActions, rawMaterialActions]) => { // 转换库存数据 const stockList = stockActions.map(action => ({ key: action.key, ...action.payload.val() })) as RawMaterialStock[]; // 创建原材料映射表 const rawMaterialMap = new Map(); rawMaterialActions.forEach(action => { const rawMaterial = action.payload.val(); rawMaterialMap.set(rawMaterial.key, rawMaterial); }); // 关联库存与原材料数据 return stockList.map(stock => { const rawMaterial = rawMaterialMap.get(stock.rawMaterialKey); return { ...stock, rawMaterialCode: rawMaterial?.code, rawMaterialName: rawMaterial?.name } as RawMaterialStockWithDetails; }); }) ); }
组件中调用示例
import { Component, OnInit } from '@angular/core'; import { RawMaterialsStockService } from './path-to-service/raw-materials-stock.service'; import { RawMaterialStockWithDetails } from './path-to-service/raw-materials-stock.service'; @Component({ selector: 'app-raw-material-stock', templateUrl: './raw-material-stock.component.html' }) export class RawMaterialStockComponent implements OnInit { stockList: RawMaterialStockWithDetails[] = []; constructor(private stockService: RawMaterialsStockService) {} ngOnInit(): void { this.stockService.getRawMaterialStockList().subscribe(list => { this.stockList = list; console.log('关联后的库存列表:', list); }); } }
内容的提问来源于stack exchange,提问作者Sb Zakaria
相关产品推荐
相关产品推荐

