You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 10:15:26