Meteor pagination: cursor fetch limit with getmore - meteor

I have an infinite scroll page where I'm not using Meteor templates to draw the items. The reason for that belongs in a whole other thread. I'm trying to figure out how to paginate the data without fetching all the items at once. I have an idea about using a limit on the cursor, but can't find any real samples online of the proper way to do this.
Should the server call return the cursor itself or just the find with limited data set? If the server doesn't return the cursor itself, won't I lose position when I try to fetch the next set of results?
Also, I want to make sure to retrieve data from the same cursor. Like if there are currently 100 items and I fetch 20, I expect the next 4 fetches to get 20-40, 40-60, 60-80, and 80-100. If in the interim some items got inserted or deleted, I don't want it to mess up the fetches. I am handling reactivity separately and letting users decide when to update the items (which should reset the cursor).
Help/advice appreciated!

What you would usually do is this:
var cursor = collection.find({},{limit:100+20*page});
The first {} is obviously the selector!
Docs:
http://docs.meteor.com/#/basic/Mongo-Collection-find
You don't have to worry about returning only the values 100-120 and then 120-140 etc. since meteors ddp does that for you!
If you were using meteor's blas or you just want to have the reactivity, you should probably store the page variable in the Session or create a dependancy:
https://manual.meteor.com/#deps-asimpleexample

Related

Can we trigger firebase cloud functions when we create a collection (not "document")?

I am trying to achieve a scenario where firebase triggers only once when a collection is created and not every time that a document is added to the collection. Let's say I want it to trigger only for the first document added to the collection and not for every other document added to the same collection. How can that be done? Please help !!!
There is no such trigger for Cloud Functions. Your trigger path must specify exactly one document, or use wildcards to specify a path that could possibly match many documents.
If you want to know what a collection contains its first document, you will have to either:
Maintain a count of documents in that collection (perhaps in yet another document in another collection), and trigger of the change of that value when it goes from 0 to 1.
Query all of the documents in the collection where a document was just created in order to figure out if it was the first one.
Both of these requires a fair amount of extra code - very much not trivial to implement correctly for arbitrary collections. They could also run into problems under heavy load. If these options won't work for you, I suggest figuring out another way to get you function to trigger at the right time.
While It's not possible to do directly. You can check if collection contains any elements, and if it does it means that it exists.
const result =await firestore.collection("collection").limit(1).get()
if(result.size){
// Collection exists
}

How do I create a Firebase collection?

So I am writing a chat application that I want to have multiple rooms, however, I can't find a button on the Firebase console that I can add child collections.
I've tried exporting, editing, then importing but that doesn't seem to do much. I have looked at some Firebase tutorial's but I can't find one that explains this.
Anything you enter in the console has to have a value itself, or at least one child (with a value). This is because Firebase does not explicitly store "null" or empty values in the database. You can enter the name of the collection and then rather than a value use the + button at the right to start adding children to it and so on until you reach a node with a value:
You cannot however simply create a placeholder for a collection that has no values. If you need a collection but can't initialize any of its data, just use your security rules to define what's allowed and write your client code knowing it may or may not exist. Firebase allows you to attach listeners to nodes that don't exist yet.

Meteor UX Issue: After adding item to a sorted list, the item is added to the top and then sorted

I am creating a basic chat with Meteor.
On the client I do:
div.chat-discussion
each messages
+chatMessage
The helper is
Messages.find
conversationId: t.data.conversation._id
,
sort:
createdAt: 1
So I am sorting the chat message in order from oldest first to newest last.
The chat looks like this
But whenever I send a message, it isn't added directly to the bottom.
It is added to the top for a few milliseconds and then shifted to the bottom.
It makes the UX feel glitchy. Why is this happening, and how can I fix this?
UPDATE
I seemed to have fixed the issue by removing the sort and just returning the messages in the helpers like
Messages.find
conversationId: t.data.conversation._id
So if I don't sort client side, the message is added to the bottom of the message list automatically without flashing. I am not sure how or why. I guess by default it is sorted in order of oldest first.
There is no default sort on a collection other than FIFO which means as long as you do not sort, the records are send as they were written.
If you just have continously messages, this may fit your needs, but when you are in sync / offline situations sometimes, you might get the list not as it is when time sorted.
I guess you are using autopublish on server?
You should write your own server publish method and return the sorted list already from server.
So on client you may subscribe then just by find() or do also the sort on mini-mongo (preferred)
This should prevent glitchy UX
Cheers
I figured out what was happening.
The problem in the end was a conflict with the sorting I was using and how the timestampable (https://atmospherejs.com/zimme/collection-timestampable) package adds the createdAt field.
I was sorting on the client by the field createdAt, which is added by the timestampable package. The issue is that the field doesn't exist when the document is first inserted, so that is why I saw the message append to the top of the list and when the createdAt field got added right after, then it jumped down to its sort position.
To fix this I am adding a field called sentAt upon insertion, and now also sorting by that field.
This fixed the issue. I was trying to sort by a field that did not exist upon insertion. This will show itself in the UI even if the field is added right after insertion.

Meteor - how to reactively render arrays instead of cursors (eg. the result of fetch() instead of find() )

I have a Meteor collection of items, which I need to search/sort/ordering according to rules that are too complex for a MongoDB/minimongo query.
For example, consider a search algorithm that returns results in order of relevance, but runs on the client for speed.
In order to render the items, I call MyCollection.find().fetch(), sort the results and pass them to the template.
This means that any time one of the items in the search results changes, or an item is added/removed, all of the items in the search results are re-rendered.
Is there a way to prevent all items being re-rendered when only one is changed/added/removed?
I think if you change your 'MyCollection.find().fetch()' to a meteor.call('methodToFetchMyCollectionInModel'), and make sure you have Meteor.subscribe('MyCollection') in your client, the client is reactive to 'change/add/remove'.

Firebase better way of getting total number of records

From the Transactions doc, second paragraph:
The intention here is for the client to increment the total number of
chat messages sent (ignore for a moment that there are better ways of
implementing this).
What are some standard "better ways" of implementing this?
Specifically, I'm looking at trying to do things like retrieve the most recent 50 records. This requires that I start from the end of the list, so I need a way to determine what the last record is.
The options as I see them:
use a transaction to update a counter each time a record is added, use the counter value with setPriority() for ordering
forEach() the parent and read all records, do my own sorting/filtering at client
write server code to analyze Firebase tables and create indexed lists like "mostRecent Messages" and "totalNumberOfMessages"
Am I missing obvious choices?
To view the last 50 records in a list, simply call "limit()" as shown:
var data = new Firebase(...);
data.limit(50).on(...);
Firebase elements are ordering first by priority, and if priorities match (or none is set), lexigraphically by name. The push() command automatically creates elements that are ordered chronologically, so if you're using push(), then no additional work is needed to use limit().
To count the elements in a list, I would suggest adding a "value" callback and then iterating through the snapshot (or doing the transaction approach we mention). The note in the documentation actually refers to some upcoming features we haven't released yet which will allow you to count elements without loading them first.

Resources