database 带有子集合的 Cloud Firestore 深度获取

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46611279/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 08:06:59  来源:igfitidea点击:

Cloud Firestore deep get with subcollection

databasefirebasegoogle-cloud-platformgoogle-cloud-firestoredata-modeling

提问by qeroqazo

Let's say we have a root collection named 'todos'.

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

Every document in this collection has:

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

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

Every document in the subcollection todo_itemshas

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

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

I know that querying in Cloud Firestore is shallow by default, which is great, but is there a way to query the todosand get results that include the subcollection todo_itemsautomatically?

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

In other words, how do I make the following query include the todo_itemssubcollection?

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

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

回答by Dan McGrath

This type of query isn't supported, although it is something we may consider in the future.

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

回答by Malick

If anyone is still interested in knowing how to do deep query in firestore, here's a version of cloud function getAllTodos that I've come up with, that returns all the 'todos' which has 'todo_items' subcollection.

如果有人仍然对了解如何在 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;
        })
}

回答by user2734839

I used AngularFirestore (afs) and Typescript:

我使用了 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))
      );
  }
  

回答by lustig

As pointed out in other answers, you cannot request deep queries.

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

My recommendation: Duplicate your dataas minimally as possible.

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

I'm running into this same problem with "pet ownership". In my search results, I need to display each pet a user owns, but I also need to be able to search for pets on their own. I ended up duplicated the data. I'm going to have a pets array property on each user AS WELL AS a pets subcollection. I think that's the best we can do with these kinds of scenarios.

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

回答by Ali Adil

I have faced the same issue but with IOS, any way if i get your question and if you use auto-ID for to-do collection document its will be easy if your store the document ID as afield with the title field in my case :

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

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

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

So when you retrieve lets say an array of to-do's and when click on any item you can navigate so easy by the path

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

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

I wish i could give you the exact code but i'm not familiar with Javascript

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

回答by Sajidh Zahir

you could try something like this

你可以试试这样的

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

Hope this helps !

希望这可以帮助 !