1

So I am trying to figure out the best structure for my use case.

Currently it looks like this:

salesItems | userId | salesItem1 | 
                    | salesItem2 | and so on.

So the items are stored in a document named with the respective userid.

The problem with this is, that I am expecting this document to get bigger than 1MB.

So I thought maybe I need to setup collection group queries.

Therefore I set up a structure like this:

salesItems | userId | StoreA | documentId | startDate: 
                                          | endDate: 
                                          | salesItems:

                    | StoreB | documentId | startDate:

Where items get stored as chunks in a document, which get start- and enddate as fields to make it possible to query these chunks by date.

So a document would look like this:

 startDate: 01/01/2021
 endDate:   12/31/2021
 salesItems:[items]

My goal is to query all documents across all stores for a user.

So my questions are:

  1. Do you think there is a better solution?
  2. If you also think I should go with collection group queries, what would be the correct security rule?

After watching fireships tutorial on collection group queries, it seems like there are special security rules needed for collection group queries.

Currently I am writing :

match /salesItems/{userId}/{documents=**} {
  allow read, write: if true; //No restriction for testing purposes.
}

but that doesn't work.

Here is a screenshot of the current structure.

NOTE I need to store items in the 2 box. I plan to remove the 1 row, but thats not part of the question.

enter image description here

This is the subcollection structure I came up with: enter image description here

Christian
  • 834
  • 7
  • 18
  • Can you clarify the structure (exactly what is being stored in each collection) with a screenshot of sample documents? The terminology is a bit confusing like `salesItems` collection has documents with `userId` and then has salesItems again in sub-documents. – Dharmaraj Jan 09 '22 at 12:12
  • I have uploaded a screenshot. – Christian Jan 09 '22 at 12:22
  • Just to understand the data. Is it like - there are users and each of them can have multiple stores and then each store has it's own items (salesItems)? – Dharmaraj Jan 09 '22 at 12:24
  • Pretty much, yes. – Christian Jan 09 '22 at 12:27
  • I have added another screenshot with the subcolletion structure I was thinking of – Christian Jan 09 '22 at 12:31
  • I've posted an answer with an example of security rules for collection groups queries but please change them as per requirement. – Dharmaraj Jan 09 '22 at 12:37

1 Answers1

2

For a stores and items data, you can try structuring your database as shown below:

users -> {userId}
(col)     (doc)

stores -> {storeId} -> items -> {itemId}
(col)       (doc)      (col)     (doc)

You can store a field ownerId in each store document to reference the user who owns the store (or an array of UIDs if a store can have multiple owners).

This way you can query items from a specific store as well as by item ID of any property in item document using CollectionGroup queries.


I'm not sure about what permissions you required on these collections but for collection group queries you can structure them as shown below:

rules_version = '2';
service cloud.firestore {

  match /databases/{database}/documents {
    // Allow anyone to read items
    match /{path=**}/items/{itemId} {
      allow read: if request.auth != null;
    }

    // Allow users to read but owner to write store
    match /stores/{storeId} {
      allow write: if request.auth.uid == resource.data.owner;
      allow read: if request.auth != null;
    }
  }
}

Additionally, the items sub-collection can also be a root level collection. Then you would have to add a field that contains storeId in it as well but then there would be no need to use CollectionGroup queries.


Edit:

Since each can have their own data of each store, the following structure can be used:

users -> {userId} -> stores -> {storeId} -> items -> {itemId}
(col)     (doc)       (col)       (doc)      (col)     (doc)

You now have a store document for each user any information about that store can be stored in the store document. While items can be an array as mentioned in the original question, it might be easier to to query those if stored in a sub-collection since there isn't any unwind like functionality in Firestore.

Dharmaraj
  • 47,845
  • 8
  • 52
  • 84
  • Okay, I am starting to understand a little better. However there is one thing I failed to make clear: Each user has its own "instance" of a store. I am collecting data from a specific store, with an API for the users account. For example: I am logging in to a users Shopify account and get the data from there. So there are never 2 users that have access to the same store"instance". Do I still need to store the `ownerId` in the documents then? – Christian Jan 09 '22 at 13:00
  • @Christian if I understand correctly, so lets say there is a store StoreA and 2 users - user1 and user2. They both can have a document associated with StoreA? Like StoreAUser1 and StoreAUser2? – Dharmaraj Jan 09 '22 at 13:02
  • I am web scraping data for my users accounts at StoreA & StoreB. So user1 gives me his credentials for StoreA, I am scraping data for his account, and store it under `salesItems - userId1 - StoreA` If user2 wants me to scrape StoreA with his credentials, I would store it under `salesItems - userId2 - StoreA` But these 2 results would have nothing to do with each other. – Christian Jan 09 '22 at 13:15
  • @Christian I've updated the answer, can you check that? – Dharmaraj Jan 09 '22 at 13:19
  • That structure looks perfect. However, would I be able to query items across all stores? – Christian Jan 09 '22 at 13:32
  • @Christian you could list all stores of a user but if you want to run a collection group query on items sub-collections then you would have to store user Id in each item document so you can specify it in the query. – Dharmaraj Jan 09 '22 at 13:48
  • That sounds good, thanks for your patience! – Christian Jan 09 '22 at 13:58