orderBy and where clause not working together in firestore - javascript

I am using a where clause on my firestore query to filter based on an attribute type and then ordering them using the orderBy to order them by time.
const tradesRef = firebase
.firestore()
.collection("cex-trades")
.orderBy("time", "desc")
.limit(16);
useEffect(() => {
if (filter === "5m") {
tradesRef
.where("type", "==", "fifteenMinutes")
.get()
.then((collections) => {
const tradesData = collections.docs.map((trade) => trade.data());
const lastDoc = collections.docs[collections.docs.length - 1];
const firstDoc = collections.docs[collections.docs.length - 16];
setTrades(tradesData);
setFirstTrade(firstDoc);
setLastTrades(lastDoc);
})
.catch((error) => {
console.error(error);
});
}
}, [filter]);
When I run my code, I am getting this error:
FirebaseError: The query requires an index. You can create it here: https://console.firebase.google.com/v1/r/project/whaletracer-432e8/firestore/indexes?create_composite=ClRwcm9qZWN0cy93aGFsZXRyYWNlci00MzJlOC9kYXRhYmFzZXMvKGRlZmF1bHQpL2NvbGxlY3Rpb25Hcm91cHMvY2V4LXRyYWRlcy9pbmRleGVzL18QARoICgR0eXBlEAEaCAoEdGltZRACGgwKCF9fbmFtZV9fEAI
I followed the link and created an index as followed:
After creating the index, I am still getting the same error. Any idea how to solve the issue?

Related

array.prototype..forEach function skipped with values in variable

I have a problem, i have a Firebase Firestore Database connected to my React.JS Project, where users can enroll to courses. Now if i'm trying to load the users collection from the DB it returns 1 entry.
const fetchAthletes = async () => {
debugger
try {
const athletes: Array<any> = [];
const athleteRef = collection(db, COLLECTION_NAME_ATHLETE);
const getAthleteQuery = query(athleteRef, where('user', '==', userAuthToken.accessToken));
const querySnapshot = await getDocs(getAthleteQuery)
if (querySnapshot.docs) {
//this for each gets skipped, even when querySnapshot.doc has values in it
querySnapshot.forEach((doc) => {
athletes.push({
id: doc.id,
...doc.data()
});
setAthletes(athletes as Array<Athlete>);
})
}
} catch (error: unknown) {
enqueueSnackbar((error as string), { variant: 'error', autoHideDuration: 3000 })
}
}
But when i want to loop over it via array.prototype.map it always skips it.
I debbuged through the funtion and found out that docs from Firestore is set with values tbat i wanna recieve.
Data returned by Firestore
I have no clue why it doesn't work. Any idea or help is appreciated
Rather than attempt to individually set each doc into state, build up your array and set the entire thing into state
const querySnapshot = await getDocs(getAthleteQuery);
setAthletes(querySnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));

react-native-firebase query with 'array-contains' in useEffect keeps refreshing component

I'm just trying to make a request to fetch only the threads that contain the current user's id.
If I remove my 'where' query, I can fetch all threads.
There is my code :
useEffect(() => {
const unsubscribe = firestore()
.collection('THREADS')
// query is empty
.where('usersIds', 'array-contains', ['60ddd70c7a3a1e8e62d14dac'])
.orderBy('latestMessage.createdAt', 'desc')
.onSnapshot(querySnapshot => {
const threadsQueried = querySnapshot
? querySnapshot.docs.map(documentSnapshot => {
return {
...documentSnapshot.data(),
};
})
: null;
setThreads(threadsQueried);
if (loading) {
setLoading(false);
}
});
return () => unsubscribe();
});
I already tried without putting my id into an array, but the component keeps refreshing, like that:
.where('usersIds', 'array-contains', '60ddd70c7a3a1e8e62d14dac')
My firebase datas:
I already check here https://stackoverflow.com/a/59053018/9300663
and here https://stackoverflow.com/a/59215461/9300663
Edit: So it is working when id is without brackets ('60ddd70c7a3a1e8e62d14dac') into the query
But my component keeps refreshing.
If I add an empty array or an array with dependencies to my useEffect, the query does not works anymore.
Edit 2: Query is working but get called two times and the second time get back with 'null', which is emptying my state.
So I found the solution when I tried another way to get my firebase query by using get() instead of onSnapshot():
firestore()
.collection('THREADS')
.where('usersIds', 'array-contains', user.id)
.orderBy('latestMessage.createdAt', 'desc')
.get()
.then(querySnapshot => {
const threadsQueried = querySnapshot.docs.map(documentSnapshot => {
return {
...documentSnapshot.data(),
};
});
setThreads(threadsQueried);
The problem with 'get()' was that the query only worked once and didn't update if new threads were created.
But it allowed me to have a firebase error asking me to create the indexes: 'usersIds' and 'latestMessage.createdAt'. After creating them, I was able to reuse my old code and everything's working correctly now.
useEffect(() => {
const unsubscribe = firestore()
.collection('THREADS')
.where('usersIds', 'array-contains', user.id)
.orderBy('latestMessage.createdAt', 'desc')
.onSnapshot(querySnapshot => {
const threadsQueried = querySnapshot.docs.map(documentSnapshot => {
return {
...documentSnapshot.data(),
};
});
setThreads(threadsQueried);
});
return () => unsubscribe();
}, []);

Unable to retrieve data from Multiple collection firebase

Hope you're in good health.
I have a problem.
export function fetchListing() {
return function (dispatch) {
dispatch(fetchListingRequest());
//Getting Listing where status is in_review
firebase
.firestore()
.collection("listings")
.where("status", "==", "in_review")
.onSnapshot(
snapshot => {
const data = [];
snapshot.docs.forEach(doc => {
const temp = {};
// Getting address of business
firebase
.firestore()
.collection("users")
.doc(doc.data().business_id)
.get()
.then(users => {
temp["address"] = users.data().address;
})
.catch(error => {
dispatch(fetchListingFailed(error));
});
temp["title"] = doc.data().title;
temp["description"] = doc.data().description;
temp["listing_file"] = doc.data().listing_file;
data.push([doc.id, temp]);
});
dispatch(fetchListingSucess(data));
},
error => {
dispatch(fetchListingFailed(error));
}
);
};
}
I am Unable to get address in state but when I log it It displayed in console. I am able to access address when I am retrieving it from firebase and also in reducer I am also getting address.
reasons can be :
The hierarchy of your firestore collection
or you have to know that in js you can't affect the data to a variable that is in the main prog just when it is in a one level functions
for exemple here you can do this
locale = this ;
than you can use all the variables in two other levels

How to query firebase items with specific reference type

I have a parent collection categories and it child collection directories
Directories connected with Categories via Category property
I want to query all directories with category equal to level
this.firestore
.collection<any>('directories', ref => ref.where('categories', '==', 'levels'))
.get()
.pipe(
map(x => {
const out: [] = [];
x.forEach(y => {
out.push(y.data());
});
return out;
})
);
I am getting an empty array in return. How would you fix that?
UPDATE based on the answer provided by #renaud-tarnec:
const categoryDocRef = this.firestore.doc('categories/levels');
this.firestore
.collection<any>('directories', ref => ref.where('categories', '==', categoryDocRef))
.get()
.pipe(
map(x => {
const out: [] = [];
x.forEach(y => {
out.push(y.data());
});
return out;
})
);
Now having an error core.js:15713 ERROR Error: Function Query.where() called with invalid data. Unsupported field value: a custom AngularFirestoreDocument object
If you want to use the DocumentReference data type in a query, you have to build a DocumentReference and use it in your query, as follows (in "standard" JavaScript):
const categoryDocRef = firebase.firestore().doc('categories/levels');
firebase.firestore().collection("directories").where("parent", "==", categoryDocRef)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id, " => ", doc.data());
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
I've made the assumption that the documents containing the field parent (which , in turn, contains the DocumentReference type data) are in a collection named directories.
UPDATE: It appears that the following won't work with angularFire2, see the comments
So, if I am not mistaking, this would be done as follow in angular, based on the code of your question:
const categoryDocRef = this.firestore.doc('categories/levels');
this.firestore
.collection<any>('directories', ref => ref.where('parent', '==', categoryDocRef))
.get()
...

Add where conditions on a Firebase query dynamically [duplicate]

I have fetch some data from firestore but in my query I want to add a conditional where clause. I am using async-await for api and not sure how to add a consitional where clause.
Here is my function
export async function getMyPosts (type) {
await api
var myPosts = []
const posts = await api.firestore().collection('posts').where('status', '==', 'published')
.get()
.then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.data())
})
})
.catch(catchError)
}
In my main function I am getting a param called 'type'. Based on the value of that param I want to add another qhere clause to the above query. For example, if type = 'nocomments', then I want to add a where clause .where('commentCount', '==', 0), otherwise if type = 'nocategories', then the where clause will be querying another property like .where('tags', '==', 'none')
I am unable to understand how to add this conditional where clause.
NOTE: in firestore you add multiple conditions by just appending your where clauses like - .where("state", "==", "CA").where("population", ">", 1000000) and so on.
Add the where clause to the query only when needed:
export async function getMyPosts (type) {
await api
var myPosts = []
var query = api.firestore().collection('posts')
if (your_condition_is_true) { // you decide
query = query.where('status', '==', 'published')
}
const questions = await query.get()
.then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.data())
})
})
.catch(catchError)
}
For the frontend Web SDK:
Or you can look at this link for a different method:
Firestore conditional where clause using Modular SDK v9
let showPublishStatus: boolean = true
let conditionalConstraint: QueryConstraint = showPublishStatus
? where("status", "==", "published")
: where("status", "!=", "published")
let queryWebSDK = query(collection(db, "Collection"), conditionalConstraint)

Categories