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

Firestore如何实现以UID为子集合名存储多分类文档

问题描述

我的数据库根目录有一个userCategories集合,应用中用户可添加名称唯一的分类,每个分类文档结构如下:

{
  createdAt: Timestamp.now(),
  categoryName: userDefinedCategoryName,
  color: randomColorCode
}

我期望的数据库结构为:

root-
  |-userCollection
      |-uid1
      |-uid2
  |-userCategories
      |-uid1
          |-{createdAt:...,categoryName:"...",color:"..."}
          |-{createdAt:...,categoryName:"...",color:"..."}
      |-uid2
          |-{createdAt:...,categoryName:"...",color:"..."}

当前我使用以下代码:

const categoryDocRef = doc(db, "userCategories", uid);
await setDoc(
  categoryDocRef, {
    createdAt: Timestamp.now(),
    categoryName: category,
    color: color
  }).then(() => {
    return {
      success: true,
      errorMessage: ""
    };
  });

但这只能在每个UID下创建单个文档,无法实现如uid1那样存储多个分类。

我尝试过另一种写法:

const categoryDocRef = doc(db, "userCategories", uid);
const colRef = collection(categoryDocRef, "Anything Here")
await addDoc(
  colRef, {
    createdAt: Timestamp.now(),
    categoryName: category,
    color: color
  }).then(() => {
    console.log(`User document for uid:${uid}`);
    return {
      success: true,
      errorMessage: ""
    };
  });

但这会生成多余的嵌套层级:

|-userCategories
    |-uid1
        |-anything here
            |-firebase generated id
                |-{createdAt:...,categoryName:"...",color:"..."}
                |-{createdAt:...,categoryName:"...",color:"..."}

我认为“firebase generated id”或“anything here”层级是多余的,可直接使用categoryName或自动生成ID来避免额外嵌套。请问是否有方法实现预期的结构?

解决方案

Firestore的层级规则是集合→文档→子集合→文档,要实现你预期的结构,有两种简洁的方案:

方案1:以UID作为子集合名称,分类文档直接存放在该子集合下

这种方案完全匹配你想要的结构,直接把每个用户的UID作为userCategories下的子集合名称,分类文档直接存入这个子集合(可以用自动生成ID或唯一的categoryName作为文档ID)。

代码示例(用自动生成ID):

// 直接创建以uid命名的子集合
const userCategoriesCol = collection(db, "userCategories", uid);
// 在子集合中添加分类文档
await addDoc(userCategoriesCol, {
  createdAt: Timestamp.now(),
  categoryName: category,
  color: color
}).then(() => {
  return {
    success: true,
    errorMessage: ""
  };
});

生成的结构:

root-
  |-userCategories
      |-uid1(子集合)
          |-自动生成ID文档1
              |-{createdAt:...,categoryName:"...",color:"..."}
          |-自动生成ID文档2
              |-{createdAt:...,categoryName:"...",color:"..."}
      |-uid2(子集合)
          |-自动生成ID文档1
              |-{createdAt:...,categoryName:"...",color:"..."}

代码示例(用categoryName作为文档ID,需保证名称唯一):

const categoryDocRef = doc(db, "userCategories", uid, category);
await setDoc(categoryDocRef, {
  createdAt: Timestamp.now(),
  categoryName: category,
  color: color
}).then(() => {
  return {
    success: true,
    errorMessage: ""
  };
});

生成的结构:

root-
  |-userCategories
      |-uid1(子集合)
          |-"分类1"文档
              |-{createdAt:...,categoryName:"分类1",color:"..."}
          |-"分类2"文档
              |-{createdAt:...,categoryName:"分类2",color:"..."}

方案2:扁平化结构,所有分类直接存放在userCategories集合中

如果不想用嵌套子集合,可以把所有分类文档直接放在userCategories集合里,每个文档额外携带uid字段,查询时通过uid过滤即可。

代码示例:

const categoryDocRef = doc(db, "userCategories"); // 自动生成文档ID
await setDoc(categoryDocRef, {
  uid: uid,
  createdAt: Timestamp.now(),
  categoryName: category,
  color: color
}).then(() => {
  return {
    success: true,
    errorMessage: ""
  };
});

查询用户分类的示例:

const querySnapshot = await getDocs(
  query(collection(db, "userCategories"), where("uid", "==", uid))
);
// 处理查询结果
querySnapshot.forEach(doc => {
  console.log(doc.data());
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 19:39:24