更新firestore文档中嵌套对象中的字段?

Posted

技术标签:

【中文标题】更新firestore文档中嵌套对象中的字段?【英文标题】:Update fields in nested objects in firestore documents? 【发布时间】:2018-08-15 11:54:45 【问题描述】:

我有一个像这样的数据结构:

我想编辑“first”对象中“test”键的值。我关注了https://firebase.google.com/docs/firestore/manage-data/add-data上的文档

但它对我不起作用。

nodejs代码:

var setAda = dbFirestore.collection('users').doc('alovelace').update(
        first : 
            test: "12345"
            
);

firestore 中的结果:

“test2”键不见了。但是,我只想更新“test”的值并保留“test2”。

这个问题有什么解决办法吗?

【问题讨论】:

【参考方案1】:

根据您提供的链接,它是这样说的:

如果您的文档包含嵌套对象,您可以在调用 update() 时使用“点表示法”来引用文档中的嵌套字段:

因此你需要使用dot notation 才能只更新一个字段而不覆盖,所以像这样:

var setAda = dbFirestore.collection('users').doc('alovelace').update(
    "first.test": "12345"
);

那么你将拥有:

 first
  test: "12345"
  test2: "abcd"

【讨论】:

从文档中不清楚使用DocumentReference.update 的第二种类型签名时行为会有所不同,这会导致硬写入:firebase.google.com/docs/reference/js/… 如果我想删除test映射的test.first条目,是否需要执行get()操作,手动删除它,然后更新整个first映射?或者是否有类似的操作来删除地图中的嵌套字段? @彼得 @ppicom 你需要做这样的事情update("first.test" :firebase.firestore.FieldValue.delete()); 由于某种原因,这不适用于 .set(..., merge: true)。 你试过下面的***.com/a/57217966/7015400@rendom吗?【参考方案2】:

试试这个: 是这样的吗?

var setAda = dbFirestore.collection('users').doc('alovelace').update(
        "first.test" : "12345"
);

【讨论】:

【参考方案3】:

如果有人使用 TypeScript(例如在 Cloud 函数中),这里是用点符号更新嵌套字段的代码。

var setAda = dbFirestore.collection('users').doc('alovelace').update(
    `first.$variableIfNedded.test`: "12345"
);

【讨论】:

@Vino 确保您使用的是 TypeScript。您使用的代码到底是什么? 当我尝试像 saveData[`picks.$matchId.points`] = pickValue; 这样的方法时,其中 saveData 是我最终写入 firebase 的地图。我得到了一个名为“picks.94904.points”的新属性,而不是写入地图。我是打字稿的新手,所以我假设有语法错误。任何想法为什么会发生这种情况? @Chamanhm,你的代码过于复杂了。试着让它更简单。祝你好运【参考方案4】:

Peter 的解决方案很棒,但它不适用于动态键。以下代码可以使用它:

var nestedkey = 'test';
var setAda = dbFirestore.collection('users').doc('alovelace').update(
    [`first.$nestedkey`]: "12345"
);

【讨论】:

这与彼得的解决方案基本相同,只是它使用模板字符串... 非常感谢。我试过 $nestedKey 但直到我用 [] 畏缩它才起作用。 试图编辑掉不必要的“此代码要好得多”部分,结果错误为“编辑队列已满” @Sam 已编辑。谢谢。【参考方案5】:

对于那些需要更通用和递归的人,这里有一个函数可以使用打字稿 Partial 非破坏性地更新 Foo Firestore 文档:

private objectToDotNotation(obj: Partial<Foo>, parent = [], keyValue = ) 
    for (let key in obj) 
        let keyPath = [...parent, key];
        if (obj[key]!== null && typeof obj[key] === 'object')
            Object.assign(keyValue, this.objectToDotNotation(obj[key], keyPath, keyValue));
        else
            keyValue[keyPath.join('.')] = obj[key];
    
    return keyValue;


public update(foo: Partial<Foo>) 
    dbFirestore.collection('foos').doc('fooId').update(
        this.objectToDotNotation(foo)
    )

【讨论】:

【参考方案6】:

如果您不希望在 'first' 字段不存在时发生异常,请尝试使用带有merge: true 选项的set 而不是update

var setAda = dbFirestore.collection('users').doc('alovelace').set(
        first : 
            test: "12345"
        
, merge: true);

【讨论】:

【参考方案7】:

对于 Swift 4

let dictionary:[String:Any] = ["first.test" : "12345"]
let plansDocumentReference = Firestore.firestore().collection("users").document("alovelace")              
plansDocumentReference.updateData(dictionary)  err in
                if let err = err 
                    print("Error updating document: \(err)")

                

您可以通过向字典中添加记录来更新多个字段,也可以通过将字典中的固定文本替换为字符串变量来构建基于变量的子键。

此技术还可以通过使用字典作为任何键的值来替换文档中的整个单个键子块

【讨论】:

【参考方案8】:

我正在寻找一个没有额外参数的打字稿版本,考虑到类型完成......最终得到以下结果:

TS Playground example

function objectToDotNotation(obj: any): any 

    return Object.keys(obj).reduce( (dnObj, key) => 
        const value = obj[key];

        if (value !== null && typeof value === 'object')             
            const childObj = objectToDotNotation(value);

            Object.keys(childObj).forEach( childKey => 
                dnObj = ...dnObj, [`$key.$childKey`]: childObj[childKey] ;
            );
         else             
            dnObj = ...dnObj, [key]: value ;
        

        return dnObj;
    , );

【讨论】:

【参考方案9】:

使用set 函数并在选项中传递merge: true 来更新深度嵌套的字段而不覆盖其他字段。

const firstore = firebase.firestore()
const ref = firestore.doc('users/alovelace').set(
  first : 
    test: "12345"
  
,  merge: true )

使用此方法,您可以更新一个字段,即使它被埋在 20 层深处。

【讨论】:

以上是关于更新firestore文档中嵌套对象中的字段?的主要内容,如果未能解决你的问题,请参考以下文章

在 Firestore 中更新嵌套在 Array 中的对象

Firestore 更新数组字段中的单个项目

Firestore使用Rest API更新文档字段

在嵌套对象中使用firestore的FieldPath.documentId()

更新 Firestore 数据库中文档的字段

如何使用flutter更新firestore中所有文档的单个字段?