web-dev-qa-db-ja.com

Cloud Firestoreはサブコレクションでディープゲット

「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) => {
    // ...
  });
});
53
qeroqazo

このタイプのクエリはサポートされていませんが、今後検討される可能性があります。

37
Dan McGrath

誰かがまだ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;
        })
}
3
Malick

他の回答で指摘されているように、詳細なクエリを要求することはできません。

私の推奨事項:データを複製するできるだけ最小限にします。

「ペットの所有権」についても同じ問題に直面しています。私の検索結果では、ユーザーが所有する各ペットを表示する必要がありますが、ペットを自分で検索できる必要もあります。最終的にデータを複製しました。ペットのサブコレクションとして、各ユーザーにペット配列プロパティを設定します。これらのシナリオでできることは最高だと思います。

0
lustig

私は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))
      );
  }
  
0
user2734839

私は同じ問題に直面しましたが、IOSで質問があり、to-doコレクション文書に自動IDを使用する場合は、私の場合はタイトルフィールドを持つ文書IDをフィールドとして保存すると簡単です:

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

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

そのため、取得するときにTo Doの配列を言うことができ、アイテムをクリックすると、パスで簡単にナビゲートできます

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

私はあなたに正確なコードを提供したいのですが、私はJavascriptに精通していません

0
Ali Adil