Answers:
更新2019-05-07
今天,我们发布了集合组查询,这些查询使您可以跨子集合进行查询。
因此,例如在Web SDK中:
db.collectionGroup('Songs')
.where('songName', '==', 'X')
.get()
这将匹配集合路径的最后部分为“歌曲”的任何集合中的文档。
您最初的问题是关于在songName =='X'处查找舞蹈,但是仍然不可能直接实现,但是,对于匹配的每首歌曲,您都可以加载其父项。
原始答案
此功能尚不存在。这称为“收藏组查询”,无论您跳舞的是哪种歌曲,都可以查询所有歌曲。这是我们打算支持的事情,但没有具体的时间表。
此时的另一种结构是使歌曲成为顶级收藏,并使歌曲以哪种舞蹈成为歌曲属性的一部分。
立即更新 Firestore支持数组包含
拥有这些文件
{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);
我希望这有帮助。
songName_Title3: false
用?如果我没记错的话,它只能用于搜索没有特定歌曲名称的舞蹈,前提是我们需要a songName_Title3: false
来dances.where("songName_"+songTitle, "==", false);
返回这样的结果,这样就不会让每个舞蹈都为每个可能的歌曲都带有布尔标志名称...
如果您将歌曲存储为对象而不是收藏,该怎么办?每个舞蹈都以歌曲为字段:键入Object(不是集合)
{
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);
});
更新2019
Firestore已发布集合组查询。请参阅上述Gil的答案或官方的“ 收藏组查询”文档
上一个答案
正如吉尔·吉尔伯特(Gil Gilbert)所说,似乎 正在进行集合组查询。同时,最好使用根级别集合,并仅使用文档UID在这些集合之间进行链接。
对于那些尚不了解的人,Jeff Delaney为在AngularFirebase上使用Firebase(和Angular)的任何人提供了一些不可思议的指南和资源。
Firestore NoSQL关系数据建模 -在这里他分解了NoSQL和Firestore DB结构化的基础知识
通过示例使用Firestore进行高级数据建模 -这些是更先进的技术,可让您牢记在心。对于那些希望将其Firestore技能提高到一个新水平的人来说是一本好书
您总是可以这样搜索:
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;
}
})
);
查询限制
Cloud Firestore不支持以下类型的查询:
在不同字段上具有范围过滤器的查询。
跨多个集合或子集合的单个查询。每个查询针对单个文档集合运行。有关数据结构如何影响查询的更多信息,请参见 选择数据结构。
逻辑或查询。在这种情况下,您应该为每个OR条件创建一个单独的查询,并将查询结果合并到您的应用中。
带!=子句的查询。在这种情况下,您应该将查询分为大于查询和小于查询。例如,尽管不支持查询子句where(“ age”,“!=”,“ 30”),但您可以通过组合两个查询获得相同的结果集,其中一个查询与子句where(“ age”,“ < “,” 30“)和带有子句where(” age“,”>“,30)的子句。
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);
});
我找到了解决方案。请检查一下。
var museums = Firestore.instance.collectionGroup('Songs').where('songName', isEqualTo: "X");
museums.getDocuments().then((querySnapshot) {
setState(() {
songCounts= querySnapshot.documents.length.toString();
});
});
然后,您可以从console.firebase.google.com在Cloud Firestore中查看“数据”,“规则”,“索引”,“使用情况”选项卡。最后,您应该在“索引”选项卡中设置索引。
在此处填写集合ID和一些字段值。然后选择收集组选项。好好享受。谢谢
我在这里使用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测试。