how to query nested maps inside an array field in firebase - firebase

I have structured my data in Firebase such that I have a collection of 'users' and each user has various fields as well as a 'skillsIndustry' Array field which contain Maps items (that have fields 'experience' and 'industry').
Now I would like to query my collection of users so that I can ask for all users that have worked in 'Airlines' with experience code of >= 1
Is this possible at all? Or do I have to create sub collections and then use Collection Group Queries?
Many thanks

No, this is not possible. You can use array-contains to query for the entire object, as explained in this SO answer, but not to query with > or <.
You could create a subcollection, but you can probably find a solution based on the duplication of the data in the same document, which is a common approach in the NoSQL world.
For example, you could have some extra fields named airlinesExperience, shippingExperience, etc. Then you use the skillsIndustry Array field when you want to display all the skills and years of experience, but you use the xxxExperience fields when you want to query.
Another possibility would be to use a map of key/value pairs like
key = "Airlines" / value = 1
key = "Shipping" / value = 3
Then you can query with:
firebase
.firestore()
.collection('users')
.where('skillsIndustry.Shipping', '>', 2)

Related

How to query Firestore documents filtered by roles defined in a subcollection

In the Security Rules! video #6 the suggestion is made to create a security rule using roles defined in a private_data sub collection with a single 'private' document:
allow update: if (get(/databases/$(database)/documents/restaurants/$(restaurantID)/private_data/private).data.roles[request.auth.uid] in ['editor', 'owner'];
Using the web API, how can I query the set of documents where a user has editor or owner permissions? I don't see that a where clause can reference sub-collection documents.
Something like
const q = query(
collection(db, 'restaurants'),
where(new FieldPath('private_data', 'private', 'roles', 'user_123'), 'in', ['editor', 'owner'])
);
Firestore queries can only filter documents based on the data in each document itself. There is no way to filter based on data in another document, either from the same collection or from another (sub)collection.
This means that while it is possible to restrict write and get (single-document read) operations based on the information in the roles subcollection, it is not possible to use those same documents in a query.
If you need this use-case, the common approach is to duplicate the necessary data from the subcollection(s) into the parent document, and the filter on it there. This complicating of data write to allow or simplify a certain read is a pattern you'll see quite regularly when dealing with NoSQL databases.

Firestore: Query Single Attribute Across all Documents

I have the following structure in a Firestore collection. The "ranks" collection is updated with documents named after the timestamps. In each document, I have the same fields and values. How can I query all documents for a specific field without parsing the entire document? I.e. I want all values in all documents where field is "aave"?
I am new to Firestore and I've been trying this for several weeks now. I tried limiting with where and considered using sub collection group queries but in my case data is not stored in sub collections. Sorry, for not being able to provide more context, since I couldn't get much closer.
Queries select specific values, or ranges of values, of a known field. There is no support for dynamic field names in a query in Firestore.
But if you want to get all documents where the field aave exists/has any value, you can make use of the fact that in the sort order of values they always start with null. So to get all documents where the field aave exists/has any value, you could do:
firebase.firebase().collection("ranks").where("aave", ">=", null)

Allow users from different collection see a different stream

I have an Orders collection. It contains a field called venueId. And I'm querying against this field using isEqualTo. The venueId is the firebase user uid. I also have a venues collection. It contains this venueId and also has a list of VenueAdmins ids(These ids are also firebase user uids )The app is a point of sales app(pos). I need to query the orders collections so that valueAdmins and venueId see the correct stream. Is quite easy to query with venueId.. venueId,isEqualto, uid. I'm wondering what's the best approach to allow the venueAdmins see the stream as well.
|-Orders // collection
order. //doc
venueId:'2344567788999999'
|-Venues // collection
venue. //doc
venueAdmin: ['3333333333333','55555555555555555']
venueId:'2344567788999999'
My query builder so far: queryBuilder: (query) => query.where('venue.id', isEqualTo: uid)
Firestore does not have the capability to "join" documents from different collections in a single query. A single query can only consider documents in single collection at a time. The way you have your data structured now, it will require at least two queries. First, to find a venue, then second, to find the orders for an admin in a venue.
The only way to make this easier from the perspective of queries is to denormalize your data by duplicating venue data into the order documents. If each order also had a list of admins, then you could reduce this down to a single query.

Query based on referenced document's field

I have 3 collections
Companies: [{name:'Lamy'}]
Pens : [name:'Safari', company:ref::companies]
Writing Samples :[{title:'Post title', pen:ref::pens }]
I want to get all writing samples from from a particular pen company.
Is it possible to filter based on field values in a referenced document or do I need to restructure my firestore?
Example
const company = db.collection('companies').doc(form.penCompany);
db.collection('samples').where('pen.company', '==', company)
My guess is no and that I need to restructure my DB to include the company information nested in the sample.
You will need to restructure. A query on a collection can't reference documents from other collections - there are no SQL-like joins. Everything in the query must be in the same collection. This means you might have to duplicate data between collections. This is a common technique when working with NoSQL. It's call "denomralization".

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

Resources