Meteor.js Collection not being created in mongo - javascript

Server Side Code:
if (Meteor.isClient) {
Meteor.subscribe("messages");
Template.hello.greeting = function () {
Messages = new Meteor.Collection("messages");
Stuff = new Meteor.Collection("stuff");
return "Welcome to feelings.";
};
Template.hello.events({
'click input' : function () {
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
var response = Messages.insert({text: "Hello, world!"});
var messages = Messages.find
console.log("You pressed the button", response, Messages, Stuff);
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
Messages = new Meteor.Collection("messages");
Messages.insert({'text' : 'bla bla bla'});
});
}
Client Side Code
<head>
<title>Test</title>
</head>
<body>
{{> hello}}
</body>
<template name="hello">
<h1>Hello World!</h1>
{{greeting}}
<input type="button" value="Click"/>
</template>
The problem:
When in javascript console I type Messages.insert({'text' : 'test test test'});
or click the button, underneath which a database insertion call is written
I don't see a document inserted in mongo. Going to mongo console and doing show dbs shows
messages (empty)
I have a few other questions, I have read through the meteor docs and also googled but I can't seem to find a clear answer to this:
Why do I need to declare a collection in client as well as server code?
I'm declaring collections inside Template.hello.greeting, what's the difference if I put it in if(Meteor.isClient) block directly.
Is any plans of adding some app directory structure in meteor like rails? where models and templates are separate? I'm not talking about express.js
Thanks.

You need to create the MongoDB collection in a global scope like outside of both the isClient and isServer scopes. So remove Messages = new Meteor.Collection("Messages") from that helper function and place it in global scope.
You cannot perform insertion directly through client, as meteor doesn't allows database insertion from client code. If you still want to insert/update from client, you must define database rules for client, see docs.
Or the preferred way is to create a server method to insert document, and call it from client using Meteor.call().
Creating collections inside Template.hello.greeting doesn't makes any sense, since the collections are used to store data on server that is accessible from client.
Update: Meteor > 0.9.1
Creating collections in Meteor is now:
Messages = new Mongo.Collection("Messages")
instead of:
Messages = new Meteor.Collection("Messages")

Related

Publish subscribe doesn't seem to work

I'm new to meteor and I saw that it's better to remove autopublish.
So I try to publish and subscribe a collection to get two different values.
In my meteor side I have :
Meteor.publish('channelUser',
function(){
var user = Meteor.users.findOne({
'_id':this.userId
});
console.log(user);
var test = Channels.find({
'_id': {$in : user.profile.channelIds}
});
return test;
}
);
Meteor.publish('channelToJoin',
function(){
var user = Meteor.users.findOne({
'_id':this.userId
});
console.log(user);
var test = Channels.find({'_id': {$nin: user.profile.channelIds}});
console.log(test);
return test;
});
And in my client side in a first component I have :
this.channelSub = MeteorObservable.subscribe('channelUser').subscribe();
this.channels = Channels.find({});
And on a second component :
Meteor.subscribe("channelToJoin");
this.channels = Channels.find({}).zone();
But on my client side on both of the component, I have the same data.
Is there some kind of conflict in the subscribe ?
I hope I was clear to describe my problem !
Pub/Sub just fills your Client collection Channels.
You can see it as a flow filling your local bucket. You may have several subscriptions filling different documents of Channels collection, but all end up in that single collection on the Client.
Then you have to adjust your query on client side to get the documents you need (e.g. Channels.find({'_id': {$nin: user.profile.channelIds}}); on Client as well). Of course you may have different queries in different templates, and different from the server publication as well.
See also How do I control two subscriptions to display within a single template?
You cannot move a document between collections via a subscription. If you subscribe to get a document that's in Pages collection, defined as new Meteor.Collection("pages"), then no matter how your pub channels look like, on the client the document will be found in the collection defined as new
> Meteor.Collection("pages")
. So remove all traces of MyPages and use Pages on the client as well.

MeteorJS I can't seem to ever get a property of an object from the server

Hey guys I have been having a ton of problems with meteorJS, because I can't seem to ever access the properties of anything client side when I subscribe to the publication on the server side. I have a collection with a "daily event" for my users that I'm going to be trying to publish to the client side. But for some reason it's undefined on the client side, even though I can do a console.log on the server side and it works fine.
Here's the code:
Client side:
communityEvents = new Mongo.Collection("communityEvents");
Meteor.subscribe('communityEventsPub');
Template.communityEvent.helpers({
type: function(){
todaysEvent = communityEvents.find().fetch();
console.log("this is the event " + todaysEvent["type"]);
return todaysEvent.type;
},
event: function(){
todaysEvent = communityEvents.find().fetch();
return todaysEvent.event;
}
});
Server Side:
communityEvents = new Mongo.Collection("communityEvents");
Meteor.publish("communityEventsPub", function(){
console.log(moment().format('l'));
console.log(communityEvents.find({date:moment().format('l')}).fetch());
return communityEvents.find({date:moment().format('l')});
});
fetch returns an array. In your helpers you'd need to do something like:
var todaysEvent = communityEvents.find().fetch()[0];
or
var todaysEvent = communityEvents.findOne();
You can easily test a publication by opening your browser console and doing a fetch like so:
communityEvents.find().fetch()
Which will return an array (hopefully) that you can examine.

Meteor methods - Internal exception while processing message

I've been following the Discover Meteor tutorials in order to create an application that has autopublish and insecure disabled. Things have gone well with autopublish but I haven't been able to successfully display the posts in the collection on the webpage after removing insecure. Could you guys take a look and see what's going on? Thanks.
The tutorials:
https://www.discovermeteor.com/blog/getting-started-with-meteor/
https://www.discovermeteor.com/blog/meteor-and-security/
The code:
forum.js
Posts = new Meteor.Collection("posts");
if (Meteor.isClient) {
Meteor.subscribe("posts", "published");
Template.posts.helpers({
posts: function() {
Meteor.call("viewPosts","published");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
Meteor.publish("posts", function(status) {
return Posts.find({status: status});
});
Meteor.methods({
viewPosts: function(status) {
return Posts.find({status: status}).fetch(); //This is still problematic
}
});
Posts.allow({
insert: function() {
return true;
}
})
}
forum.html
<head>
<title>Forum</title>
</head>
<body>
{{> posts}}
</body>
<template name="posts">
<h1>Posts</h1>
<ul>{{#each posts}}
<li>{{name}}</li>
{{/each}}</ul>
</template>
The error message. This appears whether I add or remove .fetch() from the viewPosts method:
=> Meteor server restarted
I20150320-14:27:09.418(0)? Internal exception while processing message { msg: 'method',
I20150320-14:27:09.419(0)? method: 'viewPosts',
I20150320-14:27:09.419(0)? params: [ 'published' ],
I20150320-14:27:09.419(0)? id: '1' } Maximum call stack size exceeded undefined
The problem is coming from this block in your client code:
Template.posts.helpers({
posts: function() {
Meteor.call("viewPosts","published");
}
});
The primary way Meteor retrieves data for you on the client is through its publish/subscribe architecture, which you already have in place and looks good. That means that the posts you need to display are already there for you on the client and you don't need to do a Meteor.call() to the server to go and get them. Instead, your helper can just look like this:
Template.posts.helpers({
posts: function(){
return Posts.find({status: "published"});
}
});
Generally, you want to use Meteor.call() for responding to template events, e.g. in Template.posts.events({}). Server calls generally don't belong in helpers, though I guess there can be exceptions. See this excellent article under 'overworked helpers' for more on that: https://dweldon.silvrback.com/common-mistakes

Converting Backbone.js App to communicate with parse.com

I am an IT student and I'm learning how to use Backbone.js. I read all the documentation but I find it easier to learn when I use example apps,because I never have been programming this type of apps,so it was hard and confusing to think of a way to build my own app, so I used https://github.com/dperrymorrow/example-backbone-app to make similar edited app. The example app doesn't have a server side.
Now I need to connect the app to use parse.com as a backend(server-side) instead to use local collection.
If someone could please tell me what should I change and transform in the code so it connects example app to parse.com app with REST API so when I edit something in the app to be syncronized with parse.com.
I will be really grateful if someone is willing to explain this in a more descriptive way than saying :"you should read documentatin" because I did,and I still don't get the point :)
Have a nice day.
It's just about having the right backbone models and collections and settings the right url on the collection and urlRoot on the model. Then you can just can just call backbone methods like sync, save or delete.
Best detailled answer covering also the REST explanation probably is this one.
Cant you just swap the backbone collection and model to Parse's ones?
Parse.com is a webservice providing REST interfaces for anything you like, Lets connect that to our Backbone models.
First of all Lets create a new app on Parse.com, mine is called FunkyAppartments.
Insert the script tag for loading Parse javascript lib into index.html or whathever:
<script src="http://www.parsecdn.com/js/parse-1.5.0.min.js"></script>
Switch the backbone model and collection to use parse types instead (and rename the fetch method if you have extended backbones, since we do not want to overide the one of parse):
//var Appartment = Backbone.Model.extend(); Backbone wo. Parse.com
var Appartment = Parse.Object.extend("Appartment");
//var Appartments = Backbone.Collection.extend({ Backbone wo. Parse.com
var Appartments = Parse.Collection.extend({
model: Appartment,
initializeData: function(){
var self = this;
var callback = function (data){console.log(data); self.reset(data)};
S.Appartments.loadAppartments(callback);
},
loadAppartments: function(callback){
debugger;
this.query = new Parse.Query(Appartment);
var result = this.fetch();
callback(result);
return result;
}
});
I added a debugger tag in the load appartments so that developer tools breaks in the middle of the controller, here I have access to the Appartment private type of the controller, hence i can store some data on the parse server and verify by pasting the below in the developer tools console.
var testAppartment = new Appartment();
testAppartment.save({name: "foobars"}).then(function(object) {
alert("yay! it worked");
});
Yei, the data shows up in the parse.com UI for the app we just added there. And more importantly it shows up in our frontend. That was easy!

Javascript Backbone model design

Fairly new to JavaScript so it might be a noobish question.
At the moment for my project I'm using NodeJS for my server and Backbone for the client. The client will send a request to the server and the server will send list of files in the server, my aim was to simply return the list of files and when user click on the file it will send another request to the server to load the file.
Currently in the client level my model and collection is defined something like:
app.MyFile = Backbone.Model.extend({
defaults: {
modifiedDate: new Date(),
path: '',
content: '' // content of the file
}
});
var MyFileList = Backbone.Collection.extend({
model: app.MyFile,
url: '/api/files'
});
// create global collection of files
app.MyFiles = new MyFileList();
app.AppView = Backbone.View.extend({
initialize: function () {
// fetch all files
app.MyFileList.fetch();
}
});
// app.js (point of entry)
$(function() {
// Kick things off by creating the **App**.
new app.AppView();
});
And my server code:
var application_root = __dirname,
express = require("express"),
...
app.get('/api/files', function(req, res) {
...
// return file list
}
app.get('/api/files/:id', function(req, res) {
...
// return file content?
}
Since it doesn't make sense to load all files in the directory and send it back to the client, what I did was I created the model in the server and fill up modifiedDate and path while leaving content to null. But the problem now is that how do I fill up the content when user clicks on the file? I'm not sure how to manually send an HTTP request from Backbone View or controller. Or is there any better way of doing this? One way that I can think of is to create another model that only keeps modifiedDate and path but to me this looks very verbose and repetitive.
Given what you have on the client side, you may not need anything more.
app.MyFiles = new MyFileList();
app.MyFiles.fetch().done(function() {
// your collection is fetched but each model's content is empty.
// now, I assume at this point you will show them in some view/views.
});
Now when one of those things is clicked on, you can fetch the content.
var model = app.MyFiles.get(id);
model.fetch().done(function() {
// now the model's content attribute will be set
});
This might work with no more code than what you showed. Because the url a model uses to fetch is created by default by appending the model's id to the end of its collection's url.
So from your server, you return a json array from '/api/files': [{id:1, path:'foo'}, {id:2, path:'bar'}]
Then from '/api/files/1': {id:1, path:'foo', content:'whatever'}
When user clicks the file, you can call backbone's fetch method on the model. Then your model will be filled with data from the server.
Note that for this to be working you should return collection from the server first, where models at least have id's. Every other field will be filled after fetch call. Also, you should override model url, if it differs from standard (which is collection/id).

Categories