还原查询子集合

我想我读到过你可以使用新的 FirebaseFirestore 来查询子集合,但是我没有看到任何例子。例如,我以下面的方式设置了我的火灾恢复:

  • 舞蹈〔收藏〕
    • DanceName
    • 歌曲[收藏]
      • 歌名

我如何能够查询“ Find all dance where song Name = = ‘ X’”

108296 次浏览

更新2019-05-07

今天我们发布了 集合组查询,它允许您跨子集进行查询。

因此,例如在 web SDK 中:

db.collectionGroup('Songs')
.where('songName', '==', 'X')
.get()

这将匹配任何集合中的文档,其中集合路径的最后一部分是“ Songs”。

您最初的问题是关于寻找 跳舞,其中 SongName = = ‘ X’,但是,对于每个匹配的 Song,仍然不可能直接加载它的父节点。

原始答案

这是一个尚不存在的特性。它被称为“集合组查询”,允许您查询所有歌曲,而不管其中包含哪个舞蹈。这是我们打算支持的事情,但是没有具体的时间表。

此时的替代结构是使歌曲成为顶级收藏,并使哪个舞蹈歌曲成为歌曲属性的一部分。

更新 现在火恢复支持数组包含

有这些文件

    {danceName: 'Danca name 1', songName: ['Title1','Title2']}
{danceName: 'Danca name 2', songName: ['Title3']}

这样做

collection("Dances")
.where("songName", "array-contains", "Title1")
.get()...

@ Nelson. b.austin 由于还没有这个,我建议你使用扁平结构,意思是:

Dances = {
danceName: 'Dance name 1',
songName_Title1: true,
songName_Title2: true,
songName_Title3: false
}

以这种方式,你可以做到这一点:

var songTitle = 'Title1';
var dances = db.collection("Dances");
var query = dances.where("songName_"+songTitle, "==", true);

希望这个能帮上忙。

如果将歌曲存储为对象而不是集合,该怎么办?每个舞蹈为,以歌曲为字段: 键入 Object (而不是集合)

{
danceName: "My Dance",
songs: {
"aNameOfASong": true,
"aNameOfAnotherSong": true,
}
}

然后你就可以用 NameOfASong 查询所有的舞蹈:

db.collection('Dances')
.where('songs.aNameOfASong', '==', true)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id, " => ", doc.data());
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});

使用平面数据结构可能更好。
文档指定了不同数据结构 在这一页的优缺点。

特别是关于具有子集合的结构的局限性:

不能轻松删除子集合,也不能跨子集合执行复合查询。

与所谓的扁平数据结构的优势形成对比:

根级集合提供了最大的灵活性和可伸缩性,同时在每个集合中提供了强大的查询。

你可以这样搜索:-

    this.key$ = new BehaviorSubject(null);


return this.key$.switchMap(key =>
this.angFirestore
.collection("dances").doc("danceName").collections("songs", ref =>
ref
.where("songName", "==", X)
)
.snapshotChanges()
.map(actions => {
if (actions.toString()) {
return actions.map(a => {
const data = a.payload.doc.data() as Dance;
const id = a.payload.doc.id;
return { id, ...data };
});
} else {
return false;
}
})
);

2019年最新消息

火还原已经发布了集合组查询。请参阅上面 Gil 的答案或官方 集合组查询文档


上一页答案

正如吉尔吉尔伯特所说,似乎 集合组查询目前正在进行中。同时,最好使用根级别集合,并使用文档 UID 在这些集合之间进行链接。

对于那些谁不知道,杰夫德莱尼有一些令人难以置信的指南和资源,任何人与 Firebase (和角度)在 AngularFirebase工作。

FirestorNoSQL 关系数据建模 -这里他分解了 NoSQL 和 FirestorDB 结构的基础知识

通过示例 进行高级数据建模——这些都是更高级的技术,你可以把它们放在脑后。一个伟大的阅读为那些想要采取他们的火焰恢复技能到下一个水平

var songs = []
db.collection('Dances')
.where('songs.aNameOfASong', '==', true)
.get()
.then(function(querySnapshot) {
var songLength = querySnapshot.size
var i=0;
querySnapshot.forEach(function(doc) {
songs.push(doc.data())
i ++;
if(songLength===i){
console.log(songs
}
console.log(doc.id, " => ", doc.data());
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});

查询限制

云火恢复不支持以下类型的查询:

  1. 在不同字段上使用范围过滤器的查询。

  2. 跨多个集合或子集合的单个查询。每个查询针对单个文档集合运行 有关数据结构如何影响查询的信息,请参见 选择一个数据结构

  3. 逻辑或查询。在这种情况下,应该为每个 OR 条件创建一个单独的查询,并将查询结果合并到应用程序中。

  4. 查询!= 条款。在这种情况下,应该将查询分为大于查询和小于查询。举个例子,虽然 在不支持(“ age”,“ ! =”,“30”)的查询子句中,您可以 通过组合两个查询获得相同的结果集,其中一个查询带有子句 其中(“ age”,“ <”,“30”)和一个带有(“ age”,“ >”,30)的从句。

最新更新2019年7月8日:

db.collectionGroup('Songs')
.where('songName', isEqualTo:'X')
.get()

我找到了解决办法。 请看看这个。

var museums = Firestore.instance.collectionGroup('Songs').where('songName', isEqualTo: "X");
museums.getDocuments().then((querySnapshot) {
setState(() {
songCounts= querySnapshot.documents.length.toString();
});
});

然后你可以看到数据,规则,索引,用法标签在你的云火灾恢复 console.firebase.google.com。 最后,应该在 tab.< img src = “ https://i.stack.imgur.com/crV85.png”alt = “ enter image description here”> < img src = “ https://i.stack.imgur.com/crV85.png”alt = “ enter image description here”>

索引中设置索引

在这里填写集合 ID 和一些字段值。 然后选择集合组选项。 好好享受,谢谢

我正在这里与观察和 AngularFire包装工作,但这里是我如何设法做到这一点。

这有点疯狂,我还在学习观察,我可能做过头了,但这是一个很好的练习。

一些解释(不是 RxJS 专家) :

  • SongId $是一个可观察的,将发出 id
  • Dance $是一个可观察值,它读取 id,然后只获取第一个值。
  • 然后它查询所有歌曲的 CollectionGroup 以找到它的所有实例。
  • 基于实例,它遍历到父 Dances 并获取它们的 id。
  • 现在我们有了所有 Dance id,我们需要查询它们来获取数据。但是我希望它能够很好地执行,所以我不是一个接一个地查询,而是将它们批处理为10个桶(in查询需要的最大角度)。
  • 我们最终得到 N 个桶,并且需要对 firestore 执行 N 个查询来获取它们的值。
  • 一旦我们执行了对 firestore 的查询,我们仍然需要从中解析数据。
  • 最后,我们可以合并所有的查询结果得到一个单一的数组,其中所有的舞蹈。
type Song = {id: string, name: string};
type Dance = {id: string, name: string, songs: Song[]};


const songId$: Observable<Song> = new Observable();
const dance$ = songId$.pipe(
take(1), // Only take 1 song name
switchMap( v =>
// Query across collectionGroup to get all instances.
this.db.collectionGroup('songs', ref =>
ref.where('id', '==', v.id)).get()
),
switchMap( v => {
// map the Song to the parent Dance, return the Dance ids
const obs: string[] = [];
v.docs.forEach(docRef => {
// We invoke parent twice to go from doc->collection->doc
obs.push(docRef.ref.parent.parent.id);
});
// Because we return an array here this one emit becomes N
return obs;
}),
// Firebase IN support up to 10 values so we partition the data to query the Dances
bufferCount(10),
mergeMap( v => { // query every partition in parallel
return this.db.collection('dances', ref => {
return ref.where( firebase.firestore.FieldPath.documentId(), 'in', v);
}).get();
}),
switchMap( v => {
// Almost there now just need to extract the data from the QuerySnapshots
const obs: Dance[] = [];
v.docs.forEach(docRef => {
obs.push({
...docRef.data(),
id: docRef.id
} as Dance);
});
return of(obs);
}),
// And finally we reduce the docs fetched into a single array.
reduce((acc, value) => acc.concat(value), []),
);
const parentDances = await dance$.toPromise();


我复制粘贴了我的代码,并将变量名更改为您的,不确定是否有任何错误,但它对我来说工作得很好。如果您发现任何错误,或者能够提供更好的方法来测试它,请告诉我,也许可以使用一些模拟火灾恢复。