在Firestore中,如果用户有他们可以访问的单独文档列表,我该如何查询这些文档 [英] In firestore, if a user has a separate list of documents they can access, how can I query for those documents

查看:41
本文介绍了在Firestore中,如果用户有他们可以访问的单独文档列表,我该如何查询这些文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的数据库结构:

I have a database structure like this:

companies (collection)
  userMessages (collection)
    message1 (document)
      messageId: message1 (field)
      title: ...
    ...

users (collection)
  companyMessages (collection)
    message1 (document)
      createdAt: ... (field)

我有如下安全规则:

match /users/{userId}/companyMessages/{messageId} {
  allow read: if request.auth.uid == userId
}
match /{path=**}/userMessages/{messageId} {
 allow read: if 
   exists(/databases/$(database)/documents/users/$(request.auth.uid)/companyMessages/$(messageId))
}

现在,用户可以通过这样做来查询最近的10条帖子

Now the user can query for their 10 most recent posts by doing

firestore.collection("users").doc(userId).collection("companyMessages").orderBy("createdAt").limit(10)

然后,我想使用该查询的结果来实际获取消息,因此我想执行一个集合组查询:

Then I want to use the result of that query to actually get the messages, so I want to do a collection group query:

firestore.collectionGroup("userMessages").where("messageId", "in", idsFromPreviousQuery)

但是,这将导致"FirebaseError:缺少权限或权限不足".错误.我检查了我的安全规则,因为我可以执行以下查询:

However this will cause a "FirebaseError: Missing or insufficient permissions." error. I have checked that my security rules works because I can do a query like this:

firestore.collection("companies").doc(companyId).collection("userMessages").doc(messageIdThatIsInUserCollection)

但是用 where()进行查询不起作用.

However doing a query with where() does not work.

firestore.collection("companies").doc(companyId).collection("userMessages").where("messageId", "==", messageIdThatIsInUserCollection)

我做错什么了吗?或者这种结构不可能吗?我该如何构建数据结构以允许查询用户应该能够获取最近的n条消息,但他们仍然只能访问其集合中列出的消息?

Am I doing something wrong or is this kind of structure not possible? How can i structure my data to allow queries where users should be able to get their last n messages, but they still should only have access to the messages that is listed in their collection?

推荐答案

按文档ID查询

要按文档ID查询,请使用 firebase.firestore.FieldPath.documentId() .这将返回一个特殊的对象,Firestore将其理解为使用文档的ID作为搜索的属性".重要的是,当没有找到特定的ID时,结果中会简单地省略它们-不会引发任何错误.

Query by Document ID

To query by a document ID, you use firebase.firestore.FieldPath.documentId(). This returns a special object that Firestore understands as "use the document's ID as the property to search on". Importantly, when a particular ID is not found, they are simply omitted from the results - no error is thrown.

对于基本的 CollectionReference ,您可以使用:

For a basic CollectionReference, you can use:

const idsFromPreviousQuery = await firestore
  .collection("users").doc(userId)
  .collection("companyMessages")
  .orderBy("createdAt")
  .limit(10)
  .then(querySnapshot => querySnapshot.map(doc => doc.id)); // return array of document IDs

const messageDocs = firestore
  .collection("companies")
  .doc(companyId)
  .collection("userMessages")
  .where(firebase.firestore.FieldPath.documentId(), "in", idsFromPreviousQuery)
  .get()
  .then(querySnapshot => querySnapshot.docs) // return only the documents array

但是,对于收集组查询,当以这种方式使用 documentId()时,必须指定完整路径.为此,您需要在邮件列表中存储邮件的路径和/或相关的公司:

However, for a collection group query, you must specify the full path instead when using documentId() this way. For this, you will need to store the message's path and/or the relevant company in your list of messages:

"users/someUserId/companyMessages/someMessageId": {
  createdAt: /* ... */,
  company: "companyA"
}

"users/someUserId/companyMessages/someMessageId": {
  createdAt: /* ... */,
  path: "companies/companyA/userMessages/someMessageId"
}

const myMessagePaths = await firestore
  .collection("users").doc(userId)
  .collection("companyMessages")
  .orderBy("createdAt")
  .limit(10)
  .then(querySnapshot => querySnapshot.map(doc => doc.get("path"))); // return array of document paths

const messageDocs = firestore.collectionGroup("userMessages")
  .where(firebase.firestore.FieldPath.documentId(), "in", myMessagePaths)
  .get()
  .then(querySnapshot => querySnapshot.docs) // return only the documents array

另一种选择是将消息的ID存储在消息文档中,以便可以使用收集组查询来查询它.

Another option is to store the message's ID inside the message document so that it can be queried against using a collection group query.

"companies/someCompanyId/userMessages/someMessageId": {
  "_id": "someMessageId",
  /* ... other data ... */
}

const idsFromPreviousQuery = await firestore
  .collection("users").doc(userId)
  .collection("companyMessages")
  .orderBy("createdAt")
  .limit(10)
  .then(querySnapshot => querySnapshot.map(doc => doc.id)); // return array of document IDs

firestore
  .collection("companies")
  .doc(companyId)
  .collection("userMessages")
  .where("_id", "in", idsFromPreviousQuery)
  .get()
  .then(querySnapshot => querySnapshot.docs) // return only the documents array

where("field","in",someArray)

的过滤器限制

一个 where()过滤器的 in 运算符一次被限制为10个值.搜索超过10个ID时,应将ID数组分成10个项目的块.

Filter limitations for where("field", "in", someArray)

A where() filter's in operator is limited to 10 values at a time. When searching more than 10 IDs, you should split the array of IDs up into blocks of 10 items.

/** splits array `arr` into chunks of max size `n` */
const chunkArr = (arr, n) => {
  if (n <= 0) throw new Error("n must be greater than 0");
  return Array
    .from({length: Math.ceil(arr.length/n)})
    .map((_, i) => arr.slice(n*i, n*(i+1)))
}

const idsFromPreviousQuery = [ /* ... */ ];
const idsInChunks = chunkArr(idsFromPreviousQuery, 10);

const getDocPromises = idsInChunks.map((idsInThisChunk) => (
  firestore.collectionGroup("userMessages")
    .where("_id", "in", idsInThisChunk)
    .get()
    .then(querySnapshot => querySnapshot.docs) // return only the documents array
));

const allFoundDocs = await Promise.all(getDocPromises)
  .then(getDocResults => (
    getDocResults.reduce((acc, arr) => acc.push(...arr), []) // flatten the documents into one array
  );

// allFoundDocs now contains an array of QueryDocumentSnapshot objects that match the given IDs

这篇关于在Firestore中,如果用户有他们可以访问的单独文档列表,我该如何查询这些文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆