我以为我读过您可以使用新的Firebase Firestore查询子集合,但我没有看到任何示例。例如,我通过以下方式设置了Firestore:
我怎样才能查询“查找songName =='X'的所有舞蹈”
答案 0 :(得分:96)
更新2019-05-07
今天我们发布了collection group queries,这些允许您查询子集合。
因此,例如在Web SDK中:
db.collectionGroup('Songs')
.where('songName', '==', 'X')
.get()
这将匹配任何集合中的文档,其中集合路径的最后部分是'歌曲'。
你原来的问题是关于找到舞蹈,其中songName ==' X',但这仍然不可能直接,但是,对于每个匹配你的歌曲都可以加载其父级。
原始回答
这是一项尚不存在的功能。它被称为"收集组查询"并允许您查询所有歌曲,无论哪个舞蹈包含它们。这是我们打算支持的,但没有具体的时间表来确定它何时会到来。
此时的替代结构是将歌曲设为顶级收藏,并使该歌曲成为歌曲属性的一部分。
答案 1 :(得分:18)
<强>更新强> 现在Firestore支持array-contains
拥有这些文件
{danceName: 'Danca name 1', songName: ['Title1','Title2']}
{danceName: 'Danca name 2', songName: ['Title3']}
这样做
collection("Dances")
.where("songName", "array-contains", "Title1")
.get()...
@ Nelson.b.austin因为firestore还没有,所以我建议你有一个扁平的结构,意思是:
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);
我希望这会有所帮助。
答案 2 :(得分:13)
如果您将歌曲存储为对象而不是收藏,该怎么办?每个舞蹈都是,歌曲作为一个字段:类型对象(不是集合)
{
danceName: "My Dance",
songs: {
"aNameOfASong": true,
"aNameOfAnotherSong": true,
}
}
然后你可以用aNameOfASong查询所有的舞蹈:
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);
});
答案 3 :(得分:7)
UPDATE 2019
Firestore已发布集合组查询。请参阅上述Gil的答案或官方的Collection Group Query Documentation
上一个答案
正如吉尔·吉尔伯特(Gil Gilbert)所说,似乎集合组查询目前正在开发中。同时,最好使用根级别集合,并使用文档UID在这些集合之间建立链接。
对于那些尚不了解的人,Jeff Delaney为AngularFirebase上使用Firebase(和Angular)的任何人提供了一些不可思议的指南和资源。
Firestore NoSQL Relational Data Modeling-在这里,他介绍了NoSQL和Firestore DB结构的基础知识
Advanced Data Modeling With Firestore by Example-这些是更先进的技术,可让您随时记住。对于那些希望将其Firestore技能提高到一个新水平的人来说是一本不错的书
答案 4 :(得分:4)
2019年7月8日新更新:
db.collectionGroup('Songs')
.where('songName', isEqualTo:'X')
.get()
答案 5 :(得分:1)
使用平面数据结构可能更好 文档指定了不同数据结构的优缺点here is an example。
特别是关于具有子集合的结构的局限性:
您无法轻松删除子集,也无法跨子集执行复合查询。
与平面数据结构的所谓优势相比:
根级别集合提供最大的灵活性和可伸缩性,以及每个集合中的强大查询。
答案 6 :(得分:1)
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);
});
答案 7 :(得分:1)
查询限制
Cloud Firestore不支持以下类型的查询:
在不同字段上具有范围过滤器的查询。
跨多个集合或子集合的单个查询。每个查询针对单个文档集合运行。欲了解更多 有关数据结构如何影响查询的信息,请参见 Choose a Data Structure。
- 逻辑或查询。在这种情况下,您应该为每个OR条件创建一个单独的查询,然后将查询结果合并到您的应用中。
- 带有!=子句的查询。在这种情况下,您应该将查询分为大于查询和小于查询。例如,尽管 查询子句where(“ age”,“!=”,“ 30”)不支持,您可以 通过组合两个查询获得相同的结果集,其中一个与子句 where(“ age”,“ <”,“ 30”)和带有子句where(“ age”,“>”,30)的子句。
答案 8 :(得分:1)
我在这里使用Observables和AngularFire包装器,但这是我设法做到的方式。
这有点疯狂,我仍在学习有关可观察物的信息,但我可能过时了。但这是一个很好的练习。
一些解释(不是RxJS专家):
in
查询的最大角度。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();
我复制粘贴了代码,然后将变量名更改为您的变量名,不确定是否有任何错误,但是对我来说很好。让我知道您是否发现任何错误,或者可以建议一个更好的方法来进行模拟Firestore进行测试。
答案 9 :(得分:0)
您可以像这样搜索: -
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;
}
})
);
答案 10 :(得分:0)
我找到了解决方案。 请检查一下。
var museums = Firestore.instance.collectionGroup('Songs').where('songName', isEqualTo: "X");
museums.getDocuments().then((querySnapshot) {
setState(() {
songCounts= querySnapshot.documents.length.toString();
});
});
然后,您可以从console.firebase.google.com在您的云Firestore中查看“数据”,“规则”,“索引”,“使用情况”标签。 最后,您应该在“索引”标签中设置索引。
在此处填写集合ID和一些字段值。 然后选择收集组选项。 好好享受。谢谢