How i can use a query in a multiple time with firebase? - javascript

My console log is 2 differents id : sender.id and otherparticipants[0].id
I need to query my first document with sender.id OR otherParticipants (because it could be one or another one)
I'm trying to do that with an operator OR but firebase seems doesn't recognize my second value.
Do you know how I can have the same result in a good way?
.then(() => {
console.log('participant', otherParticipants[0].id, sender.id);
firebase
.firestore()
.collectionGroup('favoris')
.where('id', '==', sender.id || otherParticipants[0].id)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log('data2', doc.data());
firebase
.firestore()
.collectionGroup('favoris')
.where('idUser', '==', sender.id || otherParticipants[0].id)
.get()
.then((querySnapshot) => {
console.log(querySnapshot.size);
querySnapshot.forEach((doc) => {
console.log('dataFinal', doc.data());
socialFeedsRef
.doc(sender.id)
.collection('chat_feed')
.doc(channel.id)
.set(
{
favoris: true,
},
{ merge: true },
);
});
});
});
});
});

That's not how you should create an OR query in Firestore:
.where('id', '==', sender.id || otherParticipants[0].id)
In this line, the || operator doesn't help.
You should create an array containing the IDs of the users who participate in the chat, say participantIDs: ["yourSenderUID", "yourOtherUid"].
Then, instead of the above call, add the following one:
.where("participantIDs", "array-contains-any", [sender.id, otherParticipants[0].id])
When you execute such a query, you'll get a warning message that sounds like this:
FAILED_PRECONDITION: The query requires a COLLECTION_GROUP_ASC index for collection favoris and field id. You can create it here: ...
Meaning that an index is required. You can simply click on that URL, or copy and paste the URL into a web browser and your index will be created automatically for you.

Related

How to update field in firebase document?

Hello I want to update a field in a firebase document.
Right now , I am accessing the document collection like this
However I am having trouble setting teh shares field of the doc to shares+=1 ?
What am i doing wrong here in the set method?
const buyStock = async () => {
const q = await query(
collection(db, 'myStocks'),
where('ticker', '==', props.name)
);
const querySnapshot = await getDocs(q);
if (!querySnapshot.empty) {
// simply update the record
querySnapshot.forEach((doc) => {
doc.id.set({
shares: doc.id.data().shares+=1
})
// doc.data() is never undefined for query doc snapshots
console.log(doc, doc.id, ' => ', doc.data());
});
You're almost there. To update a document, you need a reference to that document. You can get this with:
querySnapshot.forEach((doc) => {
doc.ref.update({
shares: doc.data().shares+=1
})
});
You can also use the built-in atomic increment operator:
doc.ref.update({
shares: increment(1)
})
It looks like you are calling the set method on the 'id' field. Try to remove that. So just do
doc.set({
shares: doc.data().shares+=1
})
give that a shot. If that doesn't work, i'd try updating a document that is not part of a query snapshot.

How to use array-contains operator with an array of objects in Firestore?

So, i want to query some data from firestore.
this is my data structure
so, the collection is Modules, then i now have 2 documents but it will be 75 or something. Then in that document i want to get the specific document which has a specific LessonId (In this example '2')
How do i query this?
this is wat i tries but it's not working for me
async function getModuleData() {
let ModuleData = await firebase
.firestore()
.collection('Modules')
.where('Lessons', 'array-contains', {LessonId: 2})
.get()
.then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.data())
})
});
} getModuleData()
when i do this
async function getModuleData() {
let ModuleData = await firebase
.firestore()
.collection('Modules')
.where('Title', '==', 'Leven vanuit verlossing')
.get()
.then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.data())
})
});
} getModuleData()
it just works so it's something with my where statement i guess?
To use array-contains with an array of objects, you need to pass the complete object you are looking for in that array.
For example,
const lessonObj = {
Title: "Leven vanuit verlossing",
Description: "the desc",
...allTheOtherFieldsAsIs
}
firebase.firestore().collection("Modules").where("Lessons", "array-contains", lessonObj)
You should ideally use a sub-collection to store lessons in a module. Then you can easily query lessons using the following query:
const db = firebase.firestore()
const lessonsSnapshot = await db.collection("Modules")
.doc("moduleID")
.collection("Lessons")
.where("Title", "==", "Leven vanuit verlossing")
.get()
console.log(lessonsSnapshot.docs[0].data())
As Dharmaraj answered, the array-contains operator performs a complete match, so it only returns documents where the array contains the exact value you specified.
If you only want to filter on lesson IDs, I'd recommend adding an additional field to each document with just the lesson IDs. You can then filter on that field with:
firebase
.firestore()
.collection('Modules')
.where('LessonsIDs', 'array-contains', 2)

How i can update my subcollection with error : [firestore/not-found]?

I need to update on document on my subcollection but I have an error:
Error: [firestore/not-found] Some requested document was not found.
First of all selected the good document on my collection Teams:
firestore()
.collection("Teams")
.where("tokenTeam", "==", "gvb2j3pcm9")
.get()
.then(async (querySnapshot) => {
if (querySnapshot.empty) {
console.log("no documents found");
} else {
querySnapshot.forEach(async (doc) => {
let Teams = doc._data;
console.log(Teams);
// code below fits in here
})
}
})
I have no error with the above code. Then I call my subcollection with just the statut in "attente" to select the one I want to update. My console.log(members) is working well.
After that I update the document selected I want to update which gives this error:
Error: [firestore/not-found] Some requested document was not found.
// insert into above code
doc.ref
.collection("membersList")
.where("statut", "==", "en attente")
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
console.log("no documents found");
} else {
querySnapshot.forEach((doc) => {
let members = doc.id;
console.log(members);
doc.ref
.collection("membersList")
.doc(members)
.update({
statut: "Validé",
});
});
}
});
This is my data model:
Did I forget something?
The problem is in the query you are making inside the querySnapshot.forEach. The doc.ref is representing a reference to the current document you are operating in the foreach, which is already a memberList document.
So what you are doing currently in your code is looking for the same document as a separate document in a subcollection contained in your original document, which won't work, in order to work all you have to do is this:
doc.ref
.update({
statut: "Validé",
});
If I understand correctly, this is your goal: For the given team token/ID, update all members who have a "statut" value of "en attente" to "Validé".
As #RafaelLemos stated in their answer, you only need to use doc.ref instead of doc.ref.collection("membersList").doc(members). This mistake was caused by you shadowing the variable named doc and is why you should name your variables appropriately.
Similar to this answer, you can search for requests the same way. As you find each document to update, rather than update it immediately as you have in your code, you should make use of a batched write to make a single atomic database write.
firestore()
.collection("Teams")
.where("tokenTeam", "==", "gvb2j3pcm9")
.get()
.then(async (matchingTeamsQuerySnapshot) => {
if (matchingTeamsQuerySnapshot.empty) {
console.log("no teams found");
return;
}
// start a batched write
const batch = firestore().batch();
// for each team found, find members with "statut" of "en attente",
// and queue updating "statut" to "Validé"
await Promise.all(
matchingTeamsQuerySnapshot.docs
.map(async (teamDocSnapshot) => {
// const teamData = teamDocSnapshot.data();
// console.log(teamData);
const memberRequestsQuerySnapshot = await teamDocSnapshot.ref
.collection("membersList")
.where("statut", "==", "en attente")
.get();
memberRequestsQuerySnapshot.forEach(memberRequestDoc => {
batch.update(memberRequestDoc.ref, {
statut: "Validé"
});
});
})
);
// update the database all at once
return batch.commit();
})

How do I fetch documents with specific ids (plural) from a firestore collection using the `in` clause?

I already read few post on the topic, but for some reason I can not fetch the docs which I need. I have a collection users with auto generated id and each doc contains name and email. Here is my collection:
Please note, the ids are auto generated.
Then, what I try to do in the code is the following:
firebase.firestore()
.collection("users")
.where(
"id",
"in",
ids
)
.get()
.then((querySnapshot) => {
const people = [];
querySnapshot.forEach(documentSnapshot => {
people.push({
...documentSnapshot.data(),
key: documentSnapshot.id
});
});
console.log("people: ", people);
});
My people arrays is empty. I am pretty sure that my ids array has the correct ids. I am not sure if this part is correct:
firebase.firestore()
.collection("users")
.where(
"id",
"in",
ids
)
.get()
Is "id" the correct name of the auto generated column?
To query a document by it's ID, you should make use of firebase.firestore.FieldPath.documentId() which returns a special value that can be used with the where() filter to search by a document's ID.
The following code has been tweaked from this documented gist (Typescript/JavaScript):
function chunkArr(arr, n) {
if (n <= 0) throw new Error("n must be greater than 0");
return Array
.from({length: Math.ceil(arr.length/n)})
.map((_, i) => arr.slice(n*i, n*(i+1)))
}
async function fetchDocumentsWithId(collectionQueryRef, arrayOfIds) {
// in batches of 10, fetch the documents with the given ID from the collection
const fetchDocsPromises = chunkArr(arrayOfIds, 10)
.map((idsInChunk) => (
collectionQueryRef
.where(firebase.firestore.FieldPath.documentId(), "in", idsInChunk)
.get()
))
return Promise.all(fetchDocsPromises)
.then((querySnapshotArray) => {
const allDocumentsArray = [];
for (let querySnapshot of querySnapshotArray) {
querySnapshot.forEach(doc => allDocumentSnapshotsArray.push({...doc.data(), key: doc.id}))
}
return allDocumentsArray;
});
}
const usersColRef = firebase.firestore()
.collection("users");
const ids = [ /* ... */ ];
const docDataArray = fetchDocumentsWithId(usersColRef, ids);
If you were to use the unedited version of the gist, you would instead use:
const usersColRef = firebase.firestore()
.collection("users");
const ids = [ /* ... */ ];
const docDataArray = [];
await fetchDocumentsWithId(usersColRef, ids, (doc) => docDataArray.push({ ...doc.data(), key: doc.id }))
console.log(docDataArray)
Note: I'd avoid using the term "key" for Firestore and instead use "id". If you are using "id" in your documents, you could always use "_id" instead.
In this situation I am assuming that ids is an array that you have in your client side code and are looking to query only for those ids in firestore?
Unfortunately, when using the .where() functionality in firestore, it does not query against the document ID's but rather the content of the document.
If you wanted to use the .where() indexing capability of firestore, you would need to add a uid field to the actual document data. Once you do that, you should be able to query for only the ID's you would like.
From the firestore docs

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()
...

Categories