68

假设我们有一个名为“todos”的根集合。

此集合中的每个文档都有:

  1. title: 细绳
  2. 子集合命名todo_items

子集合中的每个文档todo_items都有

  1. title: 细绳
  2. completed: 布尔值

我知道默认情况下 Cloud Firestore 中的查询很浅,这很好,但是有没有办法自动查询todos并获取包含子集合的结果todo_items

换句话说,如何使以下查询包含todo_items子集合?

db.collection('todos').onSnapshot((snapshot) => {
  snapshot.docChanges.forEach((change) => {
    // ...
  });
});
4

7 回答 7

49

不支持这种类型的查询,尽管我们将来可能会考虑这样做。

于 2017-10-06T22:19:03.167 回答
4

如果有人仍然有兴趣了解如何在 Firestore 中进行深度查询,这里是我提出的云函数 getAllTodos 的一个版本,它返回所有具有“todo_items”子集合的“todos”。

exports.getAllTodos = function (req, res) {
    getTodos().
        then((todos) => {
            console.log("All Todos " + todos) // All Todos with its todo_items sub collection.
            return res.json(todos);
        })
        .catch((err) => {
            console.log('Error getting documents', err);
            return res.status(500).json({ message: "Error getting the all Todos" + err });
        });
}

function getTodos(){
    var todosRef = db.collection('todos');

    return todosRef.get()
        .then((snapshot) => {
            let todos = [];
            return Promise.all(
                snapshot.docs.map(doc => {  
                        let todo = {};                
                        todo.id = doc.id;
                        todo.todo = doc.data(); // will have 'todo.title'
                        var todoItemsPromise = getTodoItemsById(todo.id);
                        return todoItemsPromise.then((todoItems) => {                    
                                todo.todo_items = todoItems;
                                todos.push(todo);         
                                return todos;                  
                            }) 
                })
            )
            .then(todos => {
                return todos.length > 0 ? todos[todos.length - 1] : [];
            })

        })
}


function getTodoItemsById(id){
    var todoItemsRef = db.collection('todos').doc(id).collection('todo_items');
    let todo_items = [];
    return todoItemsRef.get()
        .then(snapshot => {
            snapshot.forEach(item => {
                let todo_item = {};
                todo_item.id = item.id;
                todo_item.todo_item = item.data(); // will have 'todo_item.title' and 'todo_item.completed'             
                todo_items.push(todo_item);
            })
            return todo_items;
        })
}
于 2018-02-20T17:45:51.603 回答
0

我遇到了同样的问题,但是对于 IOS,无论如何,如果我收到您的问题,并且如果您将自动 ID 用于待办事项收集文档,那么如果您将文档 ID 存储为带有标题字段的字段,在我的情况下将很容易:

let ref = self.db.collection("collectionName").document()

let data  = ["docID": ref.documentID,"title" :"some title"]

因此,当您检索让我们说一系列待办事项时,当单击任何项​​目时,您可以轻松地通过路径导航

ref = db.collection("docID/\(todo_items)")

我希望我能给你确切的代码,但我不熟悉 Javascript

于 2017-11-06T18:24:58.753 回答
0

根据文档,您需要对 firestore 进行 2 次调用.. 一次调用 fetch doc,第二次调用 fetch subcollection。减少总时间的最佳方法是使用promise.Allorpromise.allSettled而不是顺序地并行进行这两个调用。

于 2021-06-29T11:52:48.703 回答
0

正如其他答案中所指出的,您不能请求深度查询。

我的建议:尽可能少地复制数据。

我在“宠物所有权”方面遇到了同样的问题。在我的搜索结果中,我需要显示用户拥有的每只宠物,但我还需要能够自行搜索宠物。我最终复制了数据。我将在每个用户以及 pets 子集合上都有一个 pets 数组属性。我认为这是我们在这种情况下能做的最好的事情。

于 2019-08-29T17:47:42.283 回答
0

你可以尝试这样的事情:

db.collection('coll').doc('doc').collection('subcoll').doc('subdoc')
于 2017-11-03T16:41:16.250 回答
0

我使用了 AngularFirestore (afs) 和 Typescript:

import { map, flatMap } from 'rxjs/operators';
import { combineLatest } from 'rxjs';

interface DocWithId {
  id: string;
}

convertSnapshots<T>(snaps) {
  return <T[]>snaps.map(snap => {
    return {
      id: snap.payload.doc.id,
      ...snap.payload.doc.data()
    };
  });
}

getDocumentsWithSubcollection<T extends DocWithId>(
    collection: string,
    subCollection: string
  ) {
    return this.afs
      .collection(collection)
      .snapshotChanges()
      .pipe(
        map(this.convertSnapshots),
        map((documents: T[]) =>
          documents.map(document => {
            return this.afs
             .collection(`${collection}/${document.id}/${subCollection}`)
              .snapshotChanges()
              .pipe(
                map(this.convertSnapshots),
                map(subdocuments =>
                  Object.assign(document, { [subCollection]: subdocuments })
                )
              );
          })
        ),
        flatMap(combined => combineLatest(combined))
      );
  }
  

于 2019-06-16T06:55:14.270 回答