Skip to content
jagi edited this page Jul 15, 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();
    }
  });
}

Now, it's the time to create a link to the post. There are two possible ways of creating a link depending on a value of the Astro.config.supportLegacyBrowsers flag. If we want to support legacy browsers (default) we can create a link in the following way:

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

However, if we set the Astro.config.supportLegacyBrowsers flag to false, we have to modify this code to look like below:

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

Which actually calls the get method on each post object. The get method takes values of the all fields in the document. It's necessary, because with the Astro.config.supportLegacyBrowsers flag set to false, values of document are not stored directly in the document but in the private _values property.

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.