I just want to check if i dont create an other chats on my firebase.
I query all my chat with this email and then, i check if the array contain the email i wanna tchat with but it doesn't work.
I'm using Firebase V9.
Anyone has an idea ?
function Sidebar() {
const [user] = useAuthState(auth);
const chatRef = collection(db, 'chats');
const qchatExist = query(chatRef, where('users', 'array-contains', user.email) );
const chatsSnapshot = getDocs(qchatExist);
const createChat = () => {
const input = prompt('Please enter a email adresse');
if(!input) return;
if (EmailValidator.validate(input) && !chatAlreadyExists(input) && input !== user.email ) {
console.log("valide");
addDoc(collection(db, 'chats'),
{
users: [user.email, input],
});
}
else {
console.log('invalide');
}
}
const chatAlreadyExists = (data) =>
!!chatsSnapshot?.docs.find(
chat =>
chat.data().users.find( (user) => user === data)?.length > 0
);
code
you probably wanna use Collection Group Queries.
so you can query across all the chats collection at once.
https://firebase.google.com/docs/firestore/query-data/queries#:~:text=We%20can%20use,across%20all%20cities%3A
const users = query(collectionGroup(db, 'users'), where('email', '==', 'example#hoge.com'));
and make sure you create indexes for the query.
Before using a collection group query, you must create an index that supports your collection group query. You can create an index through an error message, the console, or the Firebase CLI.
Related
I'm following this tutorial and made a few changes to typescript for learning purposes but got stuck when creating a filter function from react context script.
I have a working function called getCampaigns where it maps all the object from the blockchain like below:
const getCampaigns = useCallback(async () => {
const signer = accountProvider?.getSigner();
const contractWithSigner = contract?.connect(signer);
const campaigns = await contractWithSigner?.getCampaigns();
const parsedCampaigns = campaigns.map((campaign, i) => ({
owner: campaign.owner,
title: campaign.title,
description: campaign.description,
target: ethers.utils.formatEther(campaign.target.toString()),
deadline: campaign.deadline.toNumber(),
amountCollected: ethers.utils.formatEther(
campaign.amountCollected.toString()
),
image: campaign.image,
pId: i,
}));
return parsedCampaigns;
}, [contract, accountProvider]);
This is working as it should and manage to see the content like below:
[{…}]
0:
amountCollected:"0.0"
deadline:1673049600000
description: "I want to build a Robot"
image:"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAA
owner:"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
pId:0
target:"3.0"
title:"Build a Robot"
As my new function, I wanted to filter from the getCampaigns function only to display all of the owner's post and display it on a Profile page like below:
const getUserCampaigns = async () => {
const allCampaigns = await getCampaigns();
const filteredCampaigns = allCampaigns.filter(
campaign => campaign.owner === account
);
return filteredCampaigns;
};
So when I console.log filteredCampaigns, it doesnt show any result. Is there anything that I missed here? The typeof account is string and it is working if I put it like this
const filteredCampaigns = allCampaigns.filter(
campaign => campaign.owner === "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
);
Update:
So far I have been playing around with the syntax and console.log the following:
const filteredCampaigns = allCampaigns.filter(campaign => {
console.log(campaign.owner);
return campaign.owner === account;
});
it's managed to fetch the same data and the typeof campaign.owner is in fact a string (same as typeof account). But when I run it like this
const filteredCampaigns = allCampaigns.filter(campaign => {
console.log(campaign.owner === account.toString());
return campaign.owner === account;
});
It's still come out as false
It is working if I hard coded like this
console.log(campaign.owner === "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")
filteredCampaign is empty, because the content of account doesn't match any content of campaign.owner.
Check the content of account.
allCampaign.filter(elementOfArray => condition)
return element only if condition is true.
The logic of your getUserCampaign, looks right for what you want to do.
Not sure if this is the case, but may have sense, to have a field/global var/state where you keep all your campaigns.
In this way when you want to filter, you can do something like
const filteredCampaign = (account: string) => {
return allCampaigns.filter(campaign => campaign.owner === account);
}
filteredCampaign is not anymore async call, because doesn't have to await and receive the
account
Here I have a collection of cars and bikes and don't want to fetch everything if users select they are looking for only Cars, there are 2 types of categories Vehicles and Motorcycles and in firestore I query them like:
[{category: vehicles, modelYear: 2008 }, {category: motorcycles, modelYear: 2012}]
but is there a way to query only the one the user has selected, Like:
const [results, setResults] = useState([])
useEffect(() => {
if(vehicles === true){
db.collection("automotive")
.orderBy("category == Vehicles")
.limit(5)
.get()
.then((collections) =>{
const auto = collections.docs.map((res) => res.data())
setResult(auto)
})
}
}, [])
Firebase Firestore have provided proper method to put condition on query and limit works only when you use orderby on field :
db.collection("automotive")
.where("category == Vehicles")
.orderBy("modelYear")
.limit(5)
.get()
.then((collections) =>{
const auto = collections.docs.map((res) => res.data())
setResult(auto)
});
I am using Sonny Sangha's Whatsapp Clone video (he is using firebase v8 whereas I am using firebase v9)
The code below checks if the input you type in is already present in the Firestore Database, and if this is true, then we alert the user with a message that the user you are trying to chat with already exists. Otherwise, it will create a document in Firestore with the user email and the input you typed (the person you want to chat with).
const chatAlreadyExists = (recipientEmail) => {
// I used "!!" to convert this into boolean
!!chatsSnapshot?.docs.find(
(chat) => chat.data().users.find((user) => user ===
recipientEmail)?.length > 0
);
};
const input = prompt(
"Please enter an email address for the user you wish to chat
with"
);
if (
EmailValidator.validate(input) &&
!chatAlreadyExists(input) &&
input !== user.email
) {
const payload = {
users: [user.email, input],
};
addDoc(collectionRef, payload);
The chatsSnapshot is a real-time listener to the Firestore database
const [user] = useAuthState(auth);
const collectionRef = collection(db, "chats");
const userChatRef = query(
collectionRef,
where("users", "array-contains", user.email)
);
const [chatsSnapshot] = useCollection(userChatRef);
I am trying to use react-admin. I am not an expert on React.
I want to keep a list of items updated with the firestore (firebase) database in realtime (using the onSnapshot listener by firestore)
Up to now, I am able to use react-admin to show a list of items from firestore (firebase) database and showing them on a list, but I don't know where to put the listener and how to keep the list updated in realtime.
What I have up to now is a dataProvider for react-admin like this:
const dataProvider = {
getList: async (resourceName, params) => {
console.log(params);
if (params.pagination) {
let values = [];
//Firestore Query
let snapshots = await firebase
.firestore()
.collection("items")
.get();
for (const snapshot of snapshots.docs) {
const data = snapshot.data();
values.push(data);
}
//End Firestore query
if (params.filter) {
values = values.filter((item) => {
let meetsFilters = true;
for (const key of Object.keys(params.filter)) {
meetsFilters = item[key] === params.filter[key];
}
return meetsFilters;
});
}
if (params.sort) {
values.sort(
sortBy(
`${params.sort.order === "ASC" ? "" : "-"}${params.sort.field}`
)
);
}
const keys = values.map((i) => i.id);
const { page, perPage } = params.pagination;
const _start = (page - 1) * perPage;
const _end = page * perPage;
const data = values ? values.slice(_start, _end) : [];
const ids = keys.slice(_start, _end) || [];
const total = values ? values.length : 0;
console.log({ data, ids, total });
return { data, ids, total };
}
}
I want to insert a listener "onSnapshot" by Firebase replacing the Firestore Query in my code.
The listener onSnapshot is fired every time a new document is added in the firestore collection. It should be like this (according to https://firebase.google.com/docs/firestore/query-data/listen)
firebase.firestore().collection("items")
.onSnapshot(function(querySnapshot) {
var cities = [];
querySnapshot.forEach(function(doc) {
//Do Something
});
});
How could I insert this listener in place of the Firestore Query in my code?
The problem is that if I put it directly in place of the Firestore Query, the getList method never reaches the return statement.
how to get id of object from firebase database in reactjs
I have an array of list got from firebase database in react-redux , I want to get id of every object of array, How can I get?
Get the snapshot, and iterate through it as a Map, with Object.keys(foo).forEach for example.
Here is a dummy piece of code :
`
const rootRef = firebase.database().ref();
const fooRef = rootRef.child("foo");
fooRef.on("value", snap => {
const foo = snap.val();
if (foo !== null) {
Object.keys(foo).forEach(key => {
// The ID is the key
console.log(key);
// The Object is foo[key]
console.log(foo[key]);
});
}
});
`
Be careful with Arrays in Firebase : they are Maps translated into Arrays if the IDs are consecutive numbers started from '0'. If you remove an item in the middle of your array, it will not change the ID accordingly. Better work with Maps, it's more predictable.
You could try something like this:
export const getAllRooms = () => {
return roomCollection.get().then(function (querySnapshot) {
const rooms = [];
querySnapshot.forEach(function (doc) {
const room = doc.data();
room.id = doc.id;
rooms.push(room);
});
return rooms;
});
};
`