Is there a way to paginate firebase data without a snapshot? - javascript

I have a firebase collection called activity with 4 documents inside, with timestamps of 2, 3, 4, and 5 o'clock.
When I query it like so
let postsQuery = firebase
.firestore()
.collection(`activity`)
.orderBy("timestamp", "desc")
.limit(2);
I correctly get the 5 and 4 o'clock posts.
However, when I call the function again with the following conditional:
// oldest post is the 4 o'clock document
if (oldestPost) {
postsQuery = postsQuery.startAfter(oldestPost);
}
I get the 4 and 5 documents again. If I change startAFter to be any other filter, I get 0 documents returned.
So my question is, am I just doing it wrong, OR can I not pass in a document.data() as the filter, and i need to pass in the original document instead?

So answering my own questions:
when i got my posts, I was just storing them in an idMap
postsQuery
.get()
.then((documents) => {
const typeIdToDocument = {};
documents.forEach((document) => {
const data = document.data();
typeIdToDocument[document.id] = { id: document.id, ...data };
});
Then when I passed in an startAfter, I used the .data() result of the post.
However, it worked when-
A) I passed in the original firebase document, not the .data() version
OR B) I passed in the Firebase Timestamp, rather than the full document
postsQuery = postsQuery.startAfter(oldestFirebaseTimestamp);

There are two overloads of startAfter:
startAfter ( snapshot : DocumentSnapshot < any > ), which is the one I recommend you use whenever you can
startAfter ( ... fieldValues : any [] ), into which you can pass just the field values of the document to start after.
The reason I recommend the first overload is that there may be cases where you have multiple documents with the same field value. The first overload is smart enough in that case to use the document ID to disambiguate between those and not return any overlapping documents. The second overload can't guarantee that.

Related

How to query an array on a db firestore?

I don't think I'm very far from the answer, I tried to query an id inside an array on Firestore.
I wanna compare the id of the participants.
Also my DB in Firestore:
And also my function, for the moment my function return size =0 so they can't catch the query.
const deleteAbuse = (type) => {
const participants = channel?.otherParticipants;
if (!participants || participants.length != 1) {
return;
}
const myID = currentUser.id;
const otherUserID = participants[0].id;
console.log('id user', otherUserID);
channelDB
.where('participants.id', '==', otherUserID)
.get()
.then((querySnapshot) => {
console.log(querySnapshot.size);
querySnapshot.forEach((doc) => {
console.log(doc.ref);
//doc.ref.delete();
});
});
};
There is no way you can query filter your "channels" collection to get documents based only on a single field of an object that exists inside the participants array. In other words, you cannot create that filtering based only on that ID. To be able to filter the data, you should pass to the where() function, the entire object, and not only some partial data. The object should contain values for all the fields. Only the ID is not enough.
And also my function, for the moment my function return size =0
That's the expected behavior since in your array there isn't any object that holds only a single field called id. All objects hold 7 fields, or even more than that, as I cannot see all fields in your screenshot.
I wrote an article called:
How to update an array of objects in Firestore?
Where you can find in the first part, the simplest way to get a custom object from an array of custom objects.
Alternatively, you can create an array that can hold only the IDs of the participants, filter the documents and create another database call to get their corresponding data.

Using equalTo() function in Firebase Database JavaScript v9

I am trying to use the equalTo function in the Firebase Database JavaScript v9 SDK. It's not very well documented like V8 is so can't figure out how to do what I want to do.
I want to filter results by the type field. My parent field is request-log with child elements like below.
{"backtrace":false,"message":false,"organisationID":"Empty","postData":false,"referrer":"Empty","remoteIP":"0.0.0.0","requestMethod":"POST","time":1630129562,"type":"Error","url":"Empty","user":{"email":"Empty","firstName":"George","id":37,"lastName":"Bates"},"userAgent":"Empty"}
I am trying the following, but not getting any results when loaded:
const readNewLogEntries = query(child(ref(db), 'request-log'), equalTo('Error', 'type'));
I have also tried this, as the reference docs say for the 2nd argument in the equalTo() function
This argument is only allowed if ordering by child, value, or priority.
But this isn't working either
const readNewLogEntries = query(child(ref(db), 'request-log'), orderByChild('type'), equalTo('Request', 'type'));
EDIT: Screenshot of DB
Remove the second parameter from equalTo().
The optional key argument can be used to further limit the range of the query. If it is specified, then children that have exactly the specified value must also have exactly the specified key as their key name. This can be used to filter result sets with many matches for the same value.
const getData = async () => {
const readNewLogEntries = await get(
query(ref(db, "request-log"), orderByChild("type"), equalTo("Request"))
// Filters where "type" is equal to "Request". Single arg here ⬆
);
console.log(readNewLogEntries.val())
return readNewLogEntries.val();
};
You can read more about the parameters in the documentation

Query specific uid in Firebase using Angular2+

Im really confused on how to query a single record in firebase by the uid.
I have a user id and want to query the following table. I am using the following code.
However, it is returning both the records instead of just the 'this.selectedId' one. Is there 1) A way to just return the record being queried 2) keep the key instead of array of index 0, 1, 2, 3 etc...
Code used
const itemsRef = this.afs.collection<any>(`/profiles/`);
itemsRef.valueChanges(this.selectedId).subscribe(
x => {
console.log("Value change", x);
}
);
Image
Returned result
The valueChanges method doesn't take any parameters. If you want to monitor a single document
const itemRef = this.afs.doc<any>(`/profiles/`+this.selectedId);
itemRef.valueChanges()...

Access the second item in Collection [Map]

I'm making a discord bot, and fetching some messages. I got this object
//This parameters changue every time i fetch
Collection(3) [Map] {
'848689862764789770' => Message {...
}
'848689552410804234' => Message {...
}
'848689534485004319' => Message {...
}
I can access the first and third entry using .first() and .last().
I've been trying to use Object.keys() but it returns undefined.
const mensajes = await message.channel.messages.fetch({ limit: 3 });
console.log(mensajes[Object.keys(mensajes)[1]])
Tip:
.first() can take a parameter that will return the first x amount of entries you choose and will then convert the Collection into an Array. Do .first(2) - this will return the first 2 entries - and then access the 2nd element as you would with any other Array.
// Will return 2nd entry
<Collection>.first(2)[1]
Suggested Solution:
You can also call .array() on the Collection to directly convert it into an Array.
// Also returns 2nd entry
<Collection>.array()[1]
<Collection> is a placeholder for your actual object
Learn more about working with Collections in This Guide
DiscordJS's docs has some information on this. You can transform this Collection utility class intro an array with a bunch of methods that exist for it, depending on what you need to access.
Then you can use the array, for example, to access the specific value.
// For values. Array.from(collection.values());
// For keys. Array.from(collection.keys());
// For [key, value] pairs. Array.from(collection);

Firestore query 'array_contains' pass in array [duplicate]

This question already has answers here:
Firestore search array contains for multiple values
(6 answers)
Closed 3 years ago.
I am looking at Firebase, cloud firestore and I am not understanding how I would perform a query and pass in an array.
const friendIds = [1, 2, 3];
Firestone.collection('conversations')
.where('members', 'array-contains', friendIds)
.get()
.then(querySnapshot => console.log(querySnapshot))
.catch(error => console.log(error));
anyone know how to achieve this?
This is currently not possible with a single query. array-contains can only find a single item in the named array.
Your alternative is to perform three queries, one for each item in the friendsId array, then merge the results in your code.
Not sure if this is possible, but here's an example from the Firebase Node.js Snippets that can give you an idea:
let citiesRef = db.collection('cities');
// [START array_contains_filter]
let westCoastCities = citiesRef.where('regions', 'array-contains',
'west_coast');
// [END array_contains_filter]
westCoastCities.get()
.then(res => {
console.log('West Coast get: ', res);
});
Reference Documentation
According to the official documentation regarding query operators:
You can use the array-contains operator to filter based on array values.
As I can see in your code, your friendIds argument that is passed as the third parameter to the where() function is of type array. What you are actually doing, you are searching in the members property which is of type array for an array, which is actually not possible since I assume the members array in your database contains numbers.
An query like this:
Firestone.collection('conversations')
.where('members', 'array-contains', 3)
.get()
.then(querySnapshot => console.log(querySnapshot))
.catch(error => console.log(error));
Will work perfectly fine because we are searching within the members array for a number.
If you need to query for all those numbers, you should perform three separate queries and combine the result client side.

Categories

Resources