Firestore:将自定义对象添加到数据库。

25

早上好,

我尝试添加一个从这个类创建的新对象:

export class Sponsor implements ISponsor {

  title: string;    
  description?: string;
  creation: ICreation;

  constructor(title: string, description: string, author: string) {
     this.title = title;
     this.description = description;
     this.creation = new Creation(author);
  }
}

在我的服务中,create函数看起来像这样:

createSponsor(sponsor) {
   sponsor.id = this.afs.createId();
   return this.collection.doc(sponsor.id).set(sponsor);
}

当我尝试这种方式时,我会收到以下错误:

FirebaseError:[code=invalid-argument]:使用无效数据调用DocumentReference.set()函数。数据必须是对象,但是它是:自定义赞助商对象

我该如何解决这个问题?

10个回答

33
你也可以使用 Object.assign({}, sponsor)。
所以在你的情况下,它将是:
this.collection.doc(sponsor.id).set(Object.assign({}, sponsor));

1
这个可行,但我觉得它很“hack-ish”。为什么Firebase没有正确处理这个的方式? - Bjarne Gerhardt-Pedersen
4
这个方法可以正常运行,但需要注意的是 Object.assign 方法不能进行深拷贝。 - Quethzel Díaz
3
不适用于嵌套对象。 - Viacheslav Dobromyslov

24

您还可以将对象序列化为JSON,然后将其反序列化回普通的JavaScript对象,例如:

this.collection.doc(sponsor.id).set(JSON.parse( JSON.stringify(sponsor)));

适用于深度嵌套。


你使用这种方法遇到过任何限制吗?我会认为查询数据会更加困难,不知道我是否错了? - Ruben Szekér
3
保存到Firestore时,这将破坏时间戳对象。 - GorvGoyl

8

哪种方法是推荐的? - João Eudes Lima
我发现使用 '.set(classToPlain(yourObject))' 的组合效果很好。 - Alex Marchant
1
最近,Firebase 新增了一个名为 withConverter 的函数。你可以通过将 classToPlainplainToClass 传递给它来使用。这样可以使你的代码更加清晰。(完)https://firebase.google.com/docs/reference/node/firebase.firestore.FirestoreDataConverter - Jürgen Brandstetter

6
感谢Fabian Wiles - 我明白了!
尽管Firebase可以将您的对象数据发送到数据库中,但当数据返回时,它无法将其实例化为您的类的实例。因此,不允许使用类。
只需保存一个如下所示的对象即可:
interface Person{
  name: string;
  age: number
}

var person: Person = { name: 'Toxicable', age: 22} ;

1
只要您仅使用接口而不是类构造函数,这就没问题。 - Bjarne Gerhardt-Pedersen

3

不确定我是否漏掉了什么,但现在似乎有一个更简单的解决方案。

只需使用扩展运算符将类实例“展开”到一个空对象中,例如{...myClass}

let myClass = new ClassInstance(
  "newClass",
  "This is a new class instance"
);

addDoc(dbReference, { ...myClass }).then(() => {
 console.log("Document successfully written!");
});

2

我的解决方案中有一个 Interface

export interface Launch {
 id: string;
 date: Date;
 value: number;

}

将project声明为Launch类型的空对象。

将project添加到名为'launches'的集合中。


1

Firebase 的行为真的很奇怪。我通过创建新接口并将转换方法添加到我的类中来解决了这个问题:

export class Happening {
 constructor(
  public date: EventDate,
  public participants: Array<string>,
  public title: string,
  public text: string,
  public uid?: string,
  public id?: string
 ){}

 public toDto = (): HappeningDto => {
  return {
    date: {
      year: this.date.year,
      month: this.date.month,
      day: this.date.day
    },
    participants: this.participants ? this.participants : [],
    title: this.title,
    text: this.text ? this.text : '',
    uid: this.uid,
    id: this.id ? this.id : null
  }
 }
}

export interface HappeningDto {
 date: {
  year: number,
  month: number,
  day: number
 },
 participants: Array<string>,
 title: string,
 text: string,
 uid?: string,
 id?: string
}

现在,我可以做到

add(event: Happening){
  event.uid = this.uid;
  this.$afs.collection<HappeningDto>('events').add(event.toDto())
    .then(
      (success) => console.log(success),
      (err) => console.warn(err)
    )
}

0
如果您使用Angular和AngularFire2,您可以使用AngularFirestype。该模块旨在替换AngularFirestore,并允许直接使用自定义对象获取和设置Firestore数据。
为此,需要执行3个步骤:

1. 安装angular-firestype

`npm install angular-firestype --save`

2.使用映射对象初始化AngularFire类型模块

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AngularFireModule } from 'angularfire2';
import { AngularFireAuthModule } from 'angularfire2/auth';
import { AngularFirestypeModule, ModelType } from 'angular-firestype';
import { environment } from '../environments/environment';

import { User } from './user.ts';
import { Address } from './address.ts';
import { Message } from './message.ts';

/**
 * Definition of the app model mapping.
 * For more information, see https://github.com/bricepepin/angular-firestype#mapping-object.
 */
const model: {[key: string]: ModelType<any>} = {
  users: {
    type: User,
    arguments: ['username', 'image'],
    structure: {
      adress: Address
    },
    subcollections: {
      messages: Message
    }
  }
};

@NgModule({
 imports: [
   AngularFireModule.initializeApp(environment.firebase),
   AngularFireAuthModule,
   AngularFirestypeModule.forRoot(model),   // Import module using forRoot() to add mapping information
 ],
 declarations: [ AppComponent ],
 bootstrap: [ AppComponent ]
})
export class AppModule {}

3. 注入AngularFireType服务

import { Component } from '@angular/core';
import { AngularFirestype, Collection, Document } from 'angular-firestype';

import { User } from './user.ts';

@Component({
 selector: 'app-root',
 templateUrl: 'app.component.html',
 styleUrls: ['app.component.css']
})
export class AppComponent {
   const users: Observable<User[]>;
   const user: User;

   constructor(db: AngularFirestype) {
       const usersCollection: Collection<User> = db.collection<User>('users');
       usersCollection.valueChanges().subscribe(users => this.users = users);

       const userDoc: Document<User> = usersCollection.doc('user1');
       userDoc.valueChanges().subscribe(user => this.user = user);
       userDoc.set(this.user);
   }
}

你可以基本上像使用Angularfirestore一样使用AngularFirestype。
更多细节请参见此处的主页:https://github.com/bricepepin/angular-firestype


0
export class Sponsor implements ISponsor {
  title: string;    
  description?: string;
  creation: ICreation;

  constructor(title: string, description: string, author: string) {
     this.title = title;
     this.description = description;
     this.creation = new Creation(author);
  }

 toJson(){
   return {
     title:this.title,
     description:this.description,
     creation:this.creation
   }
}

在服务中,create函数将会长成这样:

createSponsor(sponsor) {
   sponsor.id = this.afs.createId();
   return this.collection.doc(sponsor.id).set(sponsor.toJson());
}

0

我在使用Vue和Nuxt时遇到了类似的问题。

firebase.firestore().collection('example')
   .doc()
   .set({
       'foo' : 'boo'
   })

错误:

Data must be an object, but it was: a custom Object object

这个链接帮了我


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接