Firebase Collection Group Query on Id / Key [duplicate] - firebase

This question already has an answer here:
How to perform collection group query using document ID in Cloud Firestore
(1 answer)
Closed 2 years ago.
I have been following along the following document:
https://firebase.google.com/docs/firestore/query-data/queries#collection-group-query
My data structure roughly looks like this:
/teams/{teamid}
{
displayName: "Company X Team",
owner: "userid",
}
/teams/{teamid}/invites/{emailAddressAsKey}
{
someProp: "my data"
}
In my web app I want to search through all the different teams records to find an invite who's id/key is equal to the email address that I pass in. After reading through the documentation, I think a Collection Group Query is what I'm looking for. However, my situation doesn't exactly match the example. I want to match on the key, not a prop within the document. I suppose I could add the email address again as a prop, but that doesn't feel right.

You have to put the document ID as a key in the document itself. There is currently no other solution.
It's tempting to use FieldPath.documentId() in a where clause (eg following Alex Mamo's answer https://stackoverflow.com/a/56967352/2518722), but that doesn't work in the general case. The reason is that FieldPath.documentId() actually refers to the full, unique ID of the document including its path.
If you do try this you'll get the following error:
Error: When querying a collection group and ordering by
FieldPath.documentId(), the corresponding value must result in a valid
document path, but '<your doc id>' is not because it contains an odd
number of segments.
Basically the where clause only works with searches on keys/values not document IDs.

You can solve this with the help of FieldPath.documentId() like in the following line of code:
db.collectionGroup('teams').where(firebase.firestore.FieldPath.documentId(), '==', 'teams/teamId').get()
This query will return all documents with a specific team id.

Related

Firestore: Wherein custom object array?

im trying to make a sort of chat app with the following architecture:
Its currently working as follows: in a root doc, there is an array of chat objects. Each chat object spawns a message doc, which contains an array of message objects. Same logic for comments.
Im thinking about a function to update all posts relative to the associated user, IE if a user changes their name all associated comments will be updated. Is this possible with the WhereIn() function? Or should i edit the architecture to something more like each document being its own message/comment? Thanks!
An in clause checks if a specific field is equal to one of a set of values, which doesn't apply here.
You might be thinking of array-contains, but that wouldn't work in your current structure either. The array-contains only matches exact an item in the array if it completely/exactly matches the value in the query.
The common way to allow such a query is to add a participants array field to each document where you store the UIDs of all participants in that doc. Then you can do an array-contains query against that.

Firestore collection group query on document id [duplicate]

This question already has an answer here:
How to perform collection group query using document ID in Cloud Firestore
(1 answer)
Closed 1 year ago.
I am trying to run the following query:
this.db.firestore
.collectionGroup('members')
.orderBy('dateModified', 'desc')
.where(firebase.firestore.FieldPath.documentId(), '==', uid)
But I get the error:
Invalid query. When querying a collection group by
FieldPath.documentId(), the value provided must result in a valid
document path, but 'X6yL5Ko55jSMWhhoQUO91xVYdEH3' is not because it
has an odd number of segments (1).
Is the only way around this to add the document id to the document?
This is not ideal as I have a lot of existing data...
The document id is the uid of the firebase user.
As the error message says, for an index on a collection group the documentId() field values are actually stored as document paths to ensure unique lookups of those values in the index.
If you want to also query on document ID over a collection group, you will indeed have to store the ID as a field value in each document.
Also keep in mind that it is then possible to get multiple documents for the query, even though that is astronomically unlikely if you use the built-in add() operation.
Adding the uid to the document itself is the only possible way at the moment and then query on that field:
this.db.firestore
.collectionGroup('members')
.orderBy('dateModified', 'desc')
.where("uid", '==', uid)
There was a Github issue for the same and explains why that's not possible.
That's pretty much why I sometimes prefer to store a root level collection members. Each document in the collection will have contain the groupID (or whatever your parent collection is meant for). If you use userID as the key for documents in there then it goes easy.
this.db.firestore.collection("members").doc(uid)
So instead of having a path like: /groups/{groupID}/members/{memberID}, the structure will be like: /groups/{groupID} and all the members will be store in the root level collection 'members'. A document in that collection may look like:
// uid as doc key
{
groupId: "groupID",
...otherFields
}
The catch is if a member can join multiple groups you cannot use the userId as the key.

Firebase database check if element exists in a ListField in Flutter

I have a real-time database on firebase which consists of ListFields. Among these fields, one field, participants is a list of strings and two usernames. I want to make a query to firebase database such that it will return the documents in which a particular username is present in the participants list.
The structure of my document is as follows :
I want to make a query such that Firebase returns all the documents in which the participants list consists aniruddh. I am using Flutter with the flutterfire plugins.
Your current data structure makes it easy to find the participants for a conversation. It does however not make it easy to find the conversations for a user.
One alternative data structure that makes this easier is to store the participants in this format:
imgUrls: {},
participants: {
"aniruddh": true,
"trubluvin": true
}
Now you can technically query for the the conversations of a user with something like:
db.child("conversations").orderByChild("participants/aniruddh").equalTo(true)
But this won't scale very well, as you'll need to define an index for each user.
The proper solution is to add a second data structure, known as an inverted index, that allows the look up of conversations for a user. In your case that could look like this:
userConversations: {
"aniruddh": {
"-LxzV5LzP9TH7L6BvV7": true
},
"trubluvin": {
"-LxzV5LzP9TH7L6BvV7": true
}
}
Now you can look up the conversations that a user is part of with a simple read operation. You could expand this data structure to contain more information on each conversation, such as the information you want to display in your list view.
Also see my answer heres:
Firebase query if child of child contains a value (for more explanation on why the queries won't work in your current structure, and why they won't scale in the first structure in my answer).
Best way to manage Chat channels in Firebase (for an alternative way of naming the chat rooms).

Is it possible to query collectionGroup on a specific collection? [duplicate]

This question already has answers here:
collectionGroup within a certain path
(2 answers)
Closed 3 years ago.
I have a user collection, and within that collection there's a collection name groups, which then has groupItems. Is it possible to run a query for all groupItems for a specific user?
I could run a global version like:
db.collectionGroup('groupItems')
but that is overkill for me, I'm looking for something like:
db.collection('users').doc(uid).collection('groups').collectionGroup('groupIems').where('categoryOnly', '==', true)
Is this possible?
The architecture of the collections looks like this:
Users
---> User
------> Collections
---------> GroupA
------------> GroupAItems
---------------> GroupAItem1
---------------> GroupAItem2
---------> GroupB
------------> GroupBItems
---------------> GroupBItem1
---------------> GroupBItem2
Ideally I could call for all Group Items instead of first calling for groups and getting [GroupA, GroupB...], and then calling for GroupA's items, then GroupB's, etc.
Update: it turns out that querying a specific path may be possible after all, thanks to how FieldPath.documentId() is indexed for collection group indexes. Check #samthecodingman's answer here: https://stackoverflow.com/a/68049847
Happy answer above 👆
Old answer below 👇
There is currently no way to limit a collection group to just collections under a specific path. All collection group queries get documents from all collections with the specified name.
So the only way to currently query a subset of your groups is to use a naming scheme that allows you to uniquely address them.
Also see:
Does collection group queries get data from all collections with the same name?
collectionGroup within a certain path

firestore: representing a relationship

In firestore i have a collection called things.
Each thing is owned by a user.
Each thing can be shared by the owner with other specified users.
the structure of thing looks something like
{
id: "thing01",
sharedWith: {
"user1": true,
"user2": true,
},
dtCreated: 3458973948
}
When I want to retrieve all thing objects that are shared with user1, ordered by dtCreated desc,
i can't do this without having to create an index on things.thing.user1
i.e. for every unique userid i have to create an index on the things collection.
Obviously this is not practical. The docs talk about using full text search for this, but this doesn't seem like a problem we would want to use full text search for.
Is there a different way i should be structuring the data to achieve what i want?
Is firestore just the wrong technology choice for this?
It's working very well for storing the thing objects themselves.
---- update ----
this question is not a real duplicate of Firestore: Working with nested single queries because the answer provided there is very specific to the OP's context.

Resources