我只是在探索新的Firebase Firestore,它包含一个称为引用的数据类型。我不清楚这是干什么的。

它像外键吗? 它可以用来指向位于其他地方的集合吗? 如果引用是一个实际的引用,我可以使用它查询吗?例如,我是否可以有一个直接指向用户的引用,而不是将userId存储在文本字段中?我可以使用这个用户引用进行查询吗?


当前回答

迟来的是,这个博客有两个好处:

如果我希望按评分、发布日期或最多的赞来排序餐厅评论,我可以在评论子集合中做到这一点,而不需要复合索引。在更大的顶级集合中,我需要为其中的每一个创建一个单独的复合索引,而且我还有200个复合索引的限制。

我不会有200个综合指数,但有一些限制。

此外,从安全规则的角度来看,基于存在于父文档中的某些数据来限制子文档是相当常见的,当您将数据设置在子集合中时,这要容易得多。

例如,如果用户没有父字段的权限,则限制插入子集合。

其他回答

2022年更新

let coursesArray = [];
const coursesCollection = async () => {
    const queryCourse = query(
        collection(db, "course"),
        where("status", "==", "active")
    )
    onSnapshot(queryCourse, (querySnapshot) => {
        querySnapshot.forEach(async (courseDoc) => {

            if (courseDoc.data().userId) {
                const userRef = courseDoc.data().userId;
                getDoc(userRef)
                    .then((res) => {
                        console.log(res.data());
                    })
            }
            coursesArray.push(courseDoc.data());
        });
        setCourses(coursesArray);
    });
}

对于那些寻找通过引用查询的Javascript解决方案的人来说,概念是,你需要在查询语句中使用一个“文档引用”对象

teamDbRef = db.collection('teams').doc('CnbasS9cZQ2SfvGY2r3b'); /* CnbasS9cZQ2SfvGY2r3b being the collection ID */
//
//
db.collection("squad").where('team', '==', teamDbRef).get().then((querySnapshot) => {
  //
}).catch(function(error) {
  //
});

(答案在这里:https://stackoverflow.com/a/53141199/1487867)

引用很像外键。

当前发布的sdk不能存储对其他项目的引用。在项目中,引用可以指向任何其他集合中的任何其他文档。

您可以像使用任何其他值一样在查询中使用引用:用于过滤、排序和分页(startAt/startAfter)。

与SQL数据库中的外键不同,引用对于在单个查询中执行连接没有用处。您可以使用它们进行依赖查找(看起来像是连接),但要小心,因为每次跳转都会导致到服务器的另一次往返。

更新12/18/22 -我把它放在一个包里。

原创博客文章

What this package does is use RXJS to loop through each field in a document. If that document type is a Reference type, then it grabs that foreign document type. The collection version grabs the foreign key value for each reference field in all documents in your collection. You can also input the fields manually that you wish to parse to speed up the searching (see my post). This is definitely not as efficient as doing manual aggregations with Firebase Functions, as you will get charged for lots of reads for each document you read, but it could come in handy for people that want a quick way to join data on the frontend.

如果您缓存数据,并且实际上只需要这样做一次,这也可以派上用场。

J

安装

npm i j-firebase

进口

import { expandRef, expandRefs } from 'j-firebase';

https://github.com/jdgamble555/j-firebase


最初的发布


自动连接:

DOC

expandRef<T>(obs: Observable<T>, fields: any[] = []): Observable<T> {
  return obs.pipe(
    switchMap((doc: any) => doc ? combineLatest(
      (fields.length === 0 ? Object.keys(doc).filter(
        (k: any) => {
          const p = doc[k] instanceof DocumentReference;
          if (p) fields.push(k);
          return p;
        }
      ) : fields).map((f: any) => docData<any>(doc[f]))
    ).pipe(
      map((r: any) => fields.reduce(
        (prev: any, curr: any) =>
          ({ ...prev, [curr]: r.shift() })
        , doc)
      )
    ) : of(doc))
  );
}

集合

expandRefs<T>(
  obs: Observable<T[]>,
  fields: any[] = []
): Observable<T[]> {
  return obs.pipe(
    switchMap((col: any[]) =>
      col.length !== 0 ? combineLatest(col.map((doc: any) =>
        (fields.length === 0 ? Object.keys(doc).filter(
          (k: any) => {
            const p = doc[k] instanceof DocumentReference;
            if (p) fields.push(k);
            return p;
          }
        ) : fields).map((f: any) => docData<any>(doc[f]))
      ).reduce((acc: any, val: any) => [].concat(acc, val)))
        .pipe(
          map((h: any) =>
            col.map((doc2: any) =>
              fields.reduce(
                (prev: any, curr: any) =>
                  ({ ...prev, [curr]: h.shift() })
                , doc2
              )
            )
          )
        ) : of(col)
    )
  );
}

简单地把这个函数放在你的可观察对象周围,它会自动展开所有提供自动连接的引用数据类型。

使用

this.posts = expandRefs(
  collectionData(
    query(
      collection(this.afs, 'posts'),
      where('published', '==', true),
      orderBy(fieldSort)
    ), { idField: 'id' }
  )
);

注意:现在还可以输入想要展开的字段,作为数组中的第二个参数。

[’imageDoc’,’authorDoc’]

这将提高速度!

添加.pipe(带(1)).toPromise ();在最后为一个承诺版本!

更多信息请看这里。工作在Firebase 8或9!

简单!

J

根据#AskFirebase https://youtu.be/Elg2zDVIcLo?t=276 目前的主要用例是Firebase控制台UI中的链接