Accessing Non persistent collection on client


#1

Hi,

Intro:
I needed to make a local collection hold a temporary list of results coming from a third party API.
The reason I choose for a local minimongo collection is to easily implement a Show More option.
I create a local collection like this (CoffeeScript);

@EpisodeList = new Meteor.Collection  null

Question: In a Meteor method I receive the full data of the third party api. There I run an forEach loop inserting each record in my local collection.

results.episodes.forEach ( item, idx ) ->
     EpisodeList.insert
          title:              item.title[ 0 ]
           description:        item.description[ 0 ]

Now I thought I read somewhere in the docs that a collection can be accessed on client as server.
I am not sure if this is also the case for a non persistent collection like mine.

when I run the method and then in my client do Episode.list.find().fetch() I always see an empty array as result.
When I do a console.log on the server just before the return of my method, I see the EpisodeList is full of documents.

To test my assumption that the collection only lives on the server, I added another method that retrieves the documents from the server.

    getEpisodes: ( filter)->
    return EpisodeList.find().fetch()

Executing this call from the client results in many documents.

So I have a working solution, using another call. But I thought Meteor would automatically push this collection to the client so that I can access it.
Setting up a subscriber can’t be done with a non persistent collection (right)?

Hope that someone can shed some light.

Cheers

UPDATE: I have another issue: the collection is public right now. Can you make it private for each client that access the application? I haven’t implemented users yet but if so, I should do that now

UPDATE 2: This probably answer both my questions: I have moved the EpisodeList.insert to the client, which inserts the data in the client minimongo (duh!!).
I just wanted to prepare all data in the server method call, seemed to be the right place for grabbing the data and put it in a non persistent collection. But of course, it can never be private per client that way, right?


#2

You can prepare your data on the server and publish it to a collection on the client and the publication can take in a userId parameter so that the user gets their provate data only.


#3

Hi, could you give an example? With server and client data.
I easily get confused with the collections part of Meteor. I have just started to work with this platform.


#4

Sure. First, a couple of pointers.

  • A collection can be either on the server or on the client.
  • The collection on the server is not the same as the one on the client even if they have the same name. The one on the client is a representation of the one on the server. It contain a subset of the data.
  • You can have a server-only collection which you don’t need to exist on the client
  • You can have a client-only collection which is essentially private to that client

What constitutes a bridge between the collection on the server and the one on the client is the publish/subscribe mechanism.

  • You take data from the collection on the server and publish it to your client.
  • Your client subscribes to that publication and puts it in the collection on the client.

Therefore, as you may probably have realized now, you can take any data from the server and publish it so that it can be put into a collection on the client. That data on the server can perfectly originate from an external API for example.

So, given this preamble, here are some very good resources for you to grasp the whole concept with an easy to follow tutorials:


#5

Thank you very much for your in-depth response.
Especially this link is helpful: http://meteorcapture.com/publishing-data-from-an-external-api/

I have used that example before.
The only variation I have is that when I do my API call I get 2 things back:
-one document with meta data about the channel,
-a collection of episodes.

Those episodes I want in my client-side collection so that I can use mongo functions. The meta data I do not want to store, but just return to the client for display purposes.

Some more content: from a list of channels, you select a channel. Then for this channel the details are retrieved which encompasses meta data about the channel and episodes lists.
I display the meta data and show a list of episodes below with Read more option (for which I want to use the limit function in mongo with reactivar or session var).

What I did so for was call a Method from the client with the channel url and grab the meta and episodes.
Then I tried to fill the collection from the server using the Insert function, however, the collection was defined on the client without a name. So this filling did not work.

Now I am actually doing the filling in the Meteor Publisher on the server, which will work fine for the episodes which can neatly fit in an Episode collection. However, the meta data is now a little orphan. I don’t want to put it in the same collection but it is already retrieved with the same HTTP call that got me the episodes.

I dont really want to do 2 calls, one the get and return the meta data of the channel and than one to get the episodes and put them in a collection.

Is it possible to fill the collection on the server outside of the publisher function? That would solve the issue, because than I can do it in the method that calls all the data for the channel, then fills the publisher with episodes and returns the meta to the client. Then on the client I could subscribe and fetch the data.

Is something like this possible?

Update:
What I do now is that when the client selects the channel, call the method that gets the channel meta data + episodes with one HTTP.
Then I format the data and send the result back to client.
There I used to fill the nameless collection with the insert function, but now I call the subscribe and pass the episode data I got from the HTTP method call:

        Meteor.call( 'getFeedContent', Session.get( 'feed' ).url, ( error, result ) ->

            if result
                 instance.channel.set( result )

                Tracker.autorun( ()->

                    searchHandle = Meteor.subscribe( 'episodes', result.episodes )
                    Session.set('searching', ! searchHandle.ready());

Then below in my template helper I do the find:

    episodes: ->
    instance = Template.instance()
    return Episodes.find()

This solution works.

However, adding the data in the client with Episodes.insert() or sending the data back to the Subscriber on the server and ussing Added their results in the same thing.
I do like it that the collection is filled in the Publisher file.

What are your thoughts?


#6

If the external api requires two calls for channel an episodes, you can make both calls on the server and combine them within a single publication on the server to end up in a single or multiple client side collections.

Basically, publications can publish more than one data source and publish to more than one collection and you can use a combination of these strategies.

So if I were you, I’d do multiple server side api calls and combine them into a single collection on the client.


#7

The Api doesnt require 2 calls, but delivers 2 sets of document in one result.
One is meta data and in this document there is a collection of episodes.
I want the store the episodes temporarily so view them in the client and make it searchable.
Then the user can select episodes and those references will be stored in persistent storage.
The meta data about the channel is just being displayed in the client so I don’t want to store that at all.

But all of this happens in the Meteor.method call.


#8

What I meant was, you can store the whole data on the client collection since it will be deleted by the end of the session anyway.

You can then use a second meteor call to insert the data you want to keep into a server side persistent collection.


#9

okay, yes agreed.
Thanks for your help!
Was of great use.