Cannot publish a MongoDB collection from the server to client Meteor - mongodb

I want to publish a sever side collection to the client side.
In Server Side
MedicalCenters = new Mongo.Collection('medicalCenters');
Meteor.publish('medicalCenters',function () {
return MedicalCenters.find({});
});
I want this collection only to be accessed by a particular template. Thefore,
In Client Side
Template.doctor.onCreated(function () {
Meteor.subscribe('medicalCenters');
});
Now I can pass the data from client side template and even write to the serve side collection. But it seems to be subscription did not work and therefore, I cannot display collection data in the template.
(The collection is not displayed in the meteortoys Mongol)
How do I fix this?

It sounds like you have not placed your collection definition code in a common location that is executed by both the client and server. I'm making this assumption because you said that the collection itself was not visible in mongol.
Remember that in order for publish/subscribe to work, collections must exist on both the client side (using minimongo) and the server side (using mongodb).
Refer to the Meteor Application Structure guide for the details, but essentially you should put your collection definition code in a file that is not within a special directory (e.g. the server/ or client/ folder). Doing so ensures that the code is executed by both the client and server (per the meteor api docs).
All JavaScript files outside special directories are loaded on both the client and the server.
In the older meteor days (before we had the imports/ folder) people often placed their collection definition code inside a lib/ folder within the meteor project root. Now it's common for it to be within the import/api/ directory as described here.

Try adding a helper to send the data to the template:
Template.doctor.helpers({
medicalcenters() {
return MedicalCenters.find();
}
});
Then in your template you can loop through the medical centers
<template name="doctor">
{{#each medicalcenters}}
{{name}}
{{/each}}
</template>

Related

Change MongoDB Collection from local to server-side on running Meteor App

Due to the Meteor Docs there are 'server-side', 'client-side' and 'local' Collections. Is there a way to change the 'status' (e.g. if it's server-side, client-side or local) on a running app?
Use Case: A Web-Application where users can register and login. They can store sensible data. Depending on the Users personal preferences he should be able to choose if that data is stored local or on the server (General decision - not from case to case).
Current Approach: It's working fine if I either instantiate the Collection local CollectionName = new Mongo.Collection(null); or server side CollectionName = new Mongo.Collection('collectionName');.
But I can't think of an approach to make it possible to the user that he can change the Collection status.
Is there a way to do this?
Or is a workaround needed (e.g. Create both, a local and server-side Collaction, and just decide which to use for insert/update/find - what would mean a lot of duplicate code?!).
Edit: To make thinks clear: I want the user to be able to choose if his data is stored in a collection which is synced with the server or a collection without any syncing.
No, you can't change the type of a collection on a running app.
I think you are confused about what these terms mean. "Client-side" collections aren't permanently stored in localstorage. It just means it's a collection that's in the browser's memory. Just as "server-side" collections are those that reside in the server's memory. The difference is not how it's defined, but where the code runs. Most collections have a client-side and a server-side counterpart, and they are kept synchronized via pub/sub. Server-side collections are also synchronized with MongoDB (using the oplog).
Local collections can live in both places, but "local" means they aren't synchronized with anything.
I probably don't fully understand what you are trying to do, but local collections do not persist data.
If you pass null as the name, then you’re creating a local collection. It’s not synchronized anywhere; it’s just a local scratchpad that supports Mongo-style find, insert, update, and remove operations. (On both the client and the server, this scratchpad is implemented using Minimongo.)
This means any data added to them on the client will be blown away when the user closes their browser (unless you are also using one of the local collection persist meteor packages) and any data added to them on the server will be blown away when the meteor app is restarted. So I don't think you really want to use local collections.
Instead, I would use a regular collection (where a name is passed to the constructor) and either the standard allow or deny options (not really recommended anymore...but still a valid approach) or Meteor methods (the preferred approach) to control who can change data and what data is allowed to change.
Or, another option could be to pass your publication function a list of fields that the user wishes to see on the client for that given session. To do this you defined a new publication that receives a displayFields argument that you then use as the field specifier options in your collection .find().
Meteor.publish("userData", function (userId, displayFields) {
// validate the structure and contents of displayFields
// retrieve the data but only use the fields that the user requested
return UserData.find({user_id: userId}, {fields: displayFields});
});
Then on the client side you would subscribe to this and pass in the fields the user wishes to make visible on the client.
var displayFields = {
firstname: 1,
lastname: 0,
//...
};
this.subscribe("userData", [displayFields]);

how meteor match subscription with client collection?

on meteor server side, this looks fine, which maps server side collection to publication
if (Meteor.isServer) { // This code only runs on the server
Meteor.publish('tasks', function tasksPublication() { return Tasks.find(); }); }
and the following on the client side is also understandable, which maps subscription to publication by name.
Meteor.subscribe('tasks');
But I couldn't find in any tutorial or docs explaining how subscription and client side collections are mapped to each other. There is no code mapping tasks (subscription) to Tasks (client side collection). Meteor might assume the client collection uses the same name as the server side by both including the same collection declaration (Tasks = new Mongo.collection('Tasks');). But what if I want to use a different collection name on the client side? or what if the info sent by the server is a mix of fields from multiple collections, how do clients know which collections to store this info when they get it from subscription?
This is part of the way Meteor works. It automatically synchronises data in collections between client and server. You don't need to worry about it, and you can't change it.
Your helper methods can pull data from different server collections, and put the data in arrays - you can read from different collections to do this, and you can do it reactively, so when the source collection changes it will run your helper again.
You can also define client only collections, which don't get saved to the server.
So you can probably do what you want, and if you then want to save something from your smooshed data, you would probably write a piece of code to extract the data to be updated into an object, and then save that.
Lets breakdown the code:
Meteor.publish('tasks', function() {
return Tasks.find();
});
Here we have defined a publication name 'tasks' which supplied data it has received from the function return Tasks.find().
Similarly, when subscribing, we refer to that particular publication- tasks in this case and we get those data.
Now coming to the part of linking it to the collection. In Meteor, when you define a collection, it should be defined on both client and server. So when you define a collection like Tasks = new Mongo.collection('tasklists');, On server, the Tasks object refers to the collection tasklists that the server will use to communicate with the mongoDB server. On the client, an object with the name Tasks is created to interact with the database minimongo created in client for tasklists. The Minimongo is a client side API in JS for MongoDB. (You can consider it as a client side replica of the mongoDB database).
So, on client side, you can define Tasks as anything as long as it is an object for the mongoDB collection tasklists- e.g AnyName=new Mongo.collection('tasklists');
Regarding how publication and subscription will know, which collection are we talking about: Publications send across something known as cursor which is related to a particular document(s) and collection in 'mongoDB'. As long as you get the collection name( tasklists) correct, you can have different object names(Tasks) on client and server.

How to connect a Meteor site to an existing db & collection?

I have server & client files and am trying to send some data to Javascript rather than into a template. In the template, I can output some values, but I need it in JS to add markers to Leaflet.
I guess, there's no sense to funnel the data through templates to get it into JS and into Leaflet, right?
What am I doing wrong?
shell
$ mongo
MongoDB shell version: 2.4.9
connecting to: test
> use atms
switched to db atms
> db.markers.count()
1868
Running the server:
$ MONGO_URL=mongodb://127.0.0.1:27017/atms meteor
lib/collections.js
Markers = new Meteor.Collection('markers');
In the client/client.js, I try to get records from the collection, but it's empty:
Template.hello.helpers({
marks: function () {
// this data renders correctly on map
return Markers.findOne({})
}
});
Template.hello.onRendered(function() {
// this data is empty in console
var query = Markers.find().fetch();
console.log(query);
});
In the template, it shows one record, which means the connection works. But console output is [].
The main problem is you have 2 different Markers collection on client and server. So, on the client, meteor accesses client Marker collections and does not show any data. Collection definition should be shared between client and server, not duplicated.
Make a folder lib and put the collection definitions there
//lib/collections.js
Markers = new Mongo.Collection('markers')
And remove the collection definitions in both server and client folder.
Also, be aware that when you use the separated mongo instance, the reactivity will happen quite slow (2 or 3 times compared to the embedded mongo)
Pretty sure this is answered here:
Using Multiple Mongodb Databases with Meteor.js
Just a note on the syntax, in ver 1.2.1 you want to declare your Meteor collection as a global variable so it can be accessed outside of the file you type it into. Also, you want to put this line in /lib or a directory that can be accessed by both the client and server.
Markers = new Mongo.Collection('markers')

Access to collection from client folder

Hi im getting started with meteor, so i have a problem: I can't access to collection from client folder
my project struct is default: meteor create testApp
/testApp
--.Meteor/
--testApp.html
--testApp.css
--testApp.js
then i create a mongo collection i add it to testApp.js
city = new Mongo.Collection('data');
running the app with meteor command, then i access to chrome console
city.find().fetch(); it work perfect and it return the cities
but when i move testApp.js , testApp.css , testApp.html to new folder named /client
/testApp
--.Meteor/
--client/
----testApp.html
----testApp.css
----testApp.js
i cant get the collection from chrome console it mean city.find().fetch(); return []
any idea ?
This is normal behavior. client and server are considered special folders by meteor, where respectively only the client or the server will execute the code that they contain. It is the equivalent of an implicit if (Meteor.isServer)
When you declare a collection in the client folder only, it will only create an empty collection in your client-side database, MiniMongo. Therefore, your MiniMongo collection has no link to any server-side, "real" mongodb collection. That is why you cannot access the data saved into your actual mongodb database.
So in order to fix this, what you can do is either:
declare your collection once in a separate js file, outside of your client and server folders so that both sides are aware of that collection (recommended in most cases). I use a collections folder at the root of my app for that
declare your collection twice : once in your client folder like you did, and another time in the server folder at the root of your app (useful in specific cases such as capped collections, etc)

Import "normal" MongoDB collections into DerbyJS 0.6

Same situation like this question, but with current DerbyJS (version 0.6):
Using imported docs from MongoDB in DerbyJS
I have a MongoDB collection with data that was not saved through my
Derby app. I want to query against that and pull it into my Derby app.
Is this still possible?
The accepted answer there links to a dead link. The newest working link would be this: https://github.com/derbyjs/racer/blob/0.3/lib/descriptor/query/README.md
Which refers to the 0.3 branch for Racer (current master version is 0.6).
What I tried
Searching the internets
The naïve way:
var query = model.query('projects-legacy', { public: true });
model.fetch(query, function() {
query.ref('_page.projects');
})
(doesn't work)
A utility was written for this purpose: https://github.com/share/igor
You may need to modify it to only run against a single collection instead of the whole database, but it essentially goes through every document in the database and modifies it with the necessary livedb metadata and creates a default operation for it as well.
In livedb every collection has a corresponding operations collection, for example profiles will have a profiles_ops collection which holds all the operations for the profiles.
You will have to convert the collection to use it with Racer/livedb because of the metadata on the document itself.
An alternative if you dont want to convert is to use traditional AJAX/REST to get the data from your mongo database and then just put it in your local model. This will not be real-time or synced to the server but it will allow you to drive your templates from data that you dont want to convert for some reason.