Firebase中使用{ merge:true }仍覆盖嵌套字段?求正确用法
问题:使用Firebase setDoc的
{ merge: true }仍导致嵌套字段被覆盖 我在注册数据时用了{ merge:true }来避免数据被覆盖,但实际操作后嵌套字段还是被覆盖了。请问我的用法是不是错了?还要加其他配置吗?
代码示例
const board = collection(db, "board"); const setBoard = async () => await setDoc( doc(board, "items"), { name: name, price: price, category: kind, size: { default: { small: size.includes("s") === true && "s", medium: size.includes("m") === true && "m", large: size.includes("l") === true && "l", extralarge: size.includes("xl") === true && "xl", twoextralarge: size.includes("xxl") === true && "xxl", }, }, description: description, }, { merge: true } ); const handleSubmit = (e) => { e.preventDefault(); setBoard(); console.log(board); ... }; return ( <form onSubmit={handleSubmit}> ... <button>제품 등록하기</button> </form> ); }
更新前数据

更新后数据

期望结果

解决方案
你遇到的问题是因为setDoc的merge: true只会合并顶层字段,但对于嵌套对象(比如这里的size.default),你传入的是一个完整的新对象,Firebase会直接用这个新对象替换原来的size.default,而不是合并里面的子字段。
要实现嵌套字段的合并,你有两种可行方案:
方案1:使用点符号路径指定要更新的嵌套字段
把要更新的嵌套子字段拆成顶层的路径形式,这样Firebase会单独更新这些子字段,不会覆盖整个size.default对象:
await setDoc( doc(board, "items"), { name: name, price: price, category: kind, "size.default.small": size.includes("s") && "s", "size.default.medium": size.includes("m") && "m", "size.default.large": size.includes("l") && "l", "size.default.extralarge": size.includes("xl") && "xl", "size.default.twoextralarge": size.includes("xxl") && "xxl", description: description, }, { merge: true } );
方案2:使用updateDoc替代setDoc
如果你的需求是仅更新现有文档的部分字段,updateDoc本身就是用来增量更新的,不需要额外的merge配置,同样可以用点符号指定嵌套字段:
const updateBoard = async () => await updateDoc( doc(board, "items"), { name: name, price: price, category: kind, "size.default.small": size.includes("s") && "s", "size.default.medium": size.includes("m") && "m", "size.default.large": size.includes("l") && "l", "size.default.extralarge": size.includes("xl") && "xl", "size.default.twoextralarge": size.includes("xxl") && "xxl", description: description, } );
额外优化:避免设置false值
如果用户没选中某个尺寸(比如没选s),size.includes("s")会返回false,Firebase会把对应字段设为false。如果你想保留原来的字段值而不是设为false,可以先判断,只添加选中的字段:
const updateFields = { name: name, price: price, category: kind, description: description, }; if (size.includes("s")) updateFields["size.default.small"] = "s"; if (size.includes("m")) updateFields["size.default.medium"] = "m"; if (size.includes("l")) updateFields["size.default.large"] = "l"; if (size.includes("xl")) updateFields["size.default.extralarge"] = "xl"; if (size.includes("xxl")) updateFields["size.default.twoextralarge"] = "xxl"; await setDoc(doc(board, "items"), updateFields, { merge: true });
这样就能实现你想要的嵌套字段合并效果,不会覆盖未修改的子字段。
内容的提问来源于stack exchange,提问作者white
相关产品推荐
相关产品推荐

