본문으로 바로가기

미티어에서 가장 중요한 개념인 발행(publish)과 구독(subscribe)는 기본적으로 서버의 MongoDB에서 클라이언트의 Mini-Mongo에 데이터를 컬렉션형태로 전달하는 개념이다.

 

발행과 구독에 대한 자세한 설명은 아래 링크에 나와있다.

http://kr.discovermeteor.com/chapters/publications-and-subscriptions/

 

 

Google Books API를 이용하여 외부 API에서 데이터를 발행하는 프로젝트를 만들어보자.

 

Project 구조

 

 

 

Client Templates - main.html

<!doctype html> 
<head> <title>pubsub2</title> </head> 
<body> 
  <form id="add"> 
    <input type="text" name="thumb" value="">
    <input type="text" name="link" value=""> 
    <input type="text" name="title" value="">
    <input type="text" name="snippet" value="">
    <input type="submit" value="Add"> 
  </form> 
  <form id="search"> 
    <input type="text" name="query" value="한국"> 
    <input type="submit" value="Search"> </form> 
  {{#if searching}} <p>Searching...</p> {{else}} {{#if books.count}} <hr> 
  <table> {{#each books}} {{> book}} {{/each}} </table> {{/if}}{{/if}} 
</body> 
<template name="book"> 
  <tr> 
    <td class="image"><img src="{{thumb}}"></td> 
    <td> <a href="{{link}}" target="_blank">{{title}}</a> <p>{{{snippet}}}</p> </td> 
  </tr>
</template>

Client - main.js

import {Random} from 'meteor/random';

Books = new Mongo.Collection('books');

Session.setDefault('searching', false);

Tracker.autorun(function() {
    if (Session.get('query')) {
        var searchHandle = Meteor.subscribe('booksSearch', Session.get('query'));
        Session.set('searching', !searchHandle.ready());
    }
});

Template.body.events({
    'submit form#search': function(event, template) {
        event.preventDefault();
        var query = template.$('input[name=query]').val();
        if (query)
            Session.set('query', query);
        }
});

Template.body.helpers({
    books: function() {
        //      query = Session.get('query');
        //      console.log("query: "+query)
        //      return Books.find({title: {$regex: ".*" + query + ".*"}});
        return Books.find();
    },
    searching: function() {
        return Session.get('searching');
    }
});

Books 컬렉션을 helper를 통해서 view에 뿌려준다.

Tracker.autorun() 안에 있는 내용은 Meteor의 시스템에서 Session과 같은 Reactive data가 변경되었을 때를 감지하여 변경이 될 경우에 다시 실행된다.

쿼리값이 변경되면 Meteor.subscribe 를 실행하여 구독해준다.

 

Server - main.js

import {Random} from 'meteor/random'

Books = new Mongo.Collection('books');

Meteor.publish('booksSearch', function(query) {
    var self = this;
    try {
        var response = HTTP.get('https://www.googleapis.com/books/v1/volumes', {
            params: {
                q: query
            }
        });
        _.each(response.data.items, function(item) {
            var doc = {
                thumb: item.volumeInfo.imageLinks.smallThumbnail,
                title: item.volumeInfo.title,
                link: item.volumeInfo.infoLink,
                snippet: item.searchInfo && item.searchInfo.textSnippet
            };
            self.added('books', Random.id(), doc);
        });

        var initializing = true;
        var handle = Books.find().observeChanges({
            added: function(id, fields) {
                if (!initializing) {
                    console.log("server - add: " + fields.title);
                    self.added('books', id, fields);
                }
            },
            removed: function(id) {
                console.log("server - remove: " + id);
            }
        });
        initializing = false;

        self.ready();
        this.onStop(() => handle.stop());
    } catch (error) {
        console.log(error);
    }
});

클라이언트에서 Meteor.subscribe 을 하면 서버에서는 Meteor.publish 부분이 실행된다.

이 때 보통 MongoDB에서 데이터를 가지고 올 경우에는 Books.find() 하면 해당 데이터가 구독되지만 실제로 코드 내부에서는 커서를 이용하여 .added() .ready()를 사용하는 작업을 한다.

 

self.added('books', Random.id(), doc);

 

publish 함수안에서만 호출되며 클라이언트에게 전달할 데이터를 추가한다. 

 

self.ready();

 

publish 함수안에서만 호출되며 모든 데이터가 서버 쪽으로 가져오고 다른 작업이 필요하지 않음을 의미합니다.

그외에 .changed(), .removed() 등등 함수가 존재한다.

참고: https://docs.meteor.com/api/pubsub.html#Meteor-publish

 

observeChanges는 컬렉션의 추가, 제거, 변경 등이 일어났을 경우 콜백으로 작동한다.

 

 

실행화면:

 

 

여기서 데이터를 insert하는 부분을 만들어보면

 

Client - main.js

Template.body.events({
    'submit form#search': function(event, template) {
        event.preventDefault();
        var query = template.$('input[name=query]').val();
        if (query)
            Session.set('query', query);
        }
    ,
    //이 부분을 추가
    'submit form#add': function(event, template) {
        event.preventDefault();
        var thumbVal = template.$('input[name=thumb]').val();
        var linkVal = template.$('input[name=link]').val();
        var titleVal = template.$('input[name=title]').val();
        var snippetVal = template.$('input[name=snippet]').val();
        console.log(thumbVal + ' ' + linkVal + ' ' + titleVal + ' ' + snippetVal)
        var books = {
            thumb: thumbVal,
            link: linkVal,
            title: titleVal,
            snippet: snippetVal
        };
        Books.insert(books);
    }
});

 

input 박스로 부터 데이터를 값을 받아 collection의 insert함수로 넘겨주면 서버와 클라이언트 DB에 모두 저장된다.

 

*서버DB에 넘겨주지 않고 클라이언트 Mini mongo에만 저장하는 방법

*Books._collections.insert(books);

_collections를 이용하여 저장할 수 있다.

 

참고자료:

http://kr.discovermeteor.com/chapters/publications-and-subscriptions/

http://webframeworks.kr/tutorials/core_meteor/4_pub_sub_in_ac

tion/

https://docs.meteor.com/api/pubsub.html

http://meteorcapture.com/publishing-data-from-an-external-api/

'웹 프로그래밍 > 미티어' 카테고리의 다른 글

Meteor의 특징, Meteor 설치 가이드  (0) 2017.05.25