Firebase get data compare two fields - firebase

I'm trying to get all the documents that have my phone number as the fromNumber or the toNumber. My call right now is:
database.collection('documents').where('fromNumber','==',myPhoneNumber).get().then();
Instead of making 2 calls, one to check the fromNumber and the second one to check the toNumber, how can I check both at the same time and in the same .get()?
Btw: tested this code:
database.collection('documents')
.where('fromNumber','==',myPhoneNumber)
.where('toNumber','==',myPhoneNumber).get()
.then();
But it checks if both are true, it's an AND instead of the OR I'm looking for.

According to the official documentation, there a are some query limitations, when it comes to Firestore:
Cloud Firestore does not support the following types of queries:
Logical OR queries. In this case, you should create a separate query for each OR condition and merge the query results in your app.
As suggested in the documentation, you should create two separate queries and merge the result cliend side.

Related

Is there a possibility to perform non-case sensitive "where" request to Firestore

I have a request to Firestore to check if the collection of tickets contains some duplicated IDs:
firestore.collection("tickets").where("extId", "==", "Test 2").get();
The problem is - where method looks up only for case-sensitive IDs.
Is there a chance I can return a document with test 2 or tesT 2 extId?
Unfortunately Firestore queries are case sensitive and there is no way to avoid this. Here are some approaches you could take to solve this problem depending on your use case:
1. Store several versions of your data (eg store both an upper and lower case version of your data)
2. Don't allow users to type in their query, and instead provide them with predefined filter items (for example chips, or a dropdown menu)
3. Do some client side processing before executing the query (eg. convert query strings into upper or lowercase to ensure it matches the format in the document)
4. Use a search engine platform on top of Firestore such as Algolia, Typesense, Meilisearch, among others as they contain typo-tolerance and other additional features
As also #Hydra mentioned in her answer, the queries in Firestore are case-sensitive, meaning that will always return documents with the exact match. If you want to get documents with test 2 OR tesT 2, then you should consider using in operator:
Use the in operator to combine up to 10 equality (==) clauses on the same field with a logical OR. An in query returns documents where the given field matches any of the comparison values.
In your particular case, the following query will do the trick:
firestore.collection("tickets").where("extId", "in", ["test 2", "tesT 2"]).get();

How can I limit and sort on document ID in firestore?

I have a collection where the documents are uniquely identified by a date, and I want to get the n most recent documents. My first thought was to use the date as a document ID, and then my query would sort by ID in descending order. Something like .orderBy(FieldPath.documentId, descending: true).limit(n). This does not work, because it requires an index, which can't be created because __name__ only indexes are not supported.
My next attempt was to use .limitToLast(n) with the default sort, which is documented here.
By default, Cloud Firestore retrieves all documents that satisfy the query in ascending order by document ID
According to that snippet from the docs, .limitToLast(n) should work. However, because I didn't specify a sort, it says I can't limit the results. To fix this, I tried .orderBy(FieldPath.documentId).limitToLast(n), which should be equivalent. This, for some reason, gives me an error saying I need an index. I can't create it for the same reason I couldn't create the previous one, but I don't think I should need to because they must already have an index like that in order to implement the default ordering.
Should I just give up and copy the document ID into the document as a field, so I can sort that way? I know it should be easy from an algorithms perspective to do what I'm trying to do, but I haven't been able to figure out how to do it using the API. Am I missing something?
Edit: I didn't realize this was important, but I'm using the flutterfire firestore library.
A few points. It is ALWAYS a good practice to use random, well distributed documentId's in firestore for scale and efficiency. Related to that, there is effectively NO WAY to query by documentId - and in the few circumstances you can use it (especially for a range, which is possible but VERY tricky, as it requires inequalities, and you can only do inequalities on one field). IF there's a reason to search on an ID, yes it is PERFECTLY appropriate to store in the document as well - in fact, my wrapper library always does this.
the correct notation, btw, would be FieldPath.documentId() (method, not constant) - alternatively, __name__ - but I believe this only works in Queries. The reason it requested a new index is without the () it assumed you had a field named FieldPath with a subfield named documentid.
Further: FieldPath.documentId() does NOT generate the documentId at the server - it generates the FULL PATH to the document - see Firestore collection group query on documentId for a more complete explanation.
So net:
=> documentId's should be as random as possible within a collection; it's generally best to let Firestore generate them for you.
=> a valid exception is when you have ONE AND ONLY ONE sub-document under another - for example, every "user" document might have one and only one "forms of Id" document as a subcollection. It is valid to use the SAME ID as the parent document in this exceptional case.
=> anything you want to query should be a FIELD in a document,and generally simple fields.
=> WORD TO THE WISE: Firestore "arrays" are ABSOLUTELY NOT ARRAYS. They are ORDERED LISTS, generally in the order they were added to the array. The SDK presents them to the CLIENT as arrays, but Firestore it self does not STORE them as ACTUAL ARRAYS - THE NUMBER YOU SEE IN THE CONSOLE is the order, not an index. matching elements in an array (arrayContains, e.g.) requires matching the WHOLE element - if you store an ordered list of objects, you CANNOT query the "array" on sub-elements.
From what I've found:
FieldPath.documentId does not match on the documentId, but on the refPath (which it gets automatically if passed a document reference).
As such, since the documents are to be sorted by timestamp, it would be more ideal to create a timestamp fieldvalue for createdAt rather than a human-readable string which is prone to string length sorting over the value of the string.
From there, you can simply sort by date and limit to last. You can keep the document ID's as you intend.

Firestore collections intersection?

I am implementing the typical followers/following/friends + feed system. For each user in my database, I have 3 subcollections: "followers", "following" and "friends". Currently, I am trying to implement a feed following these three business rules:
Feeds are order by date.
User A can be in the friends list of User B while user B is not in User A friends list.
You can see the posts of those users you follow who also follow you or/and have you scheduled on their friends list.
In my case, what I have thought to do is to perform multiple reads in a Cloud Function, because it seems not really easy to achieve the third rule... but now I wonder if it would be possible to make a query of this style (similar):
currentUserFollowingRef = db.collection(...).doc(userId).collection("following")
otherUserFollowingRef = db.collection(...).doc(otherUserId).collection("following")
otherUserFriendsRef = db.collection(...).doc(otherUserId).collection("friends")
// Some kind of intersection using queries (Pseudo)
U1 = currentUserFollowingRef.where(firebase.firestore.FieldPath.documentId(), "in", otherUserFollowingRef)
.limit(10).get();
// Other intersection
U2 = currentUserFollowingRef.where(firebase.firestore.FieldPath.documentId(), "in", otherUserFriendsRef)
.limit(10).get();
// Union of two sets using pure js
UFinal = U1 union U2 (using js)
/* Last step is to retrieve the last post of each user ordered by date using collection group queries */
Someone knows how to achieve this doing something similar (retrieving docs which
also are in other collection)?
Any consideration that should be taken into account?
Thank you.
What you're trying to do isn't supported by Firestore. A query can only consider documents in a single collection at a time. It's not possible to "join" with documents in other collections. You will have to do exactly what you said in the question - "perform multiple reads in a Cloud Function" and merge the results of those queries in your code.
Either that, or duplicate data into a new collection that effectively "pre-joins" the data from other collections for a single query. But that might be a lot of work for this case.

Firebase firestore collection count with angularFire 2

I want to get the total number of the documents that exist in firestore.
I don't want to get the data only the total number of inside Products collection I have 200.000 items is that possible with Angular 4-5, not angular.js
Can someone expert tell me how I can achieve that ??
My code so far and is not work
get_total_messages() {
this.messages_collection = this.afs.collection<MessageEntity>('messages');
return this.messages_collection.snapshotChanges();
}
End this is how I try to get the data but is not what I want;
this.firebase_Service.get_total_messages().subscribe( data => {
console.log(data);
});
There is no API to get the count of the number of documents in a Firestore collection. This means that the only ways to get the count are:
Get all documents and count them client-side.
Store the count as a separate property and update that as you add/remove documents.
Both approaches are quite common in NoSQL databases, with the second of course being a lot more efficient as the number of documents grows.
Firebase provides a sample of using Cloud Functions to keep a counter. While this sample is written for the Firebase Realtime Database, it can easily be modified to work on Cloud Firestore too.
Firestore also provides documentation on running aggregation queries and running distributed counters. Both seem slightly more involved than the first sample I linked though.
this.firebase_Service.get_total_messages().subscribe( data=>this.totalnumber=data.length);
//now, you can get total number of messages
luckily , i've solved somehow using the code,
try this, and it works well .
this.db.collection('User').valueChanges()
.subscribe( result => {
console.log(result.length);
})

Firebase - Structuring Data For Efficient Indexing

I've read almost everywhere about structuring one's Firebase Database for efficient querying, but I am still a little confused between two alternatives that I have.
For example, let's say I want to get all of a user's "maxBenchPressSessions" from the past 7 days or so.
I'm stuck between picking between these two structures:
In the first array, I use the user's id as an attribute to index on whether true or false. In the second, I use userId as the attribute NAME whose value would be the user's id.
Is one faster than the other, or would they be indexed a relatively same manner? I kind of new to database design, so I want to make sure that I'm following correct practices.
PROGRESS
I have come up with a solution that will both flatten my database AND allow me to add a ListenerForSingleValueEvent using orderBy ONLY once, but only when I want to check if a user has a session saved for a specific day.
I can have each maxBenchPressSession object have a key in the format of userId_dateString. However, if I want to get all the user's sessions from the last 7 days, I don't know how to do it in one query.
Any ideas?
I recommend to watch the video. It is told about the structuring of the data very well.
References to the playlist on the firebase 3
Firebase 3.0: Data Modelling
Firebase 3.0: Node Client
As I understand the principle firebase to use it effectively. Should be as small as possible to query the data and it does not matter how many requests.
But you will approach such a request. We'll have to add another field to the database "negativeDate".
This field allows you to get the last seven entries. Here's a video -
https://www.youtube.com/watch?v=nMR_JPfL4qg&feature=youtu.be&t=4m36s
.limitToLast(7) - 7 entries
.orderByChild('negativeDate') - sort by date
Example of a request:
const ref = firebase.database().ref('maxBenchPressSession');
ref.orderByChild('negativeDate').limitToLast(7).on('value', function(snap){ })
Then add the user, and it puts all of its sessions.
const ref = firebase.database().ref('maxBenchPressSession/' + userId);
ref.orderByChild('negativeDate').limitToLast(7).on('value', function(snap){ })

Resources