You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Firebase中用户与股票对象的关联关系设置方案咨询

嘿,刚看了你的问题,正好我在Firebase里处理过类似的用户-实体关联场景,给你梳理下最优的存储方案和查询实现思路,解决你遇到的查询限制和文档大小问题~

先聊聊你原来方案的核心问题

你之前在Stock文档里加watchedBy字段的思路,确实能快速实现“查询用户关注的股票”,但有两个致命问题:

  • 没法直接查未关注的股票:Firebase Firestore的查询是基于「存在的字段/值」的,没法直接筛选出“不包含某个用户ID”的文档;
  • 单文档大小限制风险:如果某只热门股票被数百万用户关注,watchedBy里的键值对会疯狂膨胀,很快就会触碰到Firestore单文档1MB的上限,而且多个用户同时更新同一个Stock文档,还容易出现并发冲突。

推荐两种最优存储方案

方案一:用中间关联集合(最灵活、扩展性最强)

这是类似关系型数据库“关联表”的思路,专门创建一个userWatchedStocks集合,每个文档代表一个用户关注一只股票的关联关系,结构非常简单:

// userWatchedStocks集合的文档示例
{
  userId: "joeUserId",
  stockId: "googlStockId",
  createdAt: Timestamp.fromDate(new Date()) // 可选,记录用户关注的时间,方便后续排序
}
如何实现你的两个查询需求:
  1. 获取Joe关注的所有股票
    先从userWatchedStocks里筛选出Joe的所有关联记录,拿到对应的股票ID列表,再批量查询stocks集合获取股票详情。代码示例:

    import { getDocs, collection, where } from "firebase/firestore";
    
    // 第一步:获取Joe关注的股票ID列表
    const watchedRef = collection(db, "userWatchedStocks");
    const querySnapshot = await getDocs(where(watchedRef, "userId", "==", "joeUserId"));
    const stockIds = querySnapshot.docs.map(doc => doc.data().stockId);
    
    // 第二步:批量查询股票详情(注意Firestore的in查询最多支持10个值,超过的话需要拆分批次)
    const stocksRef = collection(db, "stocks");
    const stocksSnapshot = await getDocs(where(stocksRef, "__name__", "in", stockIds));
    const watchedStocks = stocksSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
    
  2. 获取Joe未关注的所有股票
    这里分两种场景处理:

    • 如果你的股票总数不多(比如几千只以内):直接查询所有股票,再过滤掉Joe已关注的ID即可,实现简单,带宽消耗也可控;
    • 如果股票数量极大(上万甚至更多):可以配合Firebase的第三方搜索扩展(比如Algolia),把用户已关注的股票ID作为过滤条件,直接搜索出未关注的股票,效率会高很多。
这个方案的优势:
  • 完全避开单文档大小限制,每个关联都是独立文档,哪怕有百万用户关注同一只股票也没问题;
  • 并发安全:用户关注/取消关注时,只修改自己的关联文档,不会和其他用户的操作冲突;
  • 灵活扩展:后续可以轻松实现“统计某只股票的关注人数”“按关注时间排序用户的股票列表”等需求。

方案二:在User文档中存储关注的股票ID数组(适合小体量场景)

如果你的业务场景中,每个用户关注的股票数量肯定不多(比如几百只以内,远低于1MB限制),可以直接在User文档里加一个watchedStockIds数组:

// User文档示例
{
  firstName: "Joe",
  lastName: "Smith",
  watchedStockIds: ["googlStockId", "aaplStockId"]
}
查询实现:
  • 获取Joe关注的股票:直接从User文档读取watchedStockIds,再批量查询stocks集合即可,比方案一少一次查询;
  • 获取Joe未关注的股票:和方案一思路一致,小体量用全量过滤,大体量用搜索扩展。
这个方案的优缺点:
  • 优点:查询逻辑更简单,少一次数据库请求;
  • 缺点:如果用户关注的股票数量持续增加,数组会越来越大,可能触碰到文档大小限制;而且更新数组时(比如取消关注)需要修改整个数组,并发场景下需要用事务避免冲突。

方案选择建议

  • 如果你的业务未来有大量用户、大量股票的可能性,优先选方案一,扩展性和稳定性拉满;
  • 如果是小体量的Demo或者确定用户关注的股票数量极少,可以选方案二,实现更快。

最后补充个小提示:记得给需要的查询创建复合索引,比如方案一中userWatchedStocksuserId字段索引,Firestore会在你第一次执行查询时提示你创建,直接点击链接就能生成,非常方便。

内容的提问来源于stack exchange,提问作者Vafilor

火山引擎 最新活动