Firebase Javascript/Typescript映射兼容性

Firebase Javascript/Typescript映射兼容性,javascript,typescript,firebase,google-cloud-firestore,Javascript,Typescript,Firebase,Google Cloud Firestore,当我尝试将映射写入firebase时,遇到以下错误: FirebaseError: Function DocumentReference.set() called with invalid data. Unsupported field value: a custom Map object (found in field documentData.elements) 我希望将映射而不是数组写入firebase,以便能够合并数据集而不覆盖整个数组,而只添加或删除映射的条目。 然而,即使fireb

当我尝试将映射写入firebase时,遇到以下错误:

FirebaseError: Function DocumentReference.set() called with invalid data. Unsupported field value: a custom Map object (found in field documentData.elements)
我希望将映射而不是数组写入firebase,以便能够合并数据集而不覆盖整个数组,而只添加或删除映射的条目。 然而,即使firebase文档说它支持地图,我也无法让地图工作

我的界面如下所示:

export interface Element {
   uid:string;
   value:string;
}
export interface DocumentData {
    uid: string;
    elements: Map<string, Element>;
}

有人知道怎么把地图写进仓库吗?这实际上是地图的问题还是我使用的设置错误?

Firestore只接受包含要写入文档的字段和值的普通旧JavaScript对象。它不接受ES6映射对象,这是非常不同的事情

只需构建对象并将其传递给
set()

我建议参考更多的例子。Java支持映射对象,但JavaScript不支持


上面的代码将更新两个字段,“元素”将是Firestore映射类型字段。

我创建了一个方法,将映射写入平面对象,并添加一个字段,说明此成员是映射,因此从firebase获取时,可以将其放回到到目前为止运行良好的原始对象中

export function toFlatObject(data: any) {
    if (!data) {
        return null;
    }

    const obj: any = {};
    for (const [dataKey, dataValue] of Object.entries(data)) {
        if (dataValue instanceof Map) {
            const mapObj: any = {};
            dataValue.forEach((value, key) => {
                Object.defineProperty(mapObj, key.toString(), {
                    value: interfaceDataToFlatObject(value),
                    writable: true,
                    enumerable: true,
                });
            });
            Object.defineProperty(mapObj, "dataStructureIsMap", {
                value: true,
                writable: true,
                enumerable: true,
            });
            Object.defineProperty(obj, dataKey.toString(), {
                value: mapObj,
                writable: true,
                enumerable: true,
            });
        } else if (dataValue instanceof Object) {
            Object.defineProperty(obj, dataKey, {
                value: interfaceDataToFlatObject(dataValue),
                writable: true,
                enumerable: true,
            });
        } else {
            Object.defineProperty(obj, dataKey, {
                value: dataValue,
                writable: true,
                enumerable: true,
            });
        }
    }
    return obj;
}

我知道我有点晚了,但我开发了一个非常有效的解决方案,希望与大家分享

最初,我在搜索一些不相关的东西时发现,它工作得很好,但实现中存在一些问题(请参见问题列表)。最后,我通过扩展Map()类并从上面的GIT中借用一些代码创建了一个新的解决方案

   class MyMap<K, V> extends Map<K, V> {
        
        /**
         * Outputs the contents of the map to a JSON object
         * 
         * @returns {{[key: string]: V}} 
         * @memberof MyMap
         */
        public toJSON(): { [key: string]: V } {
            const obj = {}
    
            const getValue = (value: any): any => {
                if (value instanceof MyMap) {
                    return value.toJSON()
                } else if (Array.isArray(value)) {
                    return value.map(v => getValue(v))
                } else {
                    return value
                }
            }
    
            for (const [key, value] of this) {
                obj[String(key)] = getValue(value)
            }
            return obj
        }
    }
类MyMap扩展了Map{
/**
*将映射的内容输出到JSON对象
* 
*@returns{{[key:string]:V}
*@memberofmymap
*/
public-toJSON():{[key:string]:V}{
常量obj={}
const getValue=(值:any):any=>{
if(MyMap的值实例){
返回值。toJSON()
}else if(Array.isArray(值)){
返回值.map(v=>getValue(v))
}否则{
返回值
}
}
for(此项的常量[键,值]){
obj[字符串(键)]=getValue(值)
}
返回obj
}
}
我对Firestore文档成功运行了以下测试:

// Instance
const mapTerms= new MyMap<string, string>()

// Add some items (I had this within a loop)
mapTerms.set(doc.id, doc.data().text)

// Write is as a map object into Firestore
await db.doc(<my doc path>).set({
    text: currentTermsOfUse,
    map: mapTerms.toJSON()
})
//实例
const mapTerms=new MyMap()
//添加一些项目(我在一个循环中有这个)
mapTerms.set(doc.id,doc.data().text)
//将其作为映射对象写入Firestore
等待db.doc().set({
文本:currentTermsOfUse,
map:mapTerms.toJSON()
})

您可以使用自定义类型存储映射结构,而无需使用es6映射。 检查以下元素类型

导出类型元素={
关键字:字符串
名称:字符串;
类型:字符串;
}
导出类型元素={[key:string]:元素}
//在元素中添加元素的步骤
常量元素:元素={
键:“键1”,
姓名:'我的姓名',
类型:“myType”,
}
常量元素={[`${element.key}`]:element};
//使用键访问元素中的元素
常量element1=元素['key1'];
//访问元素集中的第一个元素
常量element2=elements[Object.keys(elements)[0]];
//贮藏
app.firestore().collection('a')。添加(元素);
//或
app.firestore().collection('a').doc('doc').set(元素,合并:true);
   class MyMap<K, V> extends Map<K, V> {
        
        /**
         * Outputs the contents of the map to a JSON object
         * 
         * @returns {{[key: string]: V}} 
         * @memberof MyMap
         */
        public toJSON(): { [key: string]: V } {
            const obj = {}
    
            const getValue = (value: any): any => {
                if (value instanceof MyMap) {
                    return value.toJSON()
                } else if (Array.isArray(value)) {
                    return value.map(v => getValue(v))
                } else {
                    return value
                }
            }
    
            for (const [key, value] of this) {
                obj[String(key)] = getValue(value)
            }
            return obj
        }
    }
// Instance
const mapTerms= new MyMap<string, string>()

// Add some items (I had this within a loop)
mapTerms.set(doc.id, doc.data().text)

// Write is as a map object into Firestore
await db.doc(<my doc path>).set({
    text: currentTermsOfUse,
    map: mapTerms.toJSON()
})