Firestore - query where filter of object in array field - firebase

I have question about query in firecloud.
For example, see my document:
i need filter all documents where the account_id is "value" and "approve" is true. How i do it?
I tried: where("members.account_id", "==, "qgZ564nfEaNP3Nt4cW1K3jCeVlY2") and not work:
See, this is a question that not for specific language, just about firestore query, after undestand, i go apply it in my code.
I'm programing in flutter.

If you query like this:
where("members.account_id", "==", "qgZ564nfEaNP3Nt4cW1K3jCeVlY2")
Firebase checks if there's a nested field /members/account_id with the given value. And such a field doesn't exist, because the value is actually at /members/0/account_id.
Since you don't know the position in the array the the ID exists, you instead want to use an array-contains condition. With array-contains Firestore checks if the array you contains the exact member that you specify.
With your current structure you can check if the member exists with:
.where("members", "array-contains", { accountId: "qgZ564nfEaNP3Nt4cW1K3jCeVlY2", approved: true })
So you must know the entire data of the array element in order to use array-contains.
If you only know a single member, while you're storing multiple members, you can't use array-contains. In that case, I recommend adding an additional member_accountIds field to each document, where you store just their account IDs:
member_accountIds: ["qgZ564nfEaNP3Nt4cW1K3jCeVlY2", ... ]
With that in place, you can query like this:
.where("members_accountIds", "array-contains", "qgZ564nfEaNP3Nt4cW1K3jCeVlY2")

Related

firebase query - find doc where map value is in an array

I'm trying to find the id of a doc where a map value in an array of maps equals "x".
in the following case, I'm trying to find which rep owns the cause with code "hog"
I'll likely be going down the denormalizing route, but is this possible?
Firestore has an array-contains operator that you can use to query whether a certain item exists in an array field, but that operator only works if you specify the exact, complete value of the field. It can't test for a partial match.
The common approach to your use-case is to add an additional array field with just the values you want to query on, i.e.
cause-codes: ["hog"]
Once you modified your documents with this additional field, you can then use a query like:
repsRef.where('cause-codes:', 'array-contains', 'hof')

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.

Firestore: How to query data from a map of an array

Here is the schema for test db:
I want to write a query that can get all the documents where contacts have id=1 in any of the array index.
I have checked array_contains operator for firestore but the thing is my array have map which then have field id.
Thanks
You currently can't build a query that looks for an object field within an array. The only things you can find in an array are the entire contents of an array element, not a part of an element.
With NoSQL type databases, the usual practice is to structure you data in a way that suits your queries. So, in your case, you're going to have to structure your data to let you find documents where an array item contains a certain string. So, you could create another array that contains just the strings you want to query for. You will have make sure to keep these arrays up to date.
You could also reconsider the use of an array here. Arrays are good for positional data, but unless these contacts need to be stored in a certain order, you might want to instead store an object whose keys are the id, and whose field data also contains the id and name.
As Doug said, you can't query it,
but, if you could structure your data to something that looks like this
Store your data as a map
Use id as key and name as value
Now you can write a query that can get all the documents where contacts have id=1
db.collection("test").where("contacts.1", ">=", "").get()
If you have an array of maps or objects and want to get the docoments that contains this specific map/object like this ?
array_of_maps.png
you can use
queryForCategory(categName: string, categAlias: string): Observable[] {
firestore.collection('<Collection name>', ref =>
ref.where('categories',
"array-contains", {
"alias": categAlias,
"title": categName
}
One soulions is as #Doug said, to add array with the data you need to query, and keep it uptodate.
Another solution is to make contacts as sub collection of the document, an then you could make queries of the contacts and get its parrent.
final Query contacts = db.collectionGroup("contacts").whereEqualTo("id", 1);
for (DocumentSnapshot document : querySnapshot.get().getDocuments()) {
System.out.println(document.getId());
System.out.println(document.getString("parent_id"));
}
If you don't want to add parent as another field, you can get it from parent reference, check this answer https://stackoverflow.com/a/56223319/1278463
snapshot.getRef().getParent().getParent().collection("people")
https://firebase.google.com/docs/firestore/query-data/queries#collection-group-query

How to get range of documents

Let's say I've got 100 documents in my collection. My goal is to get the documents between 5 and 33.
I tried startAt and endAt but it didn't work:
const db = firebase.firestore();
await db
.collection("pictures")
.startAt(start)
.endAt(end)
.get()
What you're trying to do isn't really possible. Documents don't have a natural index or position within a collection. To get ordering within a collection, you need to use at least one field on which you want to sort the documents. Only then do they have an order, and only then can you page through them.
The startAt and endAt methods on the query require that you define some order. You can see that in the example code provided in the API docs I linked to. Note the following statement in the docs for startAt:
Creates and returns a new Query that starts at the provided set of
field values relative to the order of the query. The order of the
provided values must match the order of the order by clauses of the
query.

Resources