How to filter on a long text just one word via Firestore on Ionic 4? - firebase

I'm trying to filter using (ionChange) on a searchbar just for a word on a long text (body of a letter) using Firestore, but the problem I don't know how to start, cannot see any option using Firestore (The filter is not about <=, ==...)
I was googleing a lot but didn't find any solution. Any idea?
Just what i want is to filter a list of ion-card (retrieved from firestore) just a word from a long text. Thank you so much

Unfortunately, Firestore does not support full-text search. So there is currently no way you can search a single word in a very long text. According to the official documentation regarding full-text search in Firestore:
To enable full text search of your Cloud Firestore data, use a third-party search service like Algolia.
If the those words that you want to search can be considered "tags", then store those tags in an array and use array-contains option.

Here is your answer find data from Firesote.
searcData( event ) {
const value = event.target.value;
this.loader.presentLoading();
const fireStoreData = this.afStore
.collection('CollectionName', ref => ref
.orderBy('fieldName')
.startAt(value.toLowerCase())
.endAt(value.toLowerCase() + '\uf8ff')
.limit(10)).valueChanges();
fireStoreData.subscribe(data => {
this.data = data;
this.loader.hideLoading();
// console.log(data);
}, err =>{
this.loader.hideLoading();
console.log(err);
});
}

Related

Google Translate API: Enable word conversion

I'm translating a list of words using google translate API, however I noticed that for words that it cannot translate, it returns the same word in the source language.
For example, let's observe the following request of word array conversion from English to Hebrew:
const response = await axios.post<TranslateResponse>(`https://translation.googleapis.com/language/translate/v2?key=xxxxxxx`,
{
"q": ["SUNFINSH", "DOG"],
"source": "en",
"target": "he",
"format": "text"
});
The returned object is
{"data":{"translations":[{"translatedText":"SUNFINSH"},{"translatedText":"כֶּלֶב"}]}}
in the above example, you can see it translated "DOG", but could not translate "SUNFISH".
However, if I go to translate.google.com, and type in "SUNFISH", even though it does not translate it on the right panel UI, it does offer kind of a "literal" translation, as if it can simply convert the word to how it sounds in Hebrew.
The question is, how can I get the same result using the Google Translate API?
You may try and change "SUNFISH" into "sunfish" and it will return the expected output same as the screenshot you provided using the Google Translate UI.
As seen in the screenshot provided using the Google Translate UI, Google converted "SUNFISH" into "sunfish" first and then from there, it translated it to Hebrew.
Please see the screenshot of my testing.
I also tested using "Sunfish" and still got the expected result in hebrew.
In addition, as mentioned in this official google support forum,
Google Translate must be case sensitive as no two languages follow the same Capitalization rule.
Below is my sample code used in testing for your reference.
// Imports the Google Cloud client library
const {Translate} = require('#google-cloud/translate').v2;
// Creates a client
const translate = new Translate();
const text = ['sunfish', 'DOG'];
const target = 'he';
async function translateText() {
// Translates the text into the target language. "text" can be a string for
// translating a single piece of text, or an array of strings for translating
// multiple texts.
let [translations] = await translate.translate(text, target);
translations = Array.isArray(translations) ? translations : [translations];
console.log('Translations:');
translations.forEach((translation, i) => {
console.log(`${text[i]} => (${target}) ${translation}`);
});
}
translateText();

How do I know if there are more documents left to get from a firestore collection?

I'm using flutter and firebase. I use pagination, max 5 documents per page. How do I know if there are more documents left to get from a firestore collection. I want to use this information to enable/disable a next page button presented to the user.
limit: 5 (5 documents each time)
orderBy: "date" (newest first)
startAfterDocument: latestDocument (just a variable that holds the latest document)
This is how I fetch the documents.
collection.limit(5).orderBy("date", descending: true).startAfterDocument(latestDocument).get()
I thought about checking if the number of docs received from firestore is equal to 5, then assume there are more docs to get. But this will not work if I there are a total of n * 5 docs in the collection.
I thought about getting the last document in the collection and store this and compare this to every doc in the batches I get, if there is a match then I know I've reach the end, but this means one excess read.
Or maybe I could keep on getting docs until I get an empty list and assume I've reached the end of the collection.
I still feel there are a much better solution to this.
Let me know if you need more info, this is my first question on this account.
There is no flag in the response to indicate there are more documents. The common solution is to request one more document than you need/display, and then use the presence of that last document as an indicator that there are more documents.
This is also what the database would have to do to include such a flag in its response, which is probably why this isn't an explicit option in the SDK.
You might also want to check the documentation on keeping a distributed count of the number of documents in a collection as that's another way to determine whether you need to enable the UI to load a next page.
here's a way to get a large data from firebase collection
let latestDoc = null; // this is to store the last doc from a query
//result
const dataArr = []; // this is to store the data getting from firestore
let loadMore = true; // this is to check if there's more data or no
const initialQuery = async () => {
const first = db
.collection("recipes-test")
.orderBy("title")
.startAfter(latestDoc || 0)
.limit(10);
const data = await first.get();
data.docs.forEach((doc) => {
// console.log("doc.data", doc.data());
dataArr.push(doc.data()); // pushing the data into the array
});
//! update latest doc
latestDoc = data.docs[data.docs.length - 1];
//! unattach event listeners if no more docs
if (data.empty) {
loadMore = false;
}
};
// running this through this function so we can actual await for the
//docs to get from firebase
const run = async () => {
// looping until we get all the docs
while (loadMore) {
console.log({ loadMore });
await initialQuery();
}
};

Trying to filter down chat messages using Flutter and Firestore

I'm trying to create a Blocked Users list in my chat app using the latest versions of Flutter Beta channel (1.23.0-18.1.pre) and cloud_firestore 0.14.3.
Here's my data structure:
At first, I tried something like this (Hardcoded just to test), by filtering the messages I'm querying from Firestore. Firebase doesn't like this.
query: firestore.collection('messages')
.where('userId', whereNotIn: ['123456789', '987654321'] )
.where('hashtag', isEqualTo: hashTag)
.orderBy('submittedAt', descending: true),
reverse: true,
I get this error:
E/FLTFirestoreMsgCodec(24331): java.lang.IllegalArgumentException: Invalid query. You have an inequality where filter (whereLessThan(), whereGreaterThan(), etc.) on field 'userId' and so you must also have 'userId' as your first orderBy() field, but your first orderBy() is currently on field 'submittedAt' instead.
After doing some more reading, filtering on the client-side by just hiding the messages actually better suits my needs.
Unfortunately, I'm running in circles. I'm currently thinking I would map a stream to a list, and then do something like this:
if (message.userId is in the list) {
isBlocked = true;
} else {
isBlocked = false;
}
And then filtering out the messages if isBlocked is true. I tried hardcoding the values for that and it worked. BTW, Sorry for the pseudocode, but I deviated so many times that now I'm simply lost.
I was wondering if this was the correct approach? Any suggestions would be rad. I also tried using a future list from a stream but I couldn't get that to work either.
Future<Stream<List<BlockedUser>>> getBlockedIds() async {
Stream<List<BlockedUser>> list;
Stream<QuerySnapshot> snapshot = FirebaseFirestore.instance.collection('user').doc('id').collection('blocked').snapshots();
list = snapshot.map((query) => query.docs.map(
(doc) => BlockedUser(
id: doc.data()['id'])
).toList());
return list;
}
I can't get that to work since I don't know what to do with that list.
Thanks, everyone!

Exclude document from query

I've been struggling with this problem for a while now, can't really find any direct answers anywhere to get around it. I really appreciate any help and more practical code to understand this.
I'm querying documents from a collection in Firestore. Then I'm putting them inside a custom List:
QuerySnapshot snapshot = await cardRef.limit(10).getDocuments();
List<CustomCard> cards =
snapshot.documents.map((doc) => CustomCard.fromDocument(doc)).toList();
Then I display the list like so:
//if cards != null
return Stack(children: cards);
However, I need to block documents from being added to 'cards' IF they contain a key inside a map of 'keys'.
I've tried to do something like this unsuccessfully:
if(snapshot.documents.contains('keys.$currentUserid'))
//dont add to list
But someone said on my previous post here, that I should hide the card on the client side. Is that the best approach since that card would still be added to the list? How would I do that?
in sum: 1) get all documents from a collection, 2) check each for specific key, 3) if they don't have key, add to list.
You're using snapshot.documents, which is a List<DocumentSnapshot> object. So what you're looking for is a way to derive another list from snapshot.documents with some of the documents removed.
My initial search for that flutter filter list, which shows that List.where is what you should be using for that. A simple example on this site: Flutter: Filter list as per some condition
So that'd lead to something like:
QuerySnapshot snapshot = await cardRef.limit(10).getDocuments();
List<DocumentSnapshot> filtered = snapshot.documents.where((doc) => ... /* your filter goes here */ )
List<CustomCard> cards = filtered.map((doc) => CustomCard.fromDocument(doc)).toList();

Querying Firestore documents by Array or Map fields values in Firebase console

Here, I want to query by the value "ministoreid1" in Firebase console. But I am not able to figure out. Here, I am trying to do the query in console not using codes.
I have filed the feature request at Alex' suggestion. And the reply I received from Firebase Support:
Currently, there is no query similar to array-contains available in the Firestore Console. I can file a feature request ticket on your behalf. However, I can't guarantee anything at the moment, so please watch out for any updates on our blog or release notes for now. For the map field, you can try to filter on the console using the format: 'mapFieldName.keyName' in the field text box
So we can query for map values by 'mapFieldName.keyName'. I didn't know this before.
Here, I am trying to do the query in console not using codes.
Unfortunately, there is currently no way you can filter your documents in the Firebase console according to a value that exist in an array. As you can see, there are only the following operators:
== is equal to
> is after
>= is after and includes
< is before
<= is before and includes
But an whereArrayContains option it is not present yet. I recommend you file a feature request for that. It might be also useful for other developers.
The query that you perform in the console does't return any results because you are checking if the mini_stores_assigned is equal to ministoreid1, which obviously is not since the mini_stores_assigned property is an array and not a String so you can compare them.
For future use, Firebase has added the feature request by Ssuburat. You can now can filter your documents in the Firebase console according to a value that exist in an array.
###FILTER BLOGS BY USER.
for example if you have two collections (one to many)
/users
/blogs
blog and user has these schemes:
blog: { name,date,user:{myusername:true}}
//notice that user is a map or object and document blog has id itself wich you can use in user document and viceversa.
user:{name,lastname,blogs:{idblog1:true,idblog2:true}} //blogs is a map or object
if you want to filter by map object you can do this:
import firebase from "firebase/compat/app";
import { getFirestore } from "firebase/firestore";
const appFirebase = firebase.initializeApp(firebaseConfig);
export const dbFirebase = getFirestore(appFirebase);
const myuser= "myusername"
const q = query(collection(dbFirebase, "blogs"), where(`user.${myuser}`, "==", true));
const blogsSnapshot = await getDocs(q);
blogsSnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
console.log({blogsSnapshot});

Resources