Подтвердить что ты не робот

Облако Firestore глубоко с субколлекцией

Скажем, у нас есть корневая коллекция с именем 'todos'.

В каждом документе этой коллекции есть:

  • title: Строка
  • подколлекция с именем todo_items

Каждый документ в субколлекции todo_items имеет

  • title: Строка
  • completed: Boolean

Я знаю, что запрос в Cloud Firestore по умолчанию неглубокий, что здорово, но есть ли способ запросить todos и получить результаты, которые включают подколлекцию todo_items автоматически?

Другими словами, как сделать следующий запрос, включите подколлекцию todo_items?

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

Ответ 1

Этот тип запроса не поддерживается, хотя это то, что мы можем рассмотреть в будущем.

Ответ 2

Если кому-то все еще интересно знать, как сделать глубокий запрос в firestore, вот версия облачной функции getAllTodos, которую я придумала, которая возвращает все 'todos', у которых есть подколлекция 'todo_items'.

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

Я столкнулся с той же проблемой, но с IOS, каким-либо образом, если я получу ваш вопрос, и если вы используете автообъект для документооборота, то это будет легко, если в вашем хранилище будет ID документа как поле с полем заголовка в моем случае:

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

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

Итак, когда вы извлекаете, давайте скажем массив дел и при нажатии на любой элемент, который можно легко перемещаться по пути

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

Я хочу, чтобы я мог дать вам точный код, но я не знаком с Javascript

Ответ 4

Я использовал 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))
      );
  }
  

Ответ 5

Как указано в других ответах, вы не можете запрашивать глубокие запросы.

Моя рекомендация: дублируйте свои данные как можно меньше.

Я сталкиваюсь с той же самой проблемой с "владением животным". В моих результатах поиска мне нужно отобразить каждого питомца, которым владеет пользователь, но я также должен иметь возможность самостоятельно искать питомцев. В итоге я продублировал данные. Я собираюсь иметь свойство массива питомцев для каждого пользователя, КАК ХОРОШО, как подколлекцию питомцев. Я думаю, что лучшее, что мы можем сделать с такими сценариями.

Ответ 6

вы можете попробовать что-то вроде этого

db.collection('coll').doc('doc').collection('subcoll').doc('subdoc') 

Надеюсь, это поможет!