how to get users from firestore database with Like query - javascript

this function work fine with equal string but i need to search a substring: if i write "h" and the string is "hello" i need to return that
async getUsers(searchUser) {
return firestore().collection('Users').where(searchUser).where('firstName', '==', searchUser)
.limit(20).get().then(snapshot => {
snapshot.docs.forEach(doc => {
const usersData = { ...doc.data(), id: doc.id };
return usersData
});
})
}

I can give you answer!
In that case, you must use a dedicated third-party search service. These services provide advanced indexing and search capabilities far beyond what any simple database query can offer.
Please use "Algolia" and at that time your code according to your expectations must be like this.
const client = algoliasearch('YourApplicationID', 'YourSearchOnlyAPIKey');
const index = client.initIndex('firstName');
index.search(searchUser, {
attributesToRetrieve: ['firstname', 'lastname'/*, .. etc the fields you need*/],
hitsPerPage: 20 /* the page Size */,
}).then(({ hits }) => {
console.log(hits); // the results you want
});
Just try it.
Helpful for you? If it's successful, I would be happy.
If you have a question please contact "Nykolai.B0411#outlook.com". I will help you.
Thanks.

When you register a new user to your app you can store their username/firstname in firestore as an array that includes the possible ways you would search for a user (look at the attached image). You can do that by splitting the name string.
then you can query the users collection by searching in that array using arrayContains like this:
await usersCollection
.where('searchOptions', arrayContains: searchText)
.get()
.then((value) =>
value.docs.map((doc) => User.fromSnapShot(doc)).toList());
If you need more capabilities than that you might need to use a 3rd party service. but this solution should be sufficient for your case.

Related

How to update all documents inside Firestore collection if you don't know the id for the document [duplicate]

I have a firestore collections named users, each users have a generated id with a field score :
users
0e8X3VFL56rHBxxgkYOW
score : 4
3SeDjrgAWMmh3ranh2u
score : 5
I use redux-firestore and i want to reset all my users score at 0, something like
firestore.update({ collection: 'users' }, { score : 0 }
I can't achieve this because update method need a document id
Do you know how to do this ?
You can get all the documents in the collection, get their id's and perform updates using those id's:
db.collection("cities").get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
doc.ref.update({
capital: true
});
});
});
For some strange reason the accepted answer ( thehamzarocks ) wasn't working for me, none of the documents were updated. Maybe there's a bug in AngularFire2. Anyway, I decided to loop over the docs array of the QuerySnapshot instead of using its forEach method, and add each update to a batch queue. Batching bulk operations is also more efficient than sending a new update request for each update operation.
resetScore(): Promise<void> {
return this.usersCollectionRef.ref.get().then(resp => {
console.log(resp.docs)
let batch = this.afs.firestore.batch();
resp.docs.forEach(userDocRef => {
batch.update(userDocRef.ref, {'score': 0, 'leadsWithSalesWin': 0, 'leadsReported': 0});
})
batch.commit().catch(err => console.error(err));
}).catch(error => console.error(error))
}
Batch updates are nice but bare in mind that they are limited to 500 document updates per transaction.
If this reset isn't done often maybe simplest approach is:
async function resetScores() {
const collection = await db
.collection("users")
.get()
collection.forEach(doc=> {
doc.ref
.update({
score: 0
})
})
}
I came across this post while searching for similar solutions. Firestore now has batched writes, which will update all documents in one go. This could be an ideal solution for fewer documents.
Updating #thehamzarocks's answer:
const batch = db.batch()
db.collection('cities').get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
const docRef = db.collection('cities').doc(doc.id)
batch.update(docRef, { capital: true })
});
batch.commit();
});
Firestore doesn't have the ability to bulk update documents without knowing their IDs. You will have to somehow know the document ID of each document to update (perform a query, or do batches of queries), and update each one individually.
Sorry if the question is old but I thought providing a new answer to this question might be useful to someone else too. I managed to bulk update the entries of a list using the following command:
this.db
.list<User[]>('users')
.set('/', users);
Edit: I'm using AngularFireDatabase.

Bulk Update using Batched Write of Firebase with conditions (using WHERE function)

The main goal of my system is to update the name of the user who posted on my forum if the authenticated user change or rename his or her account name.
The whole process is error-free but unfortunately, the other user who posted in the forum also updated their name.
So this is the output:
I try the following:
I use the WHERE function in Firebase to filter the post made by the user (log in user itself). I dont know why the whole process is failed.
This is the snippet code.
async updateAll(username) {
const batch = this.afs.firestore.batch();
// cUser is the USER ID
const userRef = this.afs
.collection('post', (ref) => ref.where('postedById', '==', this.cUser))
.ref.get();
(await userRef).forEach((element) => {
batch.update(element.ref, {
postedBy: username,
});
});
return batch.commit();
}
You end your query with .ref.get(). The .ref in there, actually returns the collection on which you run the query, so you end up loading the entire post collection.
You'll want to subscribe to snapshotChanges instead, or just use the regular JavaScript SDK to accomplish this (as you're not accessing the UI directly, I typically find that easier):
const userRef = firebase.firestore()
.collection('post').where('postedById', '==', this.cUser).get();
(await userRef).forEach((element) => {
batch.update(element.ref, {
postedBy: username,
});
});

How to get subcollections of a filtered collection item in firestore?

I have a collection which also has subcollections within individual items. I filter the collection then trying to access the subcollection of the filtered first item. I tried to do that with a foreach loop. But isn't there an easier direct way, such as giving direct path? How can I do that?
Sample data path is through: /users/O2Am1XSXBOOWOQj2pzyu/appointments
Here is my code:
useEffect(()=>{
var currentUser = auth().currentUser;
if (currentUser) {
setFoundUser(currentUser);
firestore().collection('users').where('phone','==',currentUser.phoneNumber).get()
.then(function (querySnapshot) {
if(!querySnapshot.empty){
setFoundUser(querySnapshot.docs[0])
firestore().collection('users/'+querySnapshot.docs[0].id+'/appointments').get()
.then(function (appointmentsSnapshot) {
var appointmentsArray=[]
if(appointmentsSnapshot!=undefined && !appointmentsSnapshot.empty){
console.log('say: '+appointmentsSnapshot.docs.length)
appointmentsSnapshot.forEach(function(s){
firestore().doc(s.data().aref).get()
.then(function (appiSnapshot) {
if(appiSnapshot!=undefined&&!appiSnapshot.empty){
console.log('appi: '+appiSnapshot.docs.length)
appointmentsArray.push({id:appiSnapshot.id, data:appiSnapshot.data()})
}
});
setAppointments(appointmentsArray)
});
}
});
}
});
}
},[])
You will need to perform a loop to get the subcollection data from your collection and the best way is indeed a forEach loop. As indicated in the official documentation here, the way you are doing it's pretty similar to yours. An example of code on how to do that, in case you know the document you want to get the subcollection is the following.
var query = db.collection("users").where("field", "==", "O2Am1XSXBOOWOQj2pzyu");
query.get().then((querySnapshot) => {
querySnapshot.forEach((document) => {
document.ref.collection("appointments").get().then((querySnapshot) => {
...
});
});
});
The query is pretty similar to yours, only reduced a couple of lines that you wouldn't need. This code was based in the answer provided by a Firebase Engineer from Google, that you can check here.
To summarize, you are doing what it's right and recommended for subcollections, as they are not so simple to work with adn you need to follow these specific requirenments to get the information you need. You can also read more details about subcollections and getting their information on this nice article here.

How to (using React JS web) and Firestore, can you find out when a chatRoom (on the Firestore Database) receives new messages?

I am trying to build an app using FireStore and React JS (Web)
My Firestore database basically has:
A collection of ChatRooms ChatRooms
Every chat-room has many messages which is a subcollection, for example:
this.db.collection("ChatRooms").doc(phone-number-here).collection("messages")
Also, every chat-room has some client info like first-name, last-name etc, and one that's very important:
lastVisited which is a timestamp (or firestamp whatever)
I figured I would put a React Hook that updates every second the lastVisited field, which means to try to record as accurately as possible on Firestore the last time I left a chat-room.
Based on that, I want to retrieve all the messages for every customer (chat-room) that came in after the last visit,
=> lastVisited field. :)
And show a notification.
I have tried from .onSnapshot listener on the messages subcollection, and a combination of Firestore Transactions but I haven't been lucky. My app is buggy and it keeps showing two, then one, then nothing, back to two, etc, and I am suffering much.
Here's my code!
Please I appreciate ANY help!!!
unread_messages = currentUser => {
const chatRoomsQuery = this.db.collection("ChatRooms");
// const messagesQuery = this.db.collection("ChatRooms");
return chatRoomsQuery.get().then(snapshot => {
return snapshot.forEach(chatRoom => {
const mess = chatRoomsQuery
.doc(chatRoom.id)
.collection("messages")
.where("from", "==", chatRoom.id)
.orderBy("firestamp", "desc")
.limit(5);
// the limit of the messages could change to 10 on production
return mess.onSnapshot(snapshot => {
console.log("snapshot SIZE: ", snapshot.size);
return snapshot.forEach(message => {
// console.log(message.data());
const chatRef = this.db
.collection("ChatRooms")
.doc(message.data().from);
// run transaction
return this.db
.runTransaction(transaction => {
return transaction.get(chatRef).then(doc => {
// console.log("currentUser: ", currentUser);
// console.log("doc: ", doc.data());
if (!doc.exists) return;
if (
currentUser !== null &&
message.data().from === currentUser.phone
) {
// the update it
transaction.update(chatRef, {
unread_messages: []
});
}
// else
else if (
new Date(message.data().timestamp).getTime() >
new Date(doc.data().lastVisited).getTime()
) {
console.log("THIS IS/ARE THE ONES:", message.data());
// newMessages.push(message.data().customer_response);
// the update it
transaction.update(chatRef, {
unread_messages: Array.from(
new Set([
...doc.data().unread_messages,
message.data().customer_response
])
)
});
}
});
})
.then(function() {
console.log("Transaction successfully committed!");
})
.catch(function(error) {
console.log("Transaction failed: ", error);
});
});
});
});
});
};
Searching about it, it seems that the best option for you to achieve that comparison, would be to convert your timestamps in milliseconds, using the method toMillis(). This way, you should be able to compare the results better and easier - more information on the method can be found in the official documentation here - of the timestamps of last message and last access.
I believe this would be your best option as it's mentioned in this Community post here, that this would be the only solution for comparing timestamps on Firestore - there is a method called isEqual(), but it doesn't make sense for your use case.
I would recommend you to give it a try using this to compare the timestamps for your application. Besides that, there is another question from the Community - accessible here: How to compare firebase timestamps? - where the user has a similar use cases and purpose as yours, that I believe might help you with some ideas and thoughts as well.
Let me know if the information helped you!

Saving a field from firestore that is an array

I am currently working on a mobile app on React and I am having trouble understanding how to save a field from fire store that is an array.
Since I can't post images my database structure is all strings such as username, first name, etc but I have a field called follow list that is an array.
What I want to do is save the usernames from the following list into an array to later search fire store for the username's in the array, this is basically what I want to do so I can render my app's social Feed. I do know that I can probably create another subcollection and write something familiar to what I did to search for users but that was a QuerySnapShot which was overall documents not a specific one and I also know firebase creates an ID for arrays and it increases as the array gets bigger.
I do not want to end up making two more subcollections one for followers and following which I think not ideal right? My current approach is this
export const fetchUserFollowing = async (username) => {
const ref = firebase.firestore().collection('users').doc(username)
let results = []
ref
.get()
.then( doc => {
let data = doc.data()
results = data
})
.catch((err) => {
return 'an error has occurred ', err
})
}
From what I understand is that a DocumentSnapShot .get() function returns an object but what I want is to store follow list into results and then return that but I am not sure how to manipulate the object return to just give me follow List which is an array
https://rnfirebase.io/docs/v5.x.x/firestore/reference/DocumentSnapshot
link to docs

Categories

Resources