Skip to content
jagi edited this page May 26, 2015 · 3 revisions

Table of content

Basic operations

// Create global (no var keyword) Mongo collection.
Posts = new Mongo.Collection('posts');

// Create global (no var keyword) class (model).
Post = Astro.Class({
  name: 'Post', // Name model.
  collection: Posts, // Associate collection with the model.
  transform: true, // Auto transform objects fetched from collection.
  fields: {
    title: 'string', // Define "title" field of String type.
    votes: {
      type: 'number', // Define "votes" field of Number type.
      default: 0 // Set default "votes" field value to 0.
    }
  },
  methods: { // Define few methods.
    voteUp: function () {
      this.votes++;
    },
    voteDown: function () {
      this.votes--;
    }
  },
  behaviors: ['timestamp'] // Add "timestamp" behavior that adds "createdAt" and "updatedAt" fields.
});

// Create object of our class.
var post = new Post({
  title: 'New post'
});
// Save object in the collection
post.save();

// Change title
post.title = 'Post title changed';
// Get modified fields.
post.getModified(); // Returns {title: "Post title changed"}
// Update object (save changes into collection).
post.save();

// Remove the object from the collection.
post.remove();

Templates

if (Meteor.isClient) {
  Template.Posts.helpers({ // Provide "posts" cursor for all posts in the collection.
    posts: function() {
      return Posts.find();
    }
  });

  // Voting up and down for post is as easy as calling "voteUp" or "voteDown" method on the object.
  // The "this" keyword in the event listener is an object of our "Post" class.
  Template.Posts.events({
    'click .up': function() {
      this.voteUp();
      this.save();
    },
    'click .down': function() {
      this.voteDown();
      this.save();
    }
  });
}
<head>
  <title>Posts</title>
</head>

<body>
  {{> Posts}}
</body>

<template name="Posts">
  {{#each posts}}
    <p>{{title}} <a class="up">Vote Up</a> | <a class="down">Vote Down</a> | <b>({{votes}})</b></p>
  {{/each}}
</template>

You can access document's fields the same way you would do it without Astronomy.

<div>
  <p><a href="/post/{{post._id}}">{{post.title}}</a></p>
  <div>{{post.votes}}</div>
</div>

You can also call document's methods like you would do normally.

Post.addMethods({
  getMessage: function() {
    return 'Post title: ' + this.title;
  }
});
<div>{{post.getMessage}}</div>

Iron Router

When working with Iron Router, we may want to create a link redirecting us to the given route using a document's id. Let's take a look at routes defined below. We have the route for all posts list and the route for displaying an individual post. The path consists of the /post/ prefix and a document's id.

Router.route('/', {
  name: 'posts',
  template: 'Posts'
});

Router.route('/post/:_id', {
  name: 'post'
});

Now, we define the helper on our template that returns a cursor for all posts.

if (Meteor.isClient) {
  Template.Posts.helpers({ // Provide "posts" cursor for all posts in the collection.
    posts: function() {
      return Posts.find();
    }
  });
}

The first thing you may try to do when creating a link to the post is writing a code similar to the one posted below.

<div>
  {{#each posts}}
    <p><a href="{{pathFor 'post'}}">{{title}}</a></p>
  {{/each}}
</div>

This code will not work. Iron Router looks for the _id field directly on the level of the document. However, the _id field is not there. The _id is stored in the internal object _values and we have the getter function defined for a document that takes care of getting the _id field. Fortunately, we have the get function that gets pure values (a simple JavaScript object). The correct code will look like follows.

<div>
  {{#each posts}}
    <p><a href="{{pathFor 'post' data=this.get}}">{{title}}</a></p>
  {{/each}}
</div>

Meteor methods

The Astronomy objects can be passed to Meteor methods without any modifications. All Astronomy classes are EJSON-able. It means that they can be transfered from the client to the server (and vice versa) using the DDP protocol.

Meteor.methods({
  '/user/method': function(post) {
    if (post.validate()) {
      post.save();
    }
  }
});

var post = Posts.findOne();
Meteor.call('/user/method', post);

Users collection

It's possible to apply an Astronomy model to the Meteor.users collection. The minimal class schema looks like the one below.

User = Astro.Class({
  name: 'User',
  collection: Meteor.users,
  fields: {
    emails: 'array',
    services: 'object',
    createdAt: 'date'
  }
});

Of course you will have to add to the schema any extra field that you want to publish. The example above works with the accounts-password package.

Clone this wiki locally