블로그 이미지
Peter Note
Web & LLM FullStacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2013. 8. 5. 18:51 Data Visualization/D3.js

실습-1 에서 데이터를 어떻게 사용하는지까지 살펴보았다. 이번에는 데이터와 DOM을 바인딩하여 다양한 모양을 그려본다 



1. 준비

  - p tag 없는 html에서 시작

<!DOCTYPE html>

<html>

  <head>

  <script type="text/javascript" src="d3.min.js"></script>

  </head>

  <body>

  </body>

</html>

  - p tag의 __data__ 속성값 확인

var theData = [1,2,3];

var p = d3.select('body').selectAll('p').data(theData).enter().append('p').text(function(d) { return d;});

console.log(p);

  - 결과 : p element 객체가 array 형태로 return 된다 



2. SVG Shape Element 그리기

  - circle svg shape 그려보기 (참조)

  - circle 필수 attribute

    + cx : 원중심의 x좌표값

    + cy : 원중심의 y좌표값

    + r : 원 반지름

  - 모양 만드는 순서 

    + SVG의 크기 width, height를 정한다 : append('svg')

var circleRadii = [40, 20, 10];

var svgContainer = d3.select("body").append("svg").attr("width", 200).attr("height", 200);

    + SVG 안에 child element로 포함될 SVG shape element를 append(추가)한다

var circles = svgContainer.selectAll('circle'). data(circleRadii).enter().append('circle');

    circles 객체의 내역

   


    + 데이터를 DOM과 바인딩하여 원을 그린다

var circleAttributes = circles.attr('cx', 50).attr('cy', 50).attr('r', function(d){ return d; }).style('fill', 'blue');

      결과로 파란원만 나온다 

 

  - 값에 따라서 원의 색깔을 틀리게 해보자 

var circleAttributes = circles.attr('cx', 50).attr('cy', 50).attr('r', function(d){ return d; }).style('fill', function(d) {

  if(d == 40) { return 'green'; }

  else if(d == 20) { return 'yellow'; }

  else if(d == 10) { return 'orange'; }

  else { return 'blue';}

});

  - 결과 



3. SVG 좌표 기준 알기 

  - SVG는 일반적은 x-y축에 대한 기준을 사용하지 않는다 (참조)

  - SVG x=0, y=0 은 top left 에서 시작한다 

    x 값은 left -> right

    y 값은 top -> bottom 

    으로 증가한다 


  - 좌표 테스트

// 데이터

var spaceCircles = [30, 70, 110];

// svg 영역 확보

var svgContainer = d3.select("body").append("svg")

.attr("width", 200)

.attr("height", 200);

// svg shape virutal element 생성

var circles = svgContainer.selectAll("circle")

.data(spaceCircles)

.enter()

.append('circle');

// 데이터 바인딩통하여 원그리기 

var circleAttributes = circles

.attr("cx", function (d) { return d; })

.attr("cy", function (d) { return d; })

.attr("r", 20 );

 * 원의 색깔도 넣어보자 ^^



4. D3.js 의 자료구조 

  - 계속 Array를 사용해 왔다 : 배열의 값은 number, string, object, array, HTML Element, DOM element 가능 (참조

  - Array로 넘어 올때 index에 대한 접근도 가능하다 : i 값이 array의 index 값 

var theData = [ 1, 2, 3 ];

var p = d3.select("body").selectAll("p")

  .data(theData)

  .enter()

  .append("p")

  .text(function (d, i)

    return "i = " + i + " d = "+d; 

   });

  - 외부에서 데이터를 가져올 수도 있는데 이때는 반드시 배열로 와야한다 

> XMLHttpRequest

> text file

> JSON blob

> HTML document fragment

> XML document fragment

> comma-separated values (CSV) file

> tab-separated values (TSV) file

  - JSON 형태의 데이터는 반드시 key: value 모두 double quotes로 묶는다. 그리고 d3에 데이터전달시 JSON Array 이어야 함 

var seniorEngineer = {

 "name":"YoungSik",

 "drink":"not much",

 "number":"9578"

};

  - JSON Array로 활용하여 원을 표현해 보자(참조)

// 데이터 

var jsonCircles = [

  { 

   "x_axis": 30,

   "y_axis": 30,

   "radius": 20,

   "color" : "green"

  }, {

   "x_axis": 70,

   "y_axis": 70,

   "radius": 20,

   "color" : "purple"

  }, {

   "x_axis": 110,

   "y_axis": 100,

   "radius": 20,

   "color" : "red"

}];

// SVG 컨테이너 영역 확보 

var svgContainer = d3.select("body").append("svg")

                                    .attr("width", 200)

                                    .attr("height", 200);

// SVG Shape virtual element 생성 

var circles = svgContainer.selectAll("circle")

                          .data(jsonCircles)

                          .enter()

                          .append("circle");

  - console.log(circles); 를 수행하면 __data__ 속성이 JSON 객체로 할당된 것을 볼 수 있다


  - 3단계인 데이터를 DOM에 바인딩 해보자 

var circleAttributes = circles

  .attr('cx', function(d) { return d.x_axis; })

  .attr('cy', function(d) { return d.y_axis; })

  .attr('r', function(d) { return d.radius; })

  .style('fill', function(d) { return d.color; });



5. SVG 기본 모양 알아보기 

  - SVG Basic Shape에 대해서 알아본다 (참조)

  - Circle : cx, cy, r

  - Rectangle : x, y, width, height

// SVG 컨케이너 영역 확보

var svgContainer = d3.select("body").append("svg")

                                    .attr("width", 200)

                                    .attr("height", 200);


// SVG Shape 그리기

var rectangle = svgContainer.append("rect")

                            .attr("x", 10)

                            .attr("y", 10)

                            .attr("width", 50)

                            .attr("height", 100);


  - Ellipse : cx, cy, rx, ry

var svgContainer = d3.select("body").append("svg")

                                    .attr("width", 200)

                                    .attr("height", 200);


//Draw the Rectangle

var ellipse = svgContainer.append("ellipse")

                            .attr("cx", 100)

                            .attr("cy", 100)

                            .attr("rx", 50)

                            .attr("ry", 20);


  - Line : x1, y1, x2, y2

   + stroke-width : 넓이 지정

    + stroke : 색 지정 

var svgContainer = d3.select("body").append("svg")

                                    .attr("width", 200)

                                    .attr("height", 200);



var line = svgContainer.append("line")

                            .attr("x1", 5)

                            .attr("y1", 5)

                            .attr("x2", 50)

                            .attr("y2", 50);


line.attr('stroke-width', 2).attr('stroke', 'green');


  - polyline, polygon : stroke-width, stroke, points (참조)

posted by Peter Note
2013. 8. 5. 17:01 Data Visualization/D3.js

http://www.dashingd3js.com/ 사이트의 D3.js 익히기 실습을 하면서 요약 정리해 본다. 



1. 셋업

  - https://github.com/mbostock/d3 가서 오른쪽 하단의 "Download Zip" 에서 파일 다운로드 한다 

  - 디렉토리 생성하고 d3.min.js 파일을 해당 디렉토리에 copy하고 간단한 HTML 파일 하나 만들면 준비 끝 (hello.html)

<!DOCTYPE html>

<html>

  <head>

  <script type="text/javascript" src="d3.min.js"></script>

  </head>

  <body>

    <p>Hello!</p>

  </body>

</html>



2. DOM 조작하기 

  - DOM 을 조작하여 Circle을 그린다 (참조)

  - d3는 selector를 제공하여 tag, attribute, style 등을 제어할 수 있다 (jQuery처럼)

  - Chrome Dev Tools의 console을 통해서 조작한다 

  - append : child tag 추가, attr : attribute 추가

d3.select("body").append("svg").attr('width', 50).attr('height', 50).append('circle').attr('cx', 25).attr('cy', 25).attr('r', 25).style('fill', 'orange');

  - 결과 : 오랜지색 원을 동적으로 생성함 



3. Data와 DOM 바인딩하기

  - data 메소드를 이용한 DOM과 Data의 바인딩 (참조)

  - 코드 : data(<data>).enter() 한쌍의 구문을 사용 

var theData = [1,2,3];

var p = d3.select('body').selectAll('p').data(theData).enter().append('p').text('dowon');

  - selectAll에서 Data와 바인딩 될때 empty selection 일 경우 enter()를 통해서 바인딩이 가능토록 한다 

  - data 메소드는 theData에서 1 번째는 첫번째 p tag를 2 번째는 두번째 p tag와 맵핑된다 

  - virtual selection에는 enter, update, exit 가 있다 

    + enter : missing element 와 data binding

    + update : 기존 element 와 data binding

    + exit : 맨끝에것 제거 

  - 즉, enter를 하게 되면 virtual selection의 객체 레퍼런스가 return되어 append, attr, style등의 조작이 가능해 진다 


  - 그렇다면 데이터 1, 2, 3 의 숫자 값은 어디로 갔을까? 

    + __data__ 프러퍼티가 p tag 밑으로 추가되었고 해당 속성에 값이 할당되어 있다 

    + 이것을 Binding Data to DOM Element 라고 부른다 



4. 데이터를 엑세스하여 사용하기 

  - callback function을 등록한다 (참조)

var theData = [11,222,567];

var p = d3.select('body').selectAll('p').data(theData).enter().append('p').text(function(d) { return d;});

  - 의미 : variableName의 값으로 tag의 __data__ 속성값을 갖는다. functionName은 생략하여 anonymous function으로 등록 가능하다

1function functionName (variableName) {
2  return variableName;
3}

  -  결과


다음 실습은 실제 데이터를 가지고 다양한 모양을 그려본다


<참조>

  - DashingD3js.com

posted by Peter Note
2013. 8. 3. 17:52 MongoDB/MapReduce

10Gen에서 제공하는 Aggregation Framework에 대한 동영상 소개 예제를 실습해 본다 



1. 준비 

  - 10Gen 예제

  - http://media.mongodb.org/zips.json  데이터를 mongoimport 명령을 이용하여 넣기 

// zip.json 예제 mongoimport 

$ mongoimport --db bigdata --collection zipcodes --file zip.json

connected to: 127.0.0.1

Sat Aug  3 14:55:27.002 Progress: 1919717/2871006 66%

Sat Aug  3 14:55:27.002 19700 6566/second

Sat Aug  3 14:55:28.258 check 9 29470

Sat Aug  3 14:55:28.259 imported 29470 objects


// mongo shell

> use bigdata

switched to db bigdata

> show collections

system.indexes

zipcodes



2. 간단 수행

  - $group -> $match로 pipeline stream 처리

  - aggregate 메소드에 {} 객체를 넣고 콤마(,) 로 구분하면 왼쪽-> 오른쪽으로 pipeline 됨  

db.zipcodes.aggregate(

         { $group :

                         { _id : "$state",

                           totalPop : { $sum : "$pop" } } 

         },

         { $match : 

                         {totalPop : { $gte : 10*1000*1000 } }

         } );


SELECT state, SUM(pop) AS totalPop FROM zips GROUP BY state HAVING totalPop > (10*1000*1000)



3. 동영상 따라쟁이

  - 10Gen 동영상 예제


  - 샘플 수행 순서 : 일반 operator -find()같은- 와 aggregation framework operator 비교 수행 

 

  - $match == find와 같은 결과 그러나 다른 페러다임에서 처리된다는게 함정!

> db.zipcodes.aggregate({$match: {state:'NY', pop: {$gt:110000}}});

{

"result" : [

{

"city" : "BROOKLYN",

"loc" : [

-73.956985,

40.646694

],

"pop" : 111396,

"state" : "NY",

"_id" : "11226"

}

],

"ok" : 1

}


  - $match 후에 pipeline을 통하여 $sort 하기 : 단지 콤마(,)로 구분하면 된다 

> db.zipcodes.aggregate({$match: {state:'NY'}}, {$sort: {pop:-1}});


  - $match | $sort | $limit | $skip pipeline stream 처리 

> db.zipcodes.aggregate({$match: {state:'NY'}}, {$sort: {pop:-1}}, {$limit:5}, {$skip: 2});

{

"result" : [

{

"city" : "NEW YORK",

"loc" : [

-73.968312,

40.797466

],

"pop" : 100027,

"state" : "NY",

"_id" : "10025"

},

{

"city" : "JACKSON HEIGHTS",

"loc" : [

-73.878551,

40.740388

],

"pop" : 88241,

"state" : "NY",

"_id" : "11373"

},

{

"city" : "BROOKLYN",

"loc" : [

-73.914483,

40.662474

],

"pop" : 87079,

"state" : "NY",

"_id" : "11212"

}

],

"ok" : 1

}


  - 데이터에 $ 부호 사용하기 : 기존 document에는 population 필드가 존재하지 않는다 

> db.zipcodes.aggregate({$limit:1}, {$project: {city:1, state:1, pop:1, population:'$pop'}});

{

"result" : [

{

"city" : "ACMAR",

"pop" : 6055,

"state" : "AL",

"_id" : "35004",

"population" : 6055

}

],

"ok" : 1

}


$project가 하는 일은 무엇이 있을까?

- 필드 넣기 : Include fields from the original document.

- 계산된 필드 삽입 : Insert computed fields.

- 필드 이름 변경 : Rename fields.

- 서브도큐멘트에 대한 생성과 조작 : Create and populate fields that hold sub-documents.


  - 데이터에 $를 사용해 연산하여 결과를 얻기 

> db.zipcodes.aggregate({$limit:1}, {$project: {city:1, state:1, pop:1, population:'$pop', popSquared: {$multiply: ['$pop', '$pop']}} });

{

"result" : [

{

"city" : "ACMAR",

"pop" : 6055,

"state" : "AL",

"_id" : "35004",

"population" : 6055,

"popSquared" : 36663025

}

],

"ok" : 1

}

> 6055*6055

36663025


  - 기존 필드에 sub document 넣기  .' ' 사용한다 

> db.zipcodes.aggregate({$limit:1}, {$project: {city:1, state:1, population:'$pop', 'pop.Squared': {$multiply: ['$pop', '$pop']}} });

{

"result" : [

{

"city" : "ACMAR",

"pop" : {

"Squared" : 36663025

},

"state" : "AL",

"_id" : "35004",

"population" : 6055

}

],

"ok" : 1

}


  - pipeline 해보자  : $group -> $sort -> $limit 

> db.zipcodes.aggregate( {$group: {_id: '$state', pop: {$sum: '$pop'}}}, {$sort: {pop:-1}}, {$limit:3});

{

"result" : [

{

"_id" : "CA",

"pop" : 29760021

},

{

"_id" : "NY",

"pop" : 17990455

},

{

"_id" : "TX",

"pop" : 16986510

}

],

"ok" : 1

}


// 하나의 document마다 모든 city가 다 포함되어 결과 검출됨 (실습해 보삼^^)

> db.zipcodes.aggregate( {$group: {_id: '$state', pop: {$sum: '$pop'}, cities:{$addToSet: '$city'}}}, {$sort: {pop:-1}}, {$limit:3});


  - _id를 조합한 형태로 Pipeline 해보기 : $group -> $sort -> $limit 

> db.zipcodes.aggregate(

{$group: 

    {

        _id: {city: '$city', state: '$state'}, 

        pop: {$sum: '$pop'}, 

        avgPop: {$avg: '$pop'}

    }

},  

{$sort: {pop: -1}}, 

{$limit: 1}

)

// 결과 

{

"result" : [

{

"_id" : {

"city" : "CHICAGO",

"state" : "IL"

},

"pop" : 2452177,

"avgPop" : 52173.97872340425

}

],

"ok" : 1

}



<참조>

  - 예제 json 파일

zip.json

  - DZon의 Aggregation Framework 소개 기사

'MongoDB > MapReduce' 카테고리의 다른 글

[MongoDB] Aggregation Framework 이해하기  (0) 2013.08.03
[MongoDB] GridFS 사용하기  (0) 2013.02.23
[MongoDB] GridFS 개념잡기  (0) 2013.02.23
posted by Peter Note
2013. 8. 3. 16:08 MongoDB/MapReduce

MongoDB의 Aggregation 프레임워크에 대해서 알아보자. MongoDB의 Advance과정이라 말하고 싶다. MongoDB 전문가로 가고자 한다면 꼭 알아두어야 한다



1. Aggregation Framework

  - 10gen에서 이야기하는 집계프레임워크 개념

  - MongoDB의 Aggregation 목적은 Sharding 기반의 데이터에 대한 데이터 집계이다.

    



2. 개념 이해하기 

  - MongoDB v2.2 부터 나왔다

  - Shard를 통하여 BigData를 저장하고, Aggragation Framework을 통하여 BigData를 처리한다

  - Aggregation Framework의 2개의 중요 개념이 있다 : Pipelines, Expressions 

    + Pipelines : Unix의 pipe와 동일한다. mongodb pipeline 은 document를 stream화 한다. 또한 pipeline operators는 document의 stream을 처리한다. (마치 map-reducing과 같다)

NameDescription
$project

Reshapes a document stream. $project can rename, add, or remove fields as well as create computed values and sub-documents.  (참조Projection(π)은 관계 집합에서 원하지 않는 성분을 제거한다. 수학적인, 다른 dimension으로 mapping 한다는 것과 동일하다. Projection의 결과는 관계 집합이다)

$matchFilters the document stream, and only allows matching documents to pass into the next pipeline stage. $match uses standard MongoDB queries.
$limitRestricts the number of documents in an aggregation pipeline.
$skipSkips over a specified number of documents from the pipeline and returns the rest.
$unwind

Takes an array of documents and returns them as a stream of documents. (map=key:value 즉, map 만들기)

$groupGroups documents together for the purpose of calculating aggregate values based on a collection of documents.
$sortTakes all input documents and returns them in a stream of sorted documents.
$geoNearReturns an ordered stream of documents based on proximity to a geospatial point.

  ex) $project와 $unwind 되는 중간의 콤마(,) 가 pipeline되면서 stream방식으로 데이터가 처리되는 것이다 (OLAP의 dimension과 같음)

var p2 = db.runCommand(
{ aggregate : "article", pipeline : [
{ $project : {
author : 1,
tags : 1,
pageViews : 1
}},
{ $unwind : "$tags" }

]});


   ex) Aggregation과 SQL 맵핑관계 : sql은 dbms안에서 하는 것이고, mongodb는 sharding 기반에서 하는것이다 

  


    + Expressions : input document를 수행한 계산값을 기반으로 output document를 생산하는 것이다. 

NameDescription
$addToSetReturns an array of all the unique values for the selected field among for each document in that group.
$firstReturns the first value in a group.
$lastReturns the last value in a group.
$maxReturns the highest value in a group.
$minReturns the lowest value in a group.
$avgReturns an average of all the values in a group.
$pushReturns an array of all values for the selected field among for each document in that group.
$sumReturns the sum of all the values in a group.



4. 실습하기 

// orders 컬렉션을 다음을 저장한다  

$ mongod --dbpath /home/mongodb/aggregation


// orders의 도큐먼트를 2번 동일하게 save 한다 

$ mongo

> db.orders.save({

   cust_id: "abc123",

   ord_date: ISODate("2012-11-02T17:04:11.102Z"),

   status: 'A',

   price: 50,

   items: [ { sku: "xxx", qty: 25, price: 1 },

            { sku: "yyy", qty: 25, price: 1 } ]

 });


//////////////////////////
// Where절
> db.orders.aggregate( [
    { $group: { _id: null,
                count: { $sum: 1 } } }
 ] );

// 결과 
{ "result" : [ { "_id" : null, "count" : 2 } ], "ok" : 1 }   

// sql
SELECT COUNT(*) AS count
FROM orders

////////////////////////
// sub query
> db.orders.aggregate( [
    { $group: { _id: { cust_id: "$cust_id",
                       ord_date: "$ord_date" } } },
    { $group: { _id: null, count: { $sum: 1 } } }
 ] )

{ "result" : [ { "_id" : null, "count" : 1 } ], "ok" : 1 }

// sql
SELECT COUNT(*)
FROM (SELECT cust_id, ord_date
      FROM orders
      GROUP BY cust_id, ord_date) as DerivedTable


  - Simple Aggregation Frameworkcount, distinct, group function 예제

///////////////////////////////////////////////////
// count
// find()에 대한 count() 펑션의 호출일 뿐이다 
> db.orders.find().count()
// aggregation 서비스이다. 
db.orders.count()
// aggregation 서비스이기 때문에 operation이 들어간다 
db.orders.count({status:'A'})
 
///////////////////////////////////////////////////
// 샘플 save 
db.dowonDB.save({a:1})
db.dowonDB.save({a:1})
db.dowonDB.save({a:2})
db.dowonDB.save({a:3})

db.dowonDB.count()
4
db.dowonDB.count({a:1})
2

///////////////////////////////////////////////////
db.dowonDB.distinct('a')
[ 1, 2, 3 ]

또는

// runCommand 계정권한를 가지고 수행하는 shell 명령
db.runCommand({'distinct':'dowonDB', 'key':'a'})
{
"values" : [
1,
2,
3
],
"stats" : {
"n" : 4,
"nscanned" : 4,
"nscannedObjects" : 4,
"timems" : 0,
"cursor" : "BasicCursor"
},
"ok" : 1
}

///////////////////////////////////////////////////
// group
db.dowonDB.save({dept_id: 1, salary: 1})
db.dowonDB.save({dept_id: 1, salary: 2})
db.dowonDB.save({dept_id: 1, salary: 3})
db.dowonDB.save({dept_id: 2, salary: 10})
db.dowonDB.save({dept_id: 2, salary: 12})
db.dowonDB.save({dept_id: 2, salary: 16})
db.dowonDB.save({dept_id: 3, salary: 4})
db.dowonDB.save({dept_id: 3, salary: 1})

// map 값이 distinct를 의미 : key 값이 map이 된다 
// reduce는 코딩 즉 function이다. 즉, 비즈니스 펑션이다 
> db.dowonDB.group(
 { key: {'dept_id': true},
   reduce: function(obj, prev) { prev.sum += obj.salary },
   initial: {sum: 0}
 });

// 결과
[
{
"dept_id" : null,
"sum" : NaN
},
{
"dept_id" : 1,
"sum" : 6
},
{
"dept_id" : 2,
"sum" : 38
},
{
"dept_id" : 3,
"sum" : 5
}
]

또는 condition 조건절 줌 

> db.dowonDB.group( { key: {'dept_id': true},   reduce: function(obj, prev) { prev.sum += obj.salary },   initial: {sum: 0}, condition: {'dept_id': {$gt:2}  } });
[ { "dept_id" : 3, "sum" : 5 } ]

> db.dowonDB.group( { key: {'dept_id': true},   reduce: function(obj, prev) { prev.sum += obj.salary },   initial: {sum: 0}, condition: {'dept_id': {$gte:2}  } });
[ { "dept_id" : 2, "sum" : 38 }, { "dept_id" : 3, "sum" : 5 } ]

또는

> db.dowonDB.group( { key: {'dept_id': true},   reduce: function(obj, prev) { prev.sum += obj.salary; prev.cnt++ },   initial: {sum: 0, avg:0, cnt:0}, condition: {'dept_id': {$gte:2}  }, finalize: function(out){ out.avg = out.sum/out.cnt;}  });

[
{
"dept_id" : 2,
"sum" : 38,
"avg" : 12.666666666666666,
"cnt" : 3
},
{
"dept_id" : 3,
"sum" : 5,
"avg" : 2.5,
"cnt" : 2
}
]



5. 심화학습 

  - 동영상 강좌를 보자 

    


  - 상단의 Group만들기에서 map, reduce의 흐름도 

  - Sql처럼 sub query를 하지 않고 Reduce Function을 사용하여 코딩하면 된다

  - Framework Flow PDF : collectoin에 대해서 mapping 후 reducing 하여 result 결과를 만들어 낸다 

  - 데이터 Collection에서 key에 맞는 Map을 만들고, 비즈니스 로직에 맞게 Reduce 펑션을 만든 결과를 

    실시간으로 서비스한다

  - Intermediate-1 = unwind = map = key:value로 만들기

    Intemediate-2 = group = reduce



  - 이제 group으로 작업하지 말고 Pipeline Operation으로 하는 aggregate를 사용한다. 또는 mapreduce를 사용한다 

  - 결국 v2.2 에 오면 mapreduce를 사용한다 : 비즈니스적으론 BI 솔루션과 맵핑하여 UX로 표현한다 (Real-Time)

  - SNS에서 오는 실시간 데이터가 쌓여서 BigData가 되고 이를 저장하고 처리하는 것이 MongoDB로 웹앱기술과 찰떡 궁합!

  - 해당 작업은 disk가 아니라 memory cache해서 사용한다 (메뉴얼상으로)

 /////////////////////////////////////

// 형식 

> db.dowonDB.mapreduce(map, reduce, out)


// mongo에서 map 

> var map = function() { for(var key in this) {   emit(key,{count: 1}) } }

> var reduce = function(emits){ total=0; for(var i in emits) { total+=emits[i].count; } return {'count': total}; }

> var mr = db.runCommand({'mapreduce':'dowonDB', 'map':map, 'reduce':reduce, 'out':{'inline':1}});

// 결과 

> mr

{

"results" : [

{

"_id" : "_id",

"value" : {

"count" : NaN

}

},

{

"_id" : "a",

"value" : {

"count" : NaN

}

},

{

"_id" : "dept_id",

"value" : {

"count" : NaN

}

},

{

"_id" : "salary",

"value" : {

"count" : NaN

}

}

],

"timeMillis" : 14,

"counts" : {

"input" : 12,

"emit" : 32,

"reduce" : 4,

"output" : 4

},

"ok" : 1

}


또는 


//////////////////////////////////////////////////////////

// dowonDB2 컬렉션으로 새롭게 tags 컬럼 넣기 

> db.dowonDB2.save({_id: 1, tags:['dog', 'cat']})

> db.dowonDB2.save({_id: 2, tags:['cat']})

> db.dowonDB2.save({_id: 3, tags:['mouse', 'cat', 'dog']})

> db.dowonDB4.save({_id: 4, tags:[]})


// map과 reduce를 만듦 

> var map2 = function() { this.tags.forEach( function(z) { emit(z, {count: 1}); } ); }

> var reduce2 = function(key, values) { var total=0; for(var i=0; i < values.length; i++) { total += values[i].count; } return {count:total}; }


// mapReduce 호출

> var mr2 = db.dowonDB2.mapReduce( map2, reduce2, {out:{inline:1}} );

> mr2

{

"results" : [

{

"_id" : "cat",

"value" : {

"count" : 3

}

},

{

"_id" : "dog",

"value" : {

"count" : 2

}

},

{

"_id" : "mouse",

"value" : {

"count" : 1

}

}

],

"timeMillis" : 3,

"counts" : {

"input" : 3,

"emit" : 6,

"reduce" : 2,

"output" : 3

},

"ok" : 1,

}


  - MongoDB API 

db.runCommand(

    {

     mapReduce: <collection>,

     map: <function>,

     reduce: <function>,

     out: <output>,

     query: <document>,

     sort: <document>,

     limit: <number>,

     finalize: <function>,

     scope: <document>,

     jsMode: <boolean>,

     verbose: <boolean>

    }

)


  - MapReduce의 최종 목적은 무얼까?  SPA방식의 Web Application 서비스의 구현을 위한 것은 아닐까?

    10Gen에서 이야기하는 MongoDB in SPA (이용 : Node.js + Express.js + Mongoose.js + MongoDB)

   



<참조>

  - MongoDB Aggregation Framework Concept

  - MongoDB Aggragation Framework Examples

  - Collection Functions 목록

  - Aggregation Framework의 Pipeline 과 Expression 예제

  - count, distinct, group 예제

  - DataBase Projection 개념

'MongoDB > MapReduce' 카테고리의 다른 글

[MongoDB] Aggregation Framework 실습하기  (0) 2013.08.03
[MongoDB] GridFS 사용하기  (0) 2013.02.23
[MongoDB] GridFS 개념잡기  (0) 2013.02.23
posted by Peter Note
2013. 8. 2. 16:43 Data Visualization/D3.js

만들고 있는 솔루션이 기본 Highcharts를 사용하고 있다. 다른 Javascript Chart & Data Visualization Framwork에는 어떤 것들이 있는지 찾고 정리해 본다



1. Chart

  - Chart를 표현하는 다양한 Javascript가 존재한다

    + 11-javascript-toolkit-for-creating-charts-and-graphs/

  - jqWidgets : http://www.jqwidgets.com/

    + 다양한 차트와 컴포넌트를 제공한다 with jquery

  - jQuery Top 5 chart component

    + 5 Top Chart

  - Morris.js : http://www.oesmith.co.uk/morris.js/

    + 깔끔한 UI가 인상적이다

    + SVG 사용

  - xChart.jshttp://tenxer.github.io/xcharts/

    + Morris.js 와 유사하지만 좀 더 dynamic 차트 

    + SVG 사용

  - Envision.js : http://humblesoftware.com/envision/

    + 모바일에서 보여주기 좋다

    + 실시간 라인차트 존재

    + Canvas 사용

  - flotr2 : http://humblesoftware.com/flotr2/

    + 다양한 차트 종류 제공

    + CSS 디자인을 다시 손봐야 highchart 수준이 될듯하다 

    + Canvas 사용

  - Dygraphs : http://dygraphs.com/

    + 다양한 라인차트 제공

    + Canvas 사용

  - smoothie : http://smoothiecharts.org/

    + envision.js 와 유사함

    + 나름의 옵션을 가지고 있음. option ui builder 제공

    + 실시간 라인차트 제공

    + Canvas 사용

  - Rickshaw : http://code.shutterstock.com/rickshaw/

    + d3.js 프레임워크를 기반으로 chart를 제공

    + 예제가 안보임 (버그가 있는듯...)

    + SVG 사용

  - NVD3.js : http://nvd3.org/

    + rickshaw와 같은 d3.js 를 사용한 chart를 제공

    + SVG 사용

  - CanvasXpress : http://www.canvasxpress.org/

    + Canvas 사용

  - g.Raphaeljshttp://g.raphaeljs.com/

    + Raphael.js 프레임워크를 이용한 차트

    + SVG & VML 사용

  - jQuery Sparkline : http://omnipotent.net/jquery.sparkline/#s-about

    + Canvas 사용



2. Javascript Data Visualization Framework

  - Framework 선택시 가장 중요한 것은 Canvas 로 할 것인가? SVG로 할 것인가이다

    + Canvas or SVG 각각 특징

    + Canvas & SVG 비교

A Comparison of Canvas and SVG

Canvas

SVG
Pixel-based (canvas is essentially an image element with a drawing API) Object Model-based (SVG elements are similar to HTML elements)
Single HTML element similar to <img> in behavior Multiple graphical elements which become part of the Document Object Model (DOM)
Visual presentation created and modified programmatically through script Visual presentation created with markup and modified by CSS or programmatically through script
Event model/user interaction is coarse—at the canvas element only; interactions must be manually programmed from mouse coordinates Event model/user interaction is object-based at the level of primitive graphic elements—lines, rectangles, path s
API does not support accessibility; markup-based techniques must be used in addition to canvas SVG markup and object model directly supports accessibility




  - Raphael, Pager, Processing 기능 및 성능 비교 

    + 많은 양의 데이터를 실시간으로 표현하고자 한다면 Canvas,

       데이터량이 적고 분석이나 상호작용하는 차트를 원하면 SVG를 선택한다

    + Raphael.jshttp://raphaeljs.com/

       > SVG & VML 사용

       > NHN Chart 만들기 SlideShare

    + Pager.js : http://paperjs.org

       > Canvas 사용

       > Data Visualiztion 전용 프레임워크

       > 게임제작 또는 동적 차트를 만들기 좋음

       > 지돌스타님의 소개

    + Processingjs : http://processingjs.org/

       > Canvas 사용

       


  - D3.js : http://d3js.org/

    + SVG 사용

    + Data Driven Document = D3

    + D3로 구현된 다양한 Chart와 Visualization 사이트

  - DC.js : http://nickqizhu.github.io/dc.js/

    + D3.js 와 Square의 Crossfilter를 이용

    + Dimensional Charting Framework 

    + 차트끼리의 Interactive를 통하여 빠른 조회를 제공

    + 통계 조회화면 만드는데 적합

  - InfoVis : http://philogb.github.io/jit/index.html

    + Interactive Data Visualization Toolkit

    + Canvas 사용

  - Protovis : http://mbostock.github.io/protovis/

    + Graphical Visualization Toolkit

    + SVG 사용



3. Dashboard & UI Builder

  - 차트를 통하여 나오는 결과물은 대시보드!

    + Javascript Dashboard Framework

  - JointJS : Diagram을 그리는 Javascript framework

    + http://www.jointjs.com/

  - Draw.io : SVG를 이용한 draw builder

    + https://www.draw.io/

  - Tiggzi.com : https://appery.io/

    + 모바일 웹화면을 만드는 SaaS 기반 UI Builder

  - ZingChart : http://www.zingchart.com/builder/

    + Web 기반 Chart Builder

  - 01.org : https://01.org/rib/

    + Rapid Interface Builder

    + 모바일 웹화면 만들기 : https://01.org/rib/online/ (크롬만 가능)

  - Froont : http://froont.com/

    + 웹사이트를 만들어 주는 UI Builder



<참조>

  - 10-javascript-canvas-frameworks

  - 20-popular-javascript-charts-graphics-library

  - 13-useful-javascript-solutions-for-charts-and-graphs

  - 10-awesome-data-visualization-tools-for-the-web

  - 20 best tools data visualization

  - 지돌스타님의 Canvas framework 소개

  - D3 창시자 mbostock blog

  - D3로 차트 만드는 방법

'Data Visualization > D3.js' 카테고리의 다른 글

[D3.js] Bar Chart 만들기  (0) 2015.08.20
[D3.js] 배우는 방법  (1) 2013.08.06
[D3.js] DashingD3js.com 실습 - 4  (0) 2013.08.06
[D3.js] DashingD3js.com 실습 - 2  (0) 2013.08.05
[D3.js] DashingD3js.com 실습 - 1  (0) 2013.08.05
posted by Peter Note
2013. 7. 29. 13:40 Dev Environment/Mac, Dev Tools

맥북에서 한글/영문 전화하기 위해서 왼쪽 Command + Space를 사용한다. 윈도우에 익숙한 분이라면 Space오른쪽의 한글/영문 Key가 익숙할 것이고 맥북에서 오른쪽 Command를 통해 한글/영문 바꾸는 기능을 설정해 보자


1. keymap 프로그램 설치

   - https://pqrs.org/macosx/keyremap4macbook/ 여기가서 다운로드 설치 -> 자동 OS rebooting 된다

    


 

2. 환경 설정하기

  - 설치를 하고 나면 상단에 사각형의 아이콘이 생깁니다. 해당 아이콘의 ContextMenu에서 Preferences... 를 선택함

   


  - 하기 부분 Check하면 끝! : Command_R to Command_R ( + When you type Comman_R only, toggle IM) When you type Command_R only, send Command+Space (except virtual machine, RDC)


드디어 "오른쪽 Command" Key 하나만 눌러도 한/영 문자가 전환됩니다. 물론 기존의 왼쪽 Command+Space도 동작합니다.


<참조>

  - 맥 키를 내맘대로

posted by Peter Note
2013. 7. 27. 16:06 MongoDB/Prototyping

몽고디비에서 Shard 1개 ( = ReplicaSet 1개)를 구성하였다면 이제는 n개의 Shard를 구성하여 mongos를 통하여 연결해 본다




1. Shard n개 구성하기

  - Shard Server 1개에 mongod 1개만 만듦 (mongod n개 구성은 다음 블로깅에서)

  - db11, db22, db33 디렉토리를 미리 만들어 놓는다

/mongodb_2.4.5> mongod --shardsvr --dbpath /mongodb_2.4.5/db11 --port 10000
Sat Jul 27 15:15:40.854 [initandlisten] MongoDB starting : pid=71105 port=10000 dbpath=/mongodb_2.4.5/db11 64-bit host=nulpulum-mac-13-retina.local
Sat Jul 27 15:15:41.141 [initandlisten] command local.$cmd command: { create: "startup_log", size: 10485760, capped: true } ntoreturn:1 keyUpdates:0  reslen:37 271ms
Sat Jul 27 15:15:41.141 [websvr] admin web console waiting for connections on port 11000
Sat Jul 27 15:15:41.142 [initandlisten] waiting for connections on port 10000


/mongodb_2.4.5> mongod --shardsvr --dbpath /mongodb_2.4.5/db22 --port 20000
Sat Jul 27 15:16:38.842 [initandlisten] MongoDB starting : pid=71106 port=20000 dbpath=/mongodb_2.4.5/db22 64-bit host=nulpulum-mac-13-retina.local
Sat Jul 27 15:16:39.105 [websvr] admin web console waiting for connections on port 21000
Sat Jul 27 15:16:39.105 [initandlisten] waiting for connections on port 20000


/mongodb_2.4.5> mongod --shardsvr --dbpath /mongodb_2.4.5/db33 --port 30000
Sat Jul 27 15:18:04.778 [initandlisten] MongoDB starting : pid=71120 port=30000 dbpath=/mongodb_2.4.5/db33 64-bit host=nulpulum-mac-13-retina.local
Sat Jul 27 15:18:05.031 [websvr] admin web console waiting for connections on port 31000
Sat Jul 27 15:18:05.031 [initandlisten] waiting for connections on port 30000



2. Config 환경 구성하기

   - config1, config2, config3 디렉토리를 미리 만들어 놓는다

/mongodb_2.4.5> mongod --help
.. 중략 ..
Master/slave options (old; use replica sets instead):
  --master              master mode
  --slave               slave mode
  --source arg          when slave: specify master as <server:port>
  --only arg            when slave: specify a single database to replicate
  --slavedelay arg      specify delay (in seconds) to be used when applying
                        master ops to slave
  --autoresync          automatically resync if slave data is stale

Replica set options:
  --replSet arg           arg is <setname>[/<optionalseedhostlist>]
  --replIndexPrefetch arg specify index prefetching behavior (if secondary)
                          [none|_id_only|all]

Sharding options:
  --configsvr           declare this is a config db of a cluster; default port
                        27019; default dir /data/configdb
  --shardsvr            declare this is a shard db of a cluster; default port
                        27018


  - config 서버 기동하기

/mongodb_2.4.5> mongod --configsvr --dbpath /mongodb_2.4.5/config1 --port 40000
Sat Jul 27 15:22:12.404 [initandlisten] MongoDB starting : pid=71141 port=40000 dbpath=/mongodb_2.4.5/config1 master=1 64-bit host=nulpulum-mac-13-retina.local
Sat Jul 27 15:22:12.544 [initandlisten] creating replication oplog of size: 5MB...
Sat Jul 27 15:22:12.547 [initandlisten] ******
Sat Jul 27 15:22:12.547 [websvr] admin web console waiting for connections on port 41000
Sat Jul 27 15:22:12.547 [initandlisten] waiting for connections on port 40000



3. Mongos로 Shard 제어하기

  - 명령어 : mongos <config server>

/mongodb_2.4.5> mongos --help
.. 중략 ..
Sharding options:
  --configdb arg      1 or 3 comma separated config servers
  --localThreshold arg 

                              ping time (in ms) for a node to be considered local (default 15ms)
  --test                   just run unit tests
  --upgrade             upgrade meta data version
  --chunkSize arg     maximum amount of data per chunk (기본 : 64kbytes)
  --ipv6                   enable IPv6 support (disabled by default)
  --jsonp                 allow JSONP access via http (has security implications)
  --noscripting          disable scripting engine


  - mongos 연결하기

/mongodb_2.4.5> mongos --configdb localhost:40000 --chunkSize 1 --port 50000
Sat Jul 27 15:31:45.926 [mongosMain] options: { chunkSize: 1, configdb: "localhost:40000", port: 50000 }
Sat Jul 27 15:31:45.929 [Balancer] about to contact config servers and shards
Sat Jul 27 15:31:45.929 [websvr] admin web console waiting for connections on port 51000
Sat Jul 27 15:31:45.929 [Balancer] config servers and shards contacted successfully
Sat Jul 27 15:31:45.929 [mongosMain] waiting for connections on port 50000
Sat Jul 27 15:31:45.932 [Balancer] distributed lock 'balancer/nulpulum-mac-13-retina.local:50000:1374906705:16807' acquired, ts : 51f36951133d3c7f4fe7b076
Sat Jul 27 15:31:45.932 [Balancer] distributed lock 'balancer/nulpulum-mac-13-retina.local:50000:1374906705:16807' unlocked.



4. REPL로 데이터 제어하

  - mongo로 들어가면 mongos 프롬프트가 나온다

mongodb_2.4.5> mongo localhost:50000
MongoDB shell version: 2.4.5
connecting to: localhost:50000/test
mongos>

mongos> show dbs
admin    (empty)
config    0.046875GB


  - admin db로 들어가서 config server에 shard환경을 구성한다

mongos> show dbs
admin    (empty)
config    0.046875GB
mongos> use admin
switched to db admin
mongos> show collections
mongos> db
admin
mongos> db.runCommand({ addShard: 'localhost:10000' });
{ "shardAdded" : "shard0000", "ok" : 1 }
mongos> db.runCommand({ addShard: 'localhost:20000' });
{ "shardAdded" : "shard0001", "ok" : 1 }
mongos> db.runCommand({ addShard: 'localhost:30000' });
{ "shardAdded" : "shard0002", "ok" : 1 }


  - 동적으로 mongod를 Shard에 포함시키기

/////////////// --shardsvr 옵션없이 mongod를 띄운다

/mongodb_2.4.5> mongod --dbpath /mongodb_2.4.5/db111 --port 60000
Sat Jul 27 15:43:48.510 [initandlisten] MongoDB starting : pid=71193 port=60000 dbpath=/mongodb_2.4.5/db111 64-bit host=nulpulum-mac-13-retina.local
Sat Jul 27 15:43:48.542 [websvr] admin web console waiting for connections on port 61000
Sat Jul 27 15:43:48.542 [initandlisten] waiting for connections on port 60000
Sat Jul 27 15:43:57.418 [initandlisten] connection accepted from 127.0.0.1:51723 #1 (1 connection now open)


/////////////// runCommand를 수행한다

mongos> show collections
mongos> db.runCommand({ addShard: 'localhost:60000' });
{ "shardAdded" : "shard0003", "ok" : 1 }


/////////////// mongos 의 system out 출력값
Sat Jul 27 15:43:57.419 [conn1] going to add shard: { _id: "shard0003", host: "localhost:60000" }



5. 데이터 Sharding 하기

  - mongos를 통하여 데이터를 Sharding하여 나누어서 넣는 방법 : 한곳으로 데이터가 들어갈때 트래픽이 감당하기 힘들때 다른 샤드로 데이터를 보낸다 (10gen)

mongos> use dowonDB
switched to db dowonDB
mongos> db
dowonDB
mongos> db.person.save({age:1, name:'youngsik', address:'seoul'});
mongos> db.person.find();
{ "_id" : ObjectId("51f36cfb065189f0c02620d4"), "age" : 1, "name" : "youngsik", "address" : "seoul" }
mongos> use admin
switched to db admin
mongos> db
admin
mongos> db.runCommand({ enablesharding: 'dowonDB' })
{ "ok" : 1 }
mongos> db.runCommand({ shardcollection: 'dowonDB.person', key:{_id:1} })
{ "collectionsharded" : "dowonDB.person", "ok" : 1 }


  - 데이터 넣어서 샤드 점검하기 : 여러 mongod 서버로 데이터가 나뉘어서 들어갈 것이다. 즉, mongos가 로드발샌싱하여 데이터를 라우팅하여 줄 것이다. (5백만건 넣기)

mongos> use dowonDB
switched to db dowonDB
mongos> db
dowonDB
mongos> for(var i=0; i < 5000000 ; i++) { db.person.save({ age: i, name:i+9, address: i+1000}); };

mongos> db.person.find().size();
5000001

mongos> db.person.find().skip(1000000).limit(10);
{ "_id" : ObjectId("51f36fc4065189f0c037d1d1"), "age" : 1159420, "name" : 1159429, "address" : 1160420 }
{ "_id" : ObjectId("51f36f8d065189f0c02b7e4c"), "age" : 351607, "name" : 351616, "address" : 352607 }
{ "_id" : ObjectId("51f37031065189f0c04dc534"), "age" : 2597983, "name" : 2597992, "address" : 2598983 }
{ "_id" : ObjectId("51f36fab065189f0c032416e"), "age" : 794777, "name" : 794786, "address" : 795777 }
{ "_id" : ObjectId("51f36fc4065189f0c037d1d2"), "age" : 1159421, "name" : 1159430, "address" : 1160421 }
{ "_id" : ObjectId("51f36f8d065189f0c02b7e4d"), "age" : 351608, "name" : 351617, "address" : 352608 }
{ "_id" : ObjectId("51f37031065189f0c04dc535"), "age" : 2597984, "name" : 2597993, "address" : 2598984 }
{ "_id" : ObjectId("51f36fab065189f0c032416f"), "age" : 794778, "name" : 794787, "address" : 795778 }
{ "_id" : ObjectId("51f36fc4065189f0c037d1d3"), "age" : 1159422, "name" : 1159431, "address" : 1160422 }
{ "_id" : ObjectId("51f36f8d065189f0c02b7e4e"), "age" : 351609, "name" : 351618, "address" : 352609 }


  - db11, db22, db33, db111 각 디렉토리에 1Gbytes 가량의 데이터가 쌓여진다.



<참조>

  - 10Gen ReplicaSet 프리젠테이션

posted by Peter Note
2013. 7. 27. 14:56 MongoDB/Prototyping

몽고디비에서 Replica Set 환경을 구성해 본다. ReplicaSet을 하나의 Shard로 만들어서 여러개의 Shard가 구성되면 하기와 같이 routing은 mongos가 해준다




1. Replica Set 만들기

  - 옵션 : --replSet 

  - 디렉토리 만들어 놓기 : db1, db2, db3을 미리 만들어 놓는다

mongodb_2.4.5> mongod --replSet dowonSet --port  20000  -dbpath /mongodb_2.4.5/db1
Sat Jul 27 14:11:58.007 [initandlisten] MongoDB starting : pid=71010 port=20000 dbpath=/mongodb_2.4.5/db1 64-bit host=nulpulum-mac-13-retina.local
Sat Jul 27 14:11:58.299 [websvr] admin web console waiting for connections on port 21000
Sat Jul 27 14:11:58.300 [initandlisten] waiting for connections on port 20000
Sat Jul 27 14:12:08.302 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG)


mongodb_2.4.5> mongod --replSet dowonSet --port  30000  -dbpath /mongodb_2.4.5/db2
Sat Jul 27 14:32:08.934 [initandlisten] MongoDB starting : pid=71062 port=30000 dbpath=/mongodb_2.4.5/db2 64-bit host=nulpulum-mac-13-retina.local


/mongodb_2.4.5> mongod --replSet dowonSet --port  40000  -dbpath /mongodb_2.4.5/db3
Sat Jul 27 14:32:16.317 [initandlisten] MongoDB starting : pid=71063 port=40000 dbpath=/mongodb_2.4.5/db3 64-bit host=nulpulum-mac-13-retina.local



2. Replica Set 환경설정하기

  - mongo REPL 로 연결

  - config 환경 구성

/mongodb_2.4.5> mongo localhost:20000
MongoDB shell version: 2.4.5
connecting to: localhost:20000/test
> var config={_id:'dowonSet', members:[{_id:0, host:'localhost:20000'}, {_id:1, host:'localhost:30000'}, {_id:2, host:'localhost:40000'}] };


///////////// Replica set help 보기

> rs.help();
    rs.status()                         { replSetGetStatus : 1 } checks repl set status
    rs.initiate()                         { replSetInitiate : null } initiates set with default settings
    rs.initiate(cfg)                   { replSetInitiate : cfg } initiates set with configuration cfg
    rs.conf()                           get the current configuration object from local.system.replset
    rs.reconfig(cfg)                  updates the configuration of a running replica set with cfg (disconnects)
    rs.add(hostportstr)             add a new member to the set with default attributes (disconnects)
    rs.add(membercfgobj)        add a new member to the set with extra attributes (disconnects)
    rs.addArb(hostportstr)        add a new member which is arbiterOnly:true (disconnects)
    rs.stepDown([secs])          step down as primary (momentarily) (disconnects)
    rs.syncFrom(hostportstr)    make a secondary to sync from the given member
    rs.freeze(secs)                  make a node ineligible to become primary for the time specified
    rs.remove(hostportstr)       remove a host from the replica set (disconnects)
    rs.slaveOk()                      shorthand for db.getMongo().setSlaveOk()

    db.isMaster()                     check who is primary
    db.printReplicationInfo()       check oplog size and time range

    reconfiguration helpers disconnect from the database so the shell will display
    an error, even if the command succeeds.
    see also http://<mongod_host>:28017/_replSet for additional diagnostic info


///////////// 환경 적용하기

> rs.initiate(config);
{
    "info" : "Config now saved locally.  Should come online in about a minute.",
    "ok" : 1
}


///////////// Enter를 치면 프롬프트가 변경되어 나온다

dowonSet:PRIMARY>
dowonSet:PRIMARY> show dbs
local    0.328125GB
dowonSet:PRIMARY> use dowonDB
switched to db dowonDB
dowonSet:PRIMARY> db
dowonDB
dowonSet:PRIMARY>



3. REPL 조작하기

  - PRIMARY에서 데이터 조작하기

dowonSet:PRIMARY> db.person.save({age:23, name:'youngsik', title:'hi'});
dowonSet:PRIMARY> show collections
person
system.indexes
dowonSet:PRIMARY> db.person.find();
{ "_id" : ObjectId("51f35c76076489dd83ccb46d"), "age" : 23, "name" : "youngsik", "title" : "hi" }


  - SECONDARY 들어가 보기 : PRIMARY가 다운되면 show collections에서 에러가 발생하지 않고 자신이 PRIMARY로 된다

    PRIMARY 1개 + SECONDARY 2개 + 여분 n개

/mongodb_2.4.5> mongo localhost:30000
MongoDB shell version: 2.4.5
connecting to: localhost:30000/test
dowonSet:SECONDARY> show dbs
dowonDB    0.203125GB
local    0.328125GB
test    (empty)
dowonSet:SECONDARY> use dowonDB
switched to db dowonDB
dowonSet:SECONDARY> db
dowonDB
dowonSet:SECONDARY> show collections
Sat Jul 27 14:42:38.244 JavaScript execution failed: error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:L128

///////////// 20000 번 포트의 mongod를 강제로 다운시켰을 때 : 40000 포트의 mongod가 PRIMARY가 된다

/mongodb_2.4.5> mongo localhost:40000
MongoDB shell version: 2.4.5
connecting to: localhost:40000/test
dowonSet:PRIMARY>
dowonSet:PRIMARY> use dowonDB
switched to db dowonDB
dowonSet:PRIMARY> show collections
person
system.indexes
dowonSet:PRIMARY> db.person.find();
{ "_id" : ObjectId("51f35c76076489dd83ccb46d"), "age" : 23, "name" : "youngsik", "title" : "hi" }


  - SECONDARY로 들어가서 show collections가 안될 경우 rs.slaveOk() 명령수행

/mongodb_2.4.5> mongo localhost:30000
MongoDB shell version: 2.4.5
connecting to: localhost:30000/test
dowonSet:SECONDARY>
dowonSet:SECONDARY> show dbs
dowonDB    0.203125GB
local    0.328125GB
test    (empty)
dowonSet:SECONDARY> use dowonDB
switched to db dowonDB
dowonSet:SECONDARY> db
dowonDB
dowonSet:SECONDARY> show collections
Sat Jul 27 14:48:38.663 JavaScript execution failed: error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:L128
dowonSet:SECONDARY> rs.slaveOk();
dowonSet:SECONDARY> show collections
person
system.indexes
dowonSet:SECONDARY> db.person.find();
{ "_id" : ObjectId("51f35c76076489dd83ccb46d"), "age" : 23, "name" : "youngsik", "title" : "hi" }


현재까지 Shard 1개를 만들었다. (구현되지 않는 것은 거짓말이다)



<참조>

  - 10gen Sharding 메뉴얼

posted by Peter Note
2013. 7. 27. 12:28 MongoDB/Prototyping

몽고디비의 마스터/슬레이브 환경을 만들어서 fault tolerance 시스템을 구성해 본다



1. 마스터 만들기

  - 옵션 : --master

mongodb_2.4.5> mongod --dbpath /mongodb_2.4.5/master --master --port 38000
Sat Jul 27 11:50:39.279 [initandlisten] MongoDB starting : pid=70914 port=38000 dbpath=mongodb_2.4.5/master master=1 64-bit host=nulpulum-mac-13-retina.local
Sat Jul 27 11:50:39.279 [initandlisten] db version v2.4.5
.. 중략 ..
Sat Jul 27 11:50:39.347 [websvr] admin web console waiting for connections on port 39000
Sat Jul 27 11:50:39.347 [initandlisten] waiting for connections on port 38000
Sat Jul 27 11:51:47.344 [initandlisten] connection accepted from 127.0.0.1:63461 #1 (1 connection now open)


mongodb_2.4.5> mongo --port 38000
MongoDB shell version: 2.4.5
connecting to: 127.0.0.1:38000/test
> show dbs
local    0.328125GB

> db.printReplicationInfo()
configured oplog size:   192MB
log length start to end: 317secs (0.09hrs)
oplog first event time:  Sat Jul 27 2013 11:50:16 GMT+0900 (KST)
oplog last event time:   Sat Jul 27 2013 11:55:33 GMT+0900 (KST)
now:                     Sat Jul 27 2013 11:55:36 GMT+0900 (KST)

> db.printSlaveReplicationInfo()
local.sources is empty; is this db a --slave?
> db.printShardingStatus()
printShardingStatus: this db does not have sharding enabled. be sure you are connecting to a mongos from the shell and not to a mongod.



2. slave 만들기

  - 옵션 : --slave  --source <master 위치>

mongodb_2.4.5> mongod --dbpath /mongodb_2.4.5/slave --slave --port 48000 --source localhost:38000
Sat Jul 27 12:04:55.853 [initandlisten] MongoDB starting : pid=70927 port=48000 dbpath=mongodb_2.4.5/slave slave=1 64-bit host=nulpulum-mac-13-retina.local
Sat Jul 27 12:04:55.853 [initandlisten] options: { dbpath: "/mongodb_2.4.5/slave", port: 48000, slave: true, source: "localhost:38000" }
Sat Jul 27 12:04:56.891 [replslave] build index done.  scanned 0 total records. 0 secs


  - master의 내역확인: slave하나가 연결되었다

Sat Jul 27 11:51:47.344 [initandlisten] connection accepted from 127.0.0.1:63461 #1 (1 connection now open)
Sat Jul 27 12:04:56.889 [initandlisten] connection accepted from 127.0.0.1:63547 #2 (2 connections now open)
Sat Jul 27 12:04:57.896 [slaveTracking] build index local.slaves { _id: 1 }
Sat Jul 27 12:04:57.897 [slaveTracking] build index done.  scanned 0 total records. 0 secs


  - slave 하나더 만들기

mongodb_2.4.5> mongod --dbpath /mongodb_2.4.5/slave2 --slave --port 58000 --source localhost:38000
Sat Jul 27 12:08:53.817 [initandlisten] MongoDB starting : pid=70932 port=58000 dbpath=mongodb_2.4.5/slave2 slave=1 64-bit host=nulpulum-mac-13-retina.local
Sat Jul 27 12:08:53.818 [initandlisten] options: { dbpath: "/mongodb_2.4.5/slave2", port: 58000, slave: true, source: "localhost:38000" }
Sat Jul 27 12:08:55.069 [replslave] build index local.me { _id: 1 }
Sat Jul 27 12:08:55.070 [replslave] build index done.  scanned 0 total records. 0 secs



3. REPL로 작업하고 확인하기

  - 연결 : mongo <주소:port>

////////////////// slave 1번

mongodb_2.4.5> mongo  localhost:48000
MongoDB shell version: 2.4.5
connecting to: localhost:48000/test
> db.printSlaveReplicationInfo()
source:   localhost:38000
     syncedTo: Sat Jul 27 2013 12:09:53 GMT+0900 (KST)
         = 74 secs ago (0.02hrs)
> ^C
bye

////////////////// slave 2번
mongodb_2.4.5> mongo  localhost:58000
MongoDB shell version: 2.4.5
connecting to: localhost:58000/test
> db.printSlaveReplicationInfo()
source:   localhost:38000
     syncedTo: Sat Jul 27 2013 12:08:53 GMT+0900 (KST)
         = 144 secs ago (0.04hrs)
> ^C
bye

////////////////// master
mongodb_2.4.5> mongo  localhost:38000
MongoDB shell version: 2.4.5
connecting to: localhost:38000/test
> db.printSlaveReplicationInfo()
local.sources is empty; is this db a --slave?


  - master에 데이터 넣고 master에서 save한것이 slave로 복제되는지 확인하기

////////////////// master

> use dowon
switched to db dowon
> db.youngsik.save({name:'dowon', age:22});
> db.youngsik.find();
{ "_id" : ObjectId("51f33a81dbed34cf65d102d0"), "name" : "dowon", "age" : 22 }
> show dbs
config    (empty)
dowon    0.203125GB
local    0.328125GB
> ^C
bye

////////////////// slave 1번
mongodb_2.4.5> mongo  localhost:48000
MongoDB shell version: 2.4.5
connecting to: localhost:48000/test
> show dbs
dowon    0.203125GB
local    0.078125GB
> use dowon
switched to db dowon
> show collections
system.indexes
youngsik
> db.youngsik.find();
{ "_id" : ObjectId("51f33a81dbed34cf65d102d0"), "name" : "dowon", "age" : 22 }
>

////////////////// slave 2번

mongodb_2.4.5> mongo  localhost:58000
MongoDB shell version: 2.4.5
connecting to: localhost:58000/test
> use dowon
switched to db dowon
> show collections
system.indexes
youngsik
> db.youngsik.find();
{ "_id" : ObjectId("51f33a81dbed34cf65d102d0"), "name" : "dowon", "age" : 22 }


  - 파일 시스템 확인하기 : master, slave, slave2

mongodb_2.4.5/slave2>

-rwxr-xr-x   1 nulpulum  staff          6  7 27 12:08 mongod.lock
drwxr-xr-x   4 nulpulum  staff        136  7 27 12:12 journal
-rw-------   1 nulpulum  staff  134217728  7 27 12:12 dowon.1
drwxr-xr-x   2 nulpulum  staff         68  7 27 12:12 _tmp
-rw-------   1 nulpulum  staff   16777216  7 27 12:12 local.ns
-rw-------   1 nulpulum  staff   16777216  7 27 12:12 dowon.ns
-rw-------   1 nulpulum  staff   67108864  7 27 12:12 dowon.0
-rw-------   1 nulpulum  staff   67108864  7 27 12:21 local.0

mongodb_2.4.5/slave>
-rwxr-xr-x   1 nulpulum  staff          6  7 27 12:04 mongod.lock
drwxr-xr-x   4 nulpulum  staff        136  7 27 12:12 journal
-rw-------   1 nulpulum  staff  134217728  7 27 12:12 dowon.1
drwxr-xr-x   2 nulpulum  staff         68  7 27 12:12 _tmp
-rw-------   1 nulpulum  staff   16777216  7 27 12:12 local.ns
-rw-------   1 nulpulum  staff   16777216  7 27 12:13 dowon.ns
-rw-------   1 nulpulum  staff   67108864  7 27 12:13 dowon.0
-rw-------   1 nulpulum  staff   67108864  7 27 12:23 local.0


mongodb_2.4.5/master>
-rwxr-xr-x   1 nulpulum  staff          6  7 27 11:50 mongod.lock
drwxr-xr-x   4 nulpulum  staff        136  7 27 11:51 journal
-rw-------   1 nulpulum  staff   67108864  7 27 12:05 local.0
-rw-------   1 nulpulum  staff  134217728  7 27 12:12 dowon.1
drwxr-xr-x   2 nulpulum  staff         68  7 27 12:12 _tmp
-rw-------   1 nulpulum  staff   16777216  7 27 12:12 dowon.ns
-rw-------   1 nulpulum  staff   67108864  7 27 12:12 dowon.0
-rw-------   1 nulpulum  staff   16777216  7 27 12:22 local.ns
-rw-------   1 nulpulum  staff  268435456  7 27 12:22 local.1



<참조>

  - 10Gen Master/Slave 메뉴얼

posted by Peter Note
2013. 7. 27. 11:18 MongoDB/Prototyping

몽고디비에서 인덱스를 만들고 사용하는 간단한 방법에 대해 실습해 본다.


1. 인덱스 만들기

  - <collection>.ensureIndex({key:1 or -1})   예) db.things.ensureIndex({age:1});

  - 1 (양수) : ascending,  -1 (음수) : descending

> use indextest
switched to db indextest
> db.things.save({age:12, name:'dowon', title:'hi'});
> db.things.save({age:22, name:'dowon2', title:'hi2'});
> db.things.ensureIndex({age:1});
> db.system.indexes.find();
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "indextest.things", "name" : "_id_" }
{ "v" : 1, "key" : { "age" : 1 }, "ns" : "indextest.things", "name" : "age_1" }



2. 인덱스 삭제하기

  - <collection>.dropIndexes({key:1 or -1})  예) db.things.dropIndexes({age:1});

> db.things.dropIndexes({age:1});
{
    "nIndexesWas" : 3,
    "msg" : "non-_id indexes dropped for collection",
    "ok" : 1
}
> db.system.indexes.find();
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "indextest.things", "name" : "_id_" }



3. 인덱스 종류

  - 복합 인덱스 (Compound Key Index) : 여러개의 key를 기반으로 인데스 생성가능

     예) db.things.ensureIndex({age:1, name:-1});

  - 희소 인덱스 (Sparse Index) : 색인된 필드만 인덱스 한다

     예) db.things.ensureIndex({title:1}, {sparse:true}); 기본은 false

  - Unique 인덱스 : 색인된 키에 대해 이미 있거나 중복된 것은 insert되지 않는다

     예) db.things.ensureIndex({name:1}, {unique: true});

  * 하단 참조 Link



<참조>

  - 10Gen의 인덱스 한글 버전

posted by Peter Note
2013. 7. 20. 17:45 MongoDB/Concept

몽고디비 설치는 구글링을 통하여 다양한 환경에서 설치하는 블로그가 많이 있으니 별도로 작성하진 않는다. 수행하는 방법을 알아보자. 두번째 MongoDB 강의를 들으면서 인지하지 못했던 것을 알게되었고, 다시 글을 리팩토링하였다. (컴퓨터 언어도 커뮤니케이션 수단, 한글/영등도 커뮤니케이션 수단! 모두 리팩토링과 반복학습이 필요하다.) 


1. MongoDB 시작하기 

[mongodb@localhost ~]$ ll

total 30536

//////////////////////////////////////////////////////////

// db01, db02, db03 디렉토리를 만든다

drwxrwxr-x. 2 mongodb mongodb     4096 Jan 18 21:29 db01

drwxrwxr-x. 2 mongodb mongodb     4096 Jan 18 21:29 db02

drwxrwxr-x. 2 mongodb mongodb     4096 Jan 18 21:29 db03

drwx------. 8 mongodb mongodb     4096 Jan 18 21:29 .


//////////////////////////////////////////////////////////

// mongod를 시작한다. 시작시 특정 dbpath를 full로 지정한다 

[mongodb@localhost ~]$ ./mongod --dbpath /home/mongodb/db01

Fri Jan 18 21:36:13 

Fri Jan 18 21:36:13 warning: 32-bit servers don't have journaling enabled by default. Please use --journal if you want durability.

Fri Jan 18 21:36:13 

Fri Jan 18 21:36:13 [initandlisten] MongoDB starting : pid=7402 port=27017 dbpath=/home/mongodb/db01 32-bit host=localhost.localdomain

Fri Jan 18 21:36:13 [initandlisten] options: { dbpath: "/home/mongodb/db01" }

Fri Jan 18 21:36:13 [initandlisten] waiting for connections on port 27017  // connection 연결 맺는 포트

Fri Jan 18 21:36:13 [websvr] admin web console waiting for connections on port 28017  // 브라우져 관리 화면



2. 새로운 창에서 RELP Prompt 수행하기 

  - REPL = Repeat Evalution Print Loop = 프린트 가능문자로 계속 수행

  - SpiderMonkey라는 JavaScript Engine을 사용한다. SpiderMonkey는 C로 만든 Gecko의 JavaScript 엔진이다 (최신버전은 V8로 변경)

[mongodb@localhost ~]$ ./mongo

MongoDB shell version: 2.2.2

connecting to: test

Welcome to the MongoDB shell.



3. 명령어 수행전 JavaScript의 Stream 이해하기 

  - Server side event = event stream = node.js = functional

    + Functional Operation ()  ==> Task Operation : stream+sequence = Task + Task = activity (Transactional)

    + activity + activity 들의 집합체 = workflow 라고 한다 

    + 즉, Task가 모여서 Activity가 되고 Activity가 모여서 Workflow가 된다 

    + Javascript Object {} ==> {key:value} 로 표현한다. 이것을 functional operation ({}) 로 한다. 

      이렇게 하면 Stream Service가 될 수 있게 한다. 

  - 괄호안의 {} 를 Atrribute라고 한다 ({}, {}, {}) = One Task가 된다 

  - {} = Anonymous Object = Closure Object = Stream Object 가 될 수 있다

  - 보다 자세한 Stream 이해는 Substack의 Stream-Handbook 보자



4. CRUD를 위한 Operator 명령어들 

  - 명령어는 javascript 코딩으로 이루어진다

  - show dbs 또는 show collections 

  - use : db open과 같다 

  - 명령어가 mysql과 유사하다 

////////////////////////////////

// 디비의 상태 정보 보기 

db.stats();

{

"db" : "test",

"collections" : 0,

"objects" : 0,

"avgObjSize" : 0,

"dataSize" : 0,

"storageSize" : 0,

"numExtents" : 0,

"indexes" : 0,

"indexSize" : 0,

"fileSize" : 0,

"nsSizeMB" : 0,

"ok" : 1

}

////////////////////////////////

// 몽고디비 서버의 상태 정보 보기 

> db.serverStatus();
{
"host" : "localhost.localdomain",
"version" : "2.2.2",
"process" : "mongod",
"pid" : 7402,
"uptime" : 2089,
"uptimeMillis" : NumberLong(2089225),
"uptimeEstimate" : 1938,
"localTime" : ISODate("2013-01-19T06:11:02.307Z"),
"locks" : {
"." : {
"timeLockedMicros" : {
"R" : NumberLong(0),
"W" : NumberLong(830)
},
"timeAcquiringMicros" : {
"R" : NumberLong(0),
"W" : NumberLong(37)
}
},
... 중략 ...
>

////////////////////////////////

// 다큐먼트를 만들어 보자

> var person = {age:11, name:'dowon', sex:true};
> person
{ "age" : 11, "name" : "dowon", "sex" : true }

////////////////////////////////

// show 명령어 dbs, collections

show dbs
local (empty)
test (empty)
show collections

////////////////////////////////

// 데이터베이스 만들기

// save 할때  생성됨 

use dowonDB  <== 1) DB open 없으면 save시에 신규 생성해줌 

switched to db dowonDB

show dbs

local (empty)

test (empty)


///////////////////////////////

// db가 현재 디비의 포인터이다

db.colles.save({age:11, name:'dowon', sex:true});  <== 2) collection 생성

show dbs

dowonDB 0.0625GB

local (empty)

test (empty)

> db.colles.find().pretty()  <== formatting 해주기 pretty()

{

"_id" : ObjectId("510331d0dfdfcef5beb23d02"),

"age" : 11,

"name" : "dowon",

"sex" : true

}

> db.colles.save({age:222})

> db.colles.find()

{ "_id" : ObjectId("510331d0dfdfcef5beb23d02"), "age" : 11, "name" : "dowon", "sex" : true }

{ "_id" : ObjectId("510332c0dfdfcef5beb23d03"), "age" : 222 }

> db.colles.find({age:222})

{ "_id" : ObjectId("510332c0dfdfcef5beb23d03"), "age" : 222 }


////////////////////////////////

// 입력 컬럼 수정하기 update({}, {})

> db.colles.update({

... age:222}, {

... $set: {age:22}})

> db.colles.find()

{ "_id" : ObjectId("510331d0dfdfcef5beb23d02"), "age" : 11, "name" : "dowon", "sex" : true }

{ "_id" : ObjectId("510332c0dfdfcef5beb23d03"), "age" : 22 } <==  222 에서 22 로 변경되었음 


// 새로운 document(==record) 입력

> db.colles.save({age:33, name:'sia'})

> db.colles.find()

{ "_id" : ObjectId("510331d0dfdfcef5beb23d02"), "age" : 11, "name" : "dowon", "sex" : true }

{ "_id" : ObjectId("510332c0dfdfcef5beb23d03"), "age" : 22 }

{ "_id" : ObjectId("5103350fdfdfcef5beb23d04"), "age" : 33, "name" : "sia" }

// 걸러네기 : MongoDB의 결과값은 Map으로 나온다

> db.colles.find().skip(1).limit(1)

{ "_id" : ObjectId("510332c0dfdfcef5beb23d03"), "age" : 22 }

> db.colles.find().skip(1)

{ "_id" : ObjectId("510332c0dfdfcef5beb23d03"), "age" : 22 }

{ "_id" : ObjectId("5103350fdfdfcef5beb23d04"), "age" : 33, "name" : "sia" }


// 새로운 값 입력 

> db.colles.insert({value:4});

> db.colles.insert({value:5});

> db.colles.insert({value:6});

> db.colles.insert({value:7});

> db.colles.insert({value:1});

> db.colles.insert({value:2});

> db.colles.insert({value:0});

> db.colles.find().skip(1).forEach(printjson) <== 새로운 값입력후 forEach 사용하기 
{ "_id" : ObjectId("510332c0dfdfcef5beb23d03"), "age" : 22 }
{ "_id" : ObjectId("5103350fdfdfcef5beb23d04"), "age" : 33, "name" : "sia" }
{ "_id" : ObjectId("51033646dfdfcef5beb23d05"), "value" : 4 }
{ "_id" : ObjectId("51033649dfdfcef5beb23d06"), "value" : 5 }
{ "_id" : ObjectId("5103364cdfdfcef5beb23d07"), "value" : 6 }
{ "_id" : ObjectId("51033652dfdfcef5beb23d08"), "value" : 7 }

/////////////////////////////////
// property operator 사용하기 
> db.colles.find({value: {$gt: 4}})  <== mongodb의 $는 operator가 된다. {$gt: 4}는 property operation이다
{ "_id" : ObjectId("51033649dfdfcef5beb23d06"), "value" : 5 }
{ "_id" : ObjectId("5103364cdfdfcef5beb23d07"), "value" : 6 }
{ "_id" : ObjectId("51033652dfdfcef5beb23d08"), "value" : 7 }
// 입력
> db.colles.insert({values: [a, b, c, d]});
Fri Jan 25 18:02:09 ReferenceError: a is not defined (shell):1
> db.colles.insert({values: ['a', 'b', 'c', 'd']});
> db.colles.insert({values: ['b', 'c']});
> db.colles.insert({values: ['d']});
> db.colles.insert({values: ['a', 'c']});
 db.colles.insert({values: ['a', 'c'], value:'dowon'});

> db.colles.find({values: {$in: ['a']}})  <== a가 포함됨 
{ "_id" : ObjectId("51033933dfdfcef5beb23d0c"), "values" : [ "a", "b", "c", "d" ] }
{ "_id" : ObjectId("51033955dfdfcef5beb23d0f"), "values" : [ "a", "c" ] }
{ "_id" : ObjectId("51033984dfdfcef5beb23d10"), "values" : [ "a", "c" ], "value" : "dowon" }
> db.colles.find({values: {$nin: ['a']}}) <== a만 안포함 not in
{ "_id" : ObjectId("510331d0dfdfcef5beb23d02"), "age" : 11, "name" : "dowon", "sex" : true }
{ "_id" : ObjectId("510332c0dfdfcef5beb23d03"), "age" : 22 }
{ "_id" : ObjectId("5103350fdfdfcef5beb23d04"), "age" : 33, "name" : "sia" }
{ "_id" : ObjectId("51033646dfdfcef5beb23d05"), "value" : 4 }
{ "_id" : ObjectId("51033649dfdfcef5beb23d06"), "value" : 5 }
{ "_id" : ObjectId("5103364cdfdfcef5beb23d07"), "value" : 6 }
{ "_id" : ObjectId("51033652dfdfcef5beb23d08"), "value" : 7 }
{ "_id" : ObjectId("51033679dfdfcef5beb23d09"), "value" : 1 }
{ "_id" : ObjectId("5103367cdfdfcef5beb23d0a"), "value" : 2 }
{ "_id" : ObjectId("51033683dfdfcef5beb23d0b"), "value" : 0 }
{ "_id" : ObjectId("5103393ddfdfcef5beb23d0d"), "values" : [ "b", "c" ] }
{ "_id" : ObjectId("5103394cdfdfcef5beb23d0e"), "values" : [ "d" ] }

> db.colles.find({values: {$nin: ['a']}}, {_id:0}) <== _id값은 제외하고 출력
{ "age" : 11, "name" : "dowon", "sex" : true }
{ "age" : 22 }
{ "age" : 33, "name" : "sia" }
{ "value" : 4 }
{ "value" : 5 }
{ "value" : 6 }
{ "value" : 7 }
{ "value" : 1 }
{ "value" : 2 }
{ "value" : 0 }
{ "values" : [ "b", "c" ] }
{ "values" : [ "d" ] }

> db.colles.find({values: {$size: 2}}, {values: 1, _id: 0}) <== _id는 출력하지 말고 values 출력
{ "values" : [ "b", "c" ] }
{ "values" : [ "a", "c" ] }
{ "values" : [ "a", "c" ] }

> db.colles.find({value: {$exists: true}}, {value: 1, values: 1, _id: 0}) <== value 컬럼 있는 것만  출력
{ "value" : 4 }
{ "value" : 5 }
{ "value" : 6 }
{ "value" : 7 }
{ "value" : 1 }
{ "value" : 2 }
{ "value" : 0 }
{ "values" : [ "a", "c" ], "value" : "dowon" }

////////////////////////////////

// 저장된 디렉토리 정보

// BSON으로 저장된다 

[mongodb@localhost ~]$ cd db01
[mongodb@localhost db01]$ ll
total 65552
-rw-------. 1 mongodb mongodb 16777216 Jan 18 22:30 dowonDB.0
-rw-------. 1 mongodb mongodb 33554432 Jan 18 22:30 dowonDB.1
-rw-------. 1 mongodb mongodb 16777216 Jan 18 22:30 dowonDB.ns
-rwxrwxr-x. 1 mongodb mongodb        5 Jan 18 21:36 mongod.lock
drwxrwxr-x. 2 mongodb mongodb     4096 Jan 18 22:30 _tmp

////////////////////////////////

// 컬렉션 내역 찾기 

db.colles2.find();
{ "_id" : ObjectId("50fa3ef3a33733093b8f462f"), "age" : 11 }
{ "_id" : ObjectId("50fa3ef7a33733093b8f4630"), "age" : 22 }
{ "_id" : ObjectId("50fa3efaa33733093b8f4631"), "age" : 33 }
{ "_id" : ObjectId("50fa3f0aa33733093b8f4632"), "age" : 44, "name" : "young" }
db.colles2.find({age:11});
{ "_id" : ObjectId("50fa3ef3a33733093b8f462f"), "age" : 11 }

> db.colles.find({$where : "this.value > 3"});
{ "_id" : ObjectId("51033646dfdfcef5beb23d05"), "value" : 4 }
{ "_id" : ObjectId("51033649dfdfcef5beb23d06"), "value" : 5 }
{ "_id" : ObjectId("5103364cdfdfcef5beb23d07"), "value" : 6 }
{ "_id" : ObjectId("51033652dfdfcef5beb23d08"), "value" : 7 }
> db.colles.find({$where : "this.value > 3"}, {_id:0});
{ "value" : 4 }
{ "value" : 5 }
{ "value" : 6 }
{ "value" : 7 }

// 마치 Procedure처럼 코딩을 한  Callback function을 파라미터로 넣어준다.
> var func = function() {  return this.value > 3; } 
> db.colles.find(func, {_id:0});
{ "value" : 4 }
{ "value" : 5 }
{ "value" : 6 }
{ "value" : 7 }

////////////////////////////////
// 도큐먼트를 객체로 가져와 컬럼(변수) 출력하기
> var dw=db.colles.find({age:11});
> dw[0].name  <== javascript의 객체로 얻어와 컬렉션(배열) 형식으로 변수(컬럼) 출력가능
dowon
> var dw=db.colles.find({age:11});
> dw[0]
{
"_id" : ObjectId("510331d0dfdfcef5beb23d02"),
"age" : 11,
"name" : "dowon",
"sex" : true
}

////////////////////////////////
// RDMS처럼 join 만들기 
> db.colles2.save({age:1, otherid: dw[0]._id}); <== colles 컬렉션의 _id값을 colles 컬렉션에 연결하기 
> db.colles2.find()
{ "_id" : ObjectId("510342f4dfdfcef5beb23d12"), "age" : 1, "otherid" : ObjectId("510331d0dfdfcef5beb23d02") }
> var dw2 = db.colles2.find({_id : ObjectId("510342f4dfdfcef5beb23d12")})
> dw2[0].otherid
ObjectId("510331d0dfdfcef5beb23d02")

////////////////////////////////

// 인덱스를 만들고 find 하면 

// 인덱스를 참조함

// 인덱스를 바로 execution 하여 처리 할 수 있다. 따라서 몽고디비에서는 인덱스를 무한대로 만들 수 있다

// Execution 되고서 사라지는 것이다. 메모리 휘발성이다 

db.colles2.ensureIndex({age:1});  <--- execution으로 바로 인덱스를 생성함 
db.colles2.find({age:44});  <--- index 참조
{ "_id" : ObjectId("50fa3f0aa33733093b8f4632"), "age" : 44, "name" : "young" }



5. 심화 CRUD : update, index

////////////////////////////////

// $exists 오퍼레이터 사용하기 

> db.colles.save({_id: 1, names: ['yun', 'dowon', 'young', 'sik'], qtd: 3})

> db.colles.save({_id: 2, names: ['jung', 'si', 'a', 'yab'], qtd: 3})

> db.colles.save({_id: 3, names: ['yun', 'suk', 'kyung'], qtd: 4})

> db.colles.save({_id: 4, names: ['yun', 'kyung', 'su'], qtd: 4})

> db.colles.save({_id: 4, names: ['ahn', 'chul', 'su'], qtd: 5})

> db.colles.save({_id: 4, names: ['moon', 'jea', 'in'], qtd: 5})

> db.colles.find()

{ "_id" : ObjectId("510331d0dfdfcef5beb23d02"), "age" : 11, "name" : "dowon", "sex" : true }

{ "_id" : ObjectId("510332c0dfdfcef5beb23d03"), "age" : 22 }

{ "_id" : ObjectId("5103350fdfdfcef5beb23d04"), "age" : 33, "name" : "sia" }

{ "_id" : ObjectId("51033646dfdfcef5beb23d05"), "value" : 4 }

{ "_id" : ObjectId("51033649dfdfcef5beb23d06"), "value" : 5 }

{ "_id" : ObjectId("5103364cdfdfcef5beb23d07"), "value" : 6 }

{ "_id" : ObjectId("51033652dfdfcef5beb23d08"), "value" : 7 }

{ "_id" : ObjectId("51033679dfdfcef5beb23d09"), "value" : 1 }

{ "_id" : ObjectId("5103367cdfdfcef5beb23d0a"), "value" : 2 }

{ "_id" : ObjectId("51033683dfdfcef5beb23d0b"), "value" : 0 }

{ "_id" : ObjectId("51033933dfdfcef5beb23d0c"), "values" : [ "a", "b", "c", "d" ] }

{ "_id" : ObjectId("5103393ddfdfcef5beb23d0d"), "values" : [ "b", "c" ] }

{ "_id" : ObjectId("5103394cdfdfcef5beb23d0e"), "values" : [ "d" ] }

{ "_id" : ObjectId("51033955dfdfcef5beb23d0f"), "values" : [ "a", "c" ] }

{ "_id" : ObjectId("51033984dfdfcef5beb23d10"), "values" : [ "a", "c" ], "value" : "dowon" }

{ "_id" : ObjectId("51033df5dfdfcef5beb23d11"), "values" : [ "a", "b", "c", "v" ] }

{ "_id" : 1, "names" : [ "yun", "dowon", "young", "sik" ], "qtd" : 3 }

{ "_id" : 2, "names" : [ "jung", "si", "a", "yab" ], "qtd" : 3 }

{ "_id" : 3, "names" : [ "yun", "suk", "kyung" ], "qtd" : 4 }

{ "_id" : 4, "names" : [ "moon", "jea", "in" ], "qtd" : 5 }


// 불필요한 값이 나온다 

> db.colles.find({}, {names:1, _id:0})

{ }

{ }

... {} 중략 ...

{ }

{ "names" : [ "yun", "dowon", "young", "sik" ] }

{ "names" : [ "jung", "si", "a", "yab" ] }

{ "names" : [ "yun", "suk", "kyung" ] }

{ "names" : [ "moon", "jea", "in" ] }


// $exists 오퍼레이터를 사용한다 

> db.colles.find({names: {$exists: true}}, {names:1, _id:0})

{ "names" : [ "yun", "dowon", "young", "sik" ] }

{ "names" : [ "jung", "si", "a", "yab" ] }

{ "names" : [ "yun", "suk", "kyung" ] }

{ "names" : [ "moon", "jea", "in" ] }


////////////////////////////////

// update 명령  ({1}, {2}) : {1} - 찾는 조건 find, {2} - 업데이트 값

> db.colles.update({_id: 1}, {$inc: {qtd:1}})
> db.colles.find({_id: 1})
{ "_id" : 1, "names" : [ "yun", "dowon", "young", "sik" ], "qtd" : 4 }
> db.colles.update({_id: 1}, {$inc: {qtd:1}})
> db.colles.find({_id: 1})
{ "_id" : 1, "names" : [ "yun", "dowon", "young", "sik" ], "qtd" : 5 }
> db.colles.update({_id: 1}, {$inc: {qtd:1}})
> db.colles.find({_id: 1})
{ "_id" : 1, "names" : [ "yun", "dowon", "young", "sik" ], "qtd" : 6 }

// 값 증가시키기 
> db.colles.update({_id: 3}, {$inc: {qtd:10}})
> db.colles.find({_id: 3})
{ "_id" : 3, "names" : [ "yun", "suk", "kyung" ], "qtd" : 14 }
> db.colles.update({_id: 3}, {$inc: {qtd:10}})
> db.colles.find({_id: 3})
{ "_id" : 3, "names" : [ "yun", "suk", "kyung" ], "qtd" : 24 }

// 배열에 넣기 
> db.colles.update({_id: 1},{$push: {names:'jung2'}})
> db.colles.find({_id: 1})
{ "_id" : 1, "names" : [ "yun", "dowon", "young", "sik", "jung2" ], "qtd" : 6 }
// 이걸 pushAll로 하지 않고 push로 하면 배열로 들어감
> db.colles.update({_id: 1},{$pushAll: {names:['jung2', 'kim', 'choi']}}) 
> db.colles.find({_id: 1})
{ "_id" : 1, "names" : [ "yun", "dowon", "young", "sik", "jung2", "jung2", "kim", "choi" ], "qtd" : 6 }
> db.colles.update({_id: 1},{$push: {names:['jung3', 'kim3', 'choi3']}})
> db.colles.find({_id: 1})
{ "_id" : 1, "names" : [ "yun", "dowon", "young", "sik", "jung2", "jung2", "kim", "choi", [ "jung3", "kim3", "choi3" ] ], "qtd" : 6 }  <== 여러개를 push로 할 경우 별도 배열로 들어감 

// 배열에서 제거하기 
// $pop : 0, 1로 앞단, 뒷단에서 빼기만을 지정가능
// $pull : 컬럼을 지정하여 특정 컬럼을 빼기. 자바스크립트의 Array.slice 와 유사 
> db.colles.update({_id: 1}, {$pull: {names: 'dowon'}}) 
> db.colles.find({_id: 1})
{ "_id" : 1, "names" : [ "yun", "young", "sik", "jung2", "jung2", "kim", "choi", [ "jung3", "kim3", "choi3" ] ], "qtd" : 6 }

// 컬럼 넣고 빼기
> db.colles.update({_id: 1}, {$set: {qtddd:4}})
> db.colles.find({_id: 1})
{ "_id" : 1, "names" : [ "yun", "young", "sik", "jung2", "jung2", "kim", "choi", [ "jung3", "kim3", "choi3" ] ], "qtd" : 6, "qtddd" : 4 }
> db.colles.update({_id: 1}, {$unset: {qtddd:4}})
> db.colles.find({_id: 1})
{ "_id" : 1, "names" : [ "yun", "young", "sik", "jung2", "jung2", "kim", "choi", [ "jung3", "kim3", "choi3" ] ], "qtd" : 6 } <== qtddd 컬럼이 제거됨


////////////////////////////////

// Index 사용하기 : 1 - ascending, 0 - descending

> db.colles.ensureIndex({value:1}) 

> db.system.indexes.find()
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "dowonDB.colles", "name" : "_id_" }
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "dowonDB.colles2", "name" : "_id_" }
{ "v" : 1, "key" : { "value" : 1 }, "ns" : "dowonDB.colles", "name" : "value_1" } <== 추가됨 
> db.colles.find({value:1}).explain()
{
"cursor" : "BtreeCursor value_1", <== BasicCursor에서 BtreeCursor로 바뀌었다 
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"value" : [
[
1,
1
]
]
},
"server" : "localhost.localdomain:27017"
}

> db.colles.find({value:1})  <== index에서 가져오게 된다 
{ "_id" : ObjectId("51033679dfdfcef5beb23d09"), "value" : 1 }

// index 삭제하기 
> db.colles.dropIndex({value: 1})
{ "nIndexesWas" : 2, "ok" : 1 }
> db.system.indexes.find()
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "dowonDB.colles", "name" : "_id_" }
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "dowonDB.colles2", "name" : "_id_" }

// duplicate(중복)되지 않은 index 만들기. 
// unique index는 사용하면 key 개념이 된다
// sparse(희소) index는 값이 없는 것은 저장하지 않는다 
> db.colles.ensureIndex({value:1}, {sparse: true, unique:true, dropDup:true, background:true})
> db.system.indexes.find()
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "dowonDB.colles", "name" : "_id_" }
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "dowonDB.colles2", "name" : "_id_" }
{ "v" : 1, "key" : { "value" : 1 }, "unique" : true, "ns" : "dowonDB.colles", "name" : "value_1", "sparse" : true }

// Shard와 같이 여러 부분에 걸쳐 동일 명령을 내리고 싶다면 runCommand를 사용한다
> db.runCommand({dropIndexes:'colles', index: {value:1}});
{ "nIndexesWas" : 2, "ok" : 1 }
> db.system.indexes.find()
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "dowonDB.colles", "name" : "_id_" }
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "dowonDB.colles2", "name" : "_id_" }


  - {} 브레이스의 집합체 = 몽고디비의 데이터


<참조>

  - MongoDB operation 메뉴얼

  - 간단한 CRUD

  - Index 만들기 (한글 번역)

  - MongoDB Query Pattern 트랜잭션처리를 중심으로

  - MongoDB $where 조건 

posted by Peter Note
2013. 7. 20. 12:25 NodeJS/Concept

Smart Dashboard라는 장난감을 하나 만들면서 서버단을 Node.js로 코딩을 하고 있다. Node.js에서 가장 햇갈리는 부분 그리고 인식의 전환을 해야하는 것들을 "Art of Node"에서 잘 정리해 주고 있다. Node.js의 핵심은 무엇인지 알아보자.



1. Callback

  - Node.js 는 I/O Platform 이다 : filesystm과 network I/O를 위한 플랫폼이다. Gateway와 같다고 생각해 보자~~ 


  


  - Callback은 node.js에서 나온 개념이 아니라 이미 있던 개념 : C언어에서 "함수포인터"와 같다 

  - Async가 기본이기 때문에 결과에 대한 처리를 요청하는 Callback function을 파라미터로 넘긴다 

  - 다음 예는 undefined가 나온다. Async이기 때문에 addOne() 호출(invoke)하고 바로 console.log(myNumber)으로 이동해 버린다. File I/O보다 Memory I/O가 훨씬 더 빠른다. 

var fs = require('fs') // require is a special function provided by node
var myNumber = undefined // we don't know what the number is yet since it is stored in a file

function addOne() {
  fs.readFile('number.txt', function doneReading(err, fileContents) {
    myNumber = parseInt(fileContents)
    myNumber++
  })
}

addOne()

console.log(myNumber) // logs out undefined -- this line gets run before readFile is done

  - 다음 예가 정확한 예이고 Closure개념을 결합하여 정보를 받아서 출력하고 있다. callback을 addOne 함수의 파라미터로 넘겨서 fs.readFile내부의 doneReading Callback 펑션에서 Closure객체로 callback()을 호출하는 것이다

var fs = require('fs')
var myNumber = undefined

function addOne(callback) {
  fs.readFile('number.txt', function doneReading(err, fileContents) {
    myNumber = parseInt(fileContents)
    myNumber++
    callback()
  })
}

function logMyNumber() {
  console.log(myNumber)
}

addOne(logMyNumber)

  - 이것에 대한 Pseudo Pattern 정리하면 다음과 같다 

function addOne(thenRunThisFunction) {
  waitAMinute(function waitedAMinute() {
    thenRunThisFunction()
  })
}

addOne(function thisGetsRunAfterAddOneFinishes() {})

  - Callback을 하다보면 간혹 이런 가독성이 떨어지는 문구를 볼 수 있다. 이에 대한 해결은 Defer/Promise 를 사용한다. Java 진영에서는 Future라고 한다. 주로 Async 프로그래밍시 Callback을 사용할 때의 문제점을 serial하게 해결할 수 있는 do -> then -> error 처리가 가능함 

a(function() {
  b(function() {
    c()
  })
})



2. Events

  - Node.js는 Even Machine (about ruby on rails or twisted of Python) 이다 

  - Observer Pattern을 사용하고, Publish/Subscribe 개념을 갖는다 

  - on 펑션을 통하여 Subscribe 하고, emit 펑션을 통하여 Publish 한다

  - 하기 예는 Subscribe하여 처리할 Handler를 Callback 펑션 정의(Definition)을 미리한다. 그리고 connect() 펑션에 인자로 넣는다 

var chatClient = require('my-chat-client')

function onConnect() {
  // have the UI show we are connected
}

function onConnectionError(error) {
  // show error to the user
}

function onDisconnect() {
 // tell user that they have been disconnected
}

function onMessage(message) {
 // show the chat room message in the UI
}

chatClient.connect(
  'http://mychatserver.com',
  onConnect,
  onConnectionError,
  onDisconnect,
  onMessage
)

  - 위 예를 다른 형태로 변경하면, 즉, connect() 메소드에서 작용하는 원칙은 다음과 같다. on(<EventName>, <Callback Function>) 를 통하여 Subscribe하는 것과 동일하다 

var chatClient = require('my-chat-client').connect()

chatClient.on('connect', function() {
  // have the UI show we are connected
}) 

chatClient.on('connectionError', function() {
  // show error to the user
})

chatClient.on('disconnect', function() {
  // tell user that they have been disconnected
})

chatClient.on('message', function() {
  // show the chat room message in the UI
})

  


3. Stream

  - Stream I/O 를 통하여 끊김없이 file system, network I/O를 수행할 수 있다. 성능의 병목없이 물흐르듯 데이터가 흘러간다. 

  - Substack사의 Stream Handbook을 보자

  - stream module은 노드의 코어모듈이다 : require('stream')

  - 하기 코드는 data.txt 파일읽는 것이 다 끝나면 Callback의 data로 전달이 된다. 이때 data.txt파일이 크다면 그만틈의 메모리를 사용하게 되고 병목이 생길 수 있다. Async 방식을 고려한다면 성능상의 문제를 야기할 수 있겠다. data.txt파일 읽으면서 http응답 병목발생. 

var http = require('http');
var fs = require('fs');

var server = http.createServer(function (req, res) {
    fs.readFile(__dirname + '/data.txt', function (err, data) {
        res.end(data);
    });
});
server.listen(8000);
  - 위의 예제를 Stream 방식으로 변경한다. 파일을 읽어서 일정 크기단위(Chunk)로 요청한 Client로 응답을 준다.  
var http = require('http');
var fs = require('fs');

var server = http.createServer(function (req, res) {
    var stream = fs.createReadStream(__dirname + '/data.txt');
    stream.pipe(res);
});
server.listen(8000);
  - .pipe() 의미

.pipe() is just a function that takes a readable source stream src and hooks the output to a destination writable stream dst: - 읽을 소스 스트림 src가 있고 쓸 스트림으로 output을 연결해 주는 펑션일 뿐이다

src.pipe(dst)

  - 스트림 체이닝(Chaining)의 표현
a.pipe(b).pipe(c).pipe(d)

위 아래 동일 표현

a.pipe(b);
b.pipe(c);
c.pipe(d);

the command-line to pipe programs

a | b | c | d 

  - 스트림의 5가지 : readable, writable, transform, duplex, classic
  - Readable : pipe의 읽을 소스에 대한 처리를 별도로 해주어 output destination으로 보낸다. readableStream.pipe(dst) 
var Readable = require('stream').Readable;

var rs = new Readable;
rs.push('beep ');
rs.push('boop\n');
rs.push(null);

rs.pipe(process.stdout);
$ node read0.js
beep boop
  - Writable : 소스를 읽고서 표현하는 output에 대하여 별도로 지정한다. src.pipe(writableStream)
var Writable = require('stream').Writable;
var ws = Writable();
ws._write = function (chunk, enc, next) {
    console.dir(chunk);
    next();
};

process.stdin.pipe(ws);
$ (echo beep; sleep 1; echo boop) | node write0.js 
<Buffer 62 65 65 70 0a>
<Buffer 62 6f 6f 70 0a>
  - classic방식은 node v0.4 버전때 처음 나왔다. 
  - duplex는 a.pipe(b).pipe(a) 와 같이 양방향 파이프
  - transform은 read/write filter 이다

 


4. Modules

  - 모듈개념으로 npm(Node Package Manager)를 통하여 필요한 것을 설치한다 : 34,000 개가량의 모듈이 등록되어 있음

  - 모듈 찾기 npm search <ModuleName> : npm search pdf

  - package.json 안에 해당 모듈이 사용하는 다른 모듈 정보와 모듈의 일반 정보(이름, 버전, 저장소등)가 있다 : npm init

  - node코드에서 require('some-module'); 를 찾는다. require 동작 순서

  • if a file called some_module.js exists in the current folder node will load that, otherwise - 현재 디렉토리에 있는지 찾는다 
  • node looks in the current folder for a node_modules folder with a some_module folder in it - 현재 디렉토리에 node_modules 디렉토리가 있는지 찾고 있으면 그 밑으로 some_module 폴더가 있는지 찾는다  
  • if it doesn't find it, it will go up one folder and repeat step 2 - 위 두개다 찾지 못하면 윗쪽 폴더로 가서 두번째 처럼 다시 node_module 폴더를 찾아간다 


  • <참조>

      - art of node 원문

      - 함수 포인터에 대한 이해

      - Closure 알아가기

      - NHN이 이야기하는 함수형 언어와 클로져 이야기

      - Substack사의 Stream Handbook

    posted by Peter Note
    2013. 7. 18. 10:08 Middleware, Cloud/WAS

    JBoss 기동후 정상적으로 시작되었는지 확인해 보기위하여 server.log 또는 nohup.out 에서 "Started in" 로그를 체크한다. 하지만 간혹 해당 메세지가 안나올 경우도 있는데 이때는 ADMIN PORT (default: 8080)에 대해서 체크하도록 한다 



    1. start, stop, status check shell

    #!/bin/sh
    #JBOSS start and stop script.
    #rks2286(at)gmail(dot)com
    #Sample script start and stop for jboss:
    #-----------------------
    #Changable texts JBOSS_ROOT, ADMIN_USERNAME, ADMIN_PASSWD, ADMIN_PORT, RMI_PORT, PROFILE.
    #-----------------------
    JBOSS_ROOT=/opt/jboss-eap-4.3/jboss-as/
    ADMIN_USERNAME=admin
    ADMIN_PASSWD=jbossadm
    ADMIN_PORT=8080
    RMI_PORT=1099
    PROFILE=all
    #---------------------
    #JBOSS StartUp.....
    #---------------------
    export CLASSPATH
    start() {
    echo Starting jboss...;
    echo Wait while the jboss server starts...;
    $JBOSS_ROOT/bin/run.sh -c $PROFILE -b 0.0.0.0 > /tmp/null &
    }
    #-------------------
    #JBOSS shutdown.....
    #-------------------
    
    stop() {
    echo Stopping jboss..;
    echo Wait while the jboss server stops;
    $JBOSS_ROOT/bin/shutdown.sh -s `hostname`:$RMI_PORT -u $ADMIN_USERNAME -p $ADMIN_PASSWD &
    }
    status() {
    echo Checking JBoss Status..
    echo Wait for a while...
    _up=`netstat -an | grep $ADMIN_PORT | grep -v grep | wc -l`
    
    if [[ "${_up}" != "0" ]]; then
    echo "###############################################"
    echo "JBoss Application Server is Up!! And Running.!!"
    echo "###############################################"
    else
    echo "##################################"
    echo "JBoss Application Server is Down!!"
    echo "##################################"
    fi;
    }
    
    if [[ "${1}" == "start" ]];
    then
    start
    elif [[ "${1}" == "stop" ]];
    then
    stop
    elif [[ "${1}" == "status" ]];
    then
    status
    else
    echo "####################################################"
    echo Usage:
    echo export JBOSS_ROOT=Path_To_Root_Folder
    echo .\/\jboss.sh start\|\stop;
    echo Example:
    echo export JBOSS_ROOT=\/\opt\/\jboss-eap-4.3\/\jboss-as;
    echo ./jboss.sh start\|\stop;
    echo "####################################################"
    fi;
    exit 0;


    2. 수행 방법 

      - 해당 쉘이 jboss.sh 라면

      - 시작 : jboss.sh start

      - 종료 : jboss.sh stop

      - 정상 : jboss.sh status



    <참조>

      - 원문 : start, stop, status shell script

    posted by Peter Note
    2013. 7. 10. 18:06 Middleware, Cloud/WAS

    아파치<->제이보스로 연결되어 있고 업무 애플리케이션에서 큰 파일을 업로드하면서 아파치에서는 응답없음 메세지가 화면에 나타나고, 제이보스는 계속해서 파일업로드 처리를 하여 정상 종료되었을 경우 어디를 보아야 하는지 알아보자 



    1. mod_jk 설정 찾기

      - 먼저 apache에 설정된 workers.properties 파일을 찾는다

      - socket_timeout 과 reply_timeout 설정 값을 확인한다



    2. socket_timeout 의미

    Socket timeout in seconds used for communication channel between JK and remote host. If remote host does not respond inside that timeout the JK will generate an error, and retry again. If set to value zero (default) the JK will wait for infinite on all socket operations. 

      - 초단위로 설정

      - JK와 리모트이니 여기서는 제이보스간의 연결

      - 제이보스에서 응답이 없으면 timeout 설정값에 따라 에러가 발생함

      - 0으로 설정하면 응답 올 때까지 socket 동작이 유지됨. 권장하지 않음 (참조)



    3. reply_timeout 의미

     Reply_timeout property told webserver to wait some time for reply to a forwarded request before considering the remote tomcat is dead and eventually switch to another tomcat in a cluster group. 

      - 밀리초단위로 설정

      - 리모트 서버 -여기서는 제이보스가 다운되기 전까지- 아파치가 앞선 요청에 대하여 응답을 기다리는 시간

      - 만일 제이보스가 클러스터링 되어 있고 timeout이 발생하면 Live된 곳으로 요청이 재전송됨



    4. 상황 및 튜닝

      - socket_timeout 300 초, reply_timeout 60 초 이면서 파일 업로드가 180초걸릴 경우

        + 아파치에서는 60초후 응답이 없으므로 브라우져로 응답이 없다고 에러를 클라이언트에게 던진다

        + 그러나 리모트 서버쪽의 socket은 300초까지 live 이므로 파일업로드는 정상적으로 수행하게 된다 

        + 클라이언트 입장에서는 브라우져에서 에러를 뱉어내니 에러인줄 알지만 실상은 서버에 정상적으로 업로드 되었다 


      - 파일 업로드 시간이 최대 180초 걸릴 경우

        + socket_timeout = 200 , reply_timeout = 200000 

        + 즉 각 timeout 값을 180초 이상 설정한다 



    <참조> 

      - workers.properties 설정하기

      - socket_timeout과 reply_timeout의 의미

      - apache timeout 에 대하여 : 파일다운로드시

      - socket_timeout과 retry count에 대하여

    posted by Peter Note
    2013. 7. 10. 15:42 MongoDB/Prototyping

    Mongoose를 사용할 경우 몇가지 유용한 API를 제공하고 있다. 이중 virtual, method, pre에 대한 사용법을 알아보자. 예제는 로그인시 패스워드를 암호화 하는 코드를 가지고 파악해 본다



    1. Schemas

      - http://mongoosejs.com/docs/guide.html 의 Schemas에 대한 정의와 플러그인 확장이 가능하다

      - 스키마 인스턴스를 만들었다면 여기에 methods, statics, indexes, virtuals, options등을 설정할 수 있다

      - 플로그인들은 http://plugins.mongoose.com에서 검색가능하다. 현재 나는 _id에 대한 auto increase 기능을 잘 쓰고 있다 

    // 1) 스키마 만들기 : 도큐먼트 구조의 정의

    var ComponentSchema = new mongoose.Schema({
        _id         : { type: Number },
        name        : { type: String },
        type        : { type: String },
        config      : { type: String },
        updated_on  : { type: Date, default: Date.now }
      });

      // 2) 플러그인 확장 & methods, statics, indexes, virtuals, options등 설정
      ComponentSchema.plugin(autoinc.plugin, {
        model : 'sd_component',
        field : '_id',
        start : 200000,
        step  : 1
      });


    // 3) 모델은 스키마 정의에 대한 컴파일된 생성자이다. Model 인스턴스를 통해서 몽고디비로부터 데이터를 CRUD한다

    var Component = mongoose.model('sd_component', ComponentSchema);


      - 샘플로 UserSchema 생성하기

      var UserSchema = new mongoose.Schema({
        username : {type:String, required:true , unique:true},
        hashed_password : {type:String, required:true},
        salt : {type:String, required:true}
      });



    2. Instance Methods

      - 스키마가 만들어지고 난후 기본적으로 설정된 메소드를 상속받아 사용한다 예) findById

      - 사용자 커스텀 메소드를 정의할 수 있다. 처리 결과를 return 한다.

      - statics는 callback을 파라미터로 넘기고, return이 없다. (참조)

    // 메소드안에서 메소드 호출이 가능하다  

    UserSchema.method('authenticate', function(plainText) {
        console.log('authenticate called:')
        console.log('plain text = ' + plainText)
        console.log('hashed = ' + this.encryptPassword(plainText))
        console.log('db password= ' + this.hashed_password)
        return this.encryptPassword(plainText) === this.hashed_password;
      });

      UserSchema.method('makeSalt', function() {
        return Math.round((new Date().valueOf() * Math.random())) + '';
      });


      // crypto 모듈 사용하여 암호화  

      UserSchema.method('encryptPassword', function(password) {
        return crypto.createHmac('sha1', this.salt).update(password).digest('hex');
      });

      UserSchema.method('generateToken', function() {
        return crypto.createHash('md5').update(this.username + Date().toString()).digest("hex");
      });



    3. Virtual

      - MongoDB에 저장되지 않는 편리한 Attribute이다 (참조)

      - set/get 펑션을 정의한다

      UserSchema.virtual('password')
        .set(function(password) {
          this._password = password;
          this.salt = this.makeSalt(); // 사용자정의 메소드 호출
          this.hashed_password = this.encryptPassword(password); // 사용자정의 메소드 호출
        })
        .get(function() { return this._password; });


    // 모델 생성

    var User = mongoose.model('User', UserSchema);

    User.password = '1234';     // set

    console.log(User.password); // get



    4. Pre

      - 몽구스의 middleware기능이다

      - init, validate, save, remove 메소드 수행시 처리되는 미들웨어 펑션이다 

      - 복잡한 유효성검사, 트리거 이벤트 처리등. 예로 사용자를 삭제하면 사용자 관련 블로그포스트도 삭제하기같은 경우 사용

         또는 에러 핸들링

      UserSchema.pre('save', function(next) {
        this.token = this.generateToken();
        if (!validatePresenceOf(this.password || this.hashed_password)) {
          next(new Error('Invalid password'));
        } else {
          next();
        }
      });


    function validatePresenceOf(value) {
      return value && value.length;
    }


    // ex)

    User.save(function(err) { console.log(err.message); } );


      - post : 사후처리



    5. 전체 소스 코드

      - User Model을 모듈로 만든다.  User.js

      - 애플리케이션에서는 User.js를 Model 인스턴스를 리턴받아서 사용한다 

      - Express의 Middleware에서 사용자 로그인시에 User.authenticate을 호출하여 패스워드를 암호화 한다

    var mongoose = require('mongoose'),
      crypto = require('crypto');

    module.exports = function () {

      var UserSchema = new mongoose.Schema({
        username : {type:String, required:true , unique:true},
        hashed_password : {type:String, required:true},
        salt : {type:String, required:true}
      });

      UserSchema.virtual('password')
        .set(function(password) {
          this._password = password;
          this.salt = this.makeSalt();
          this.hashed_password = this.encryptPassword(password);
        })
        .get(function() { return this._password; });

      UserSchema.method('authenticate', function(plainText) {
        console.log('authenticate called:')
        console.log('plain text = ' + plainText)
        console.log('hashed = ' + this.encryptPassword(plainText))
        console.log('db password= ' + this.hashed_password)
        return this.encryptPassword(plainText) === this.hashed_password;
      });

      UserSchema.method('makeSalt', function() {
        return Math.round((new Date().valueOf() * Math.random())) + '';
      });

      UserSchema.method('encryptPassword', function(password) {
        return crypto.createHmac('sha1', this.salt).update(password).digest('hex');
      });

      UserSchema.method('generateToken', function() {
        return crypto.createHash('md5').update(this.username + Date().toString()).digest("hex");
      });

      UserSchema.pre('save', function(next) {
        this.token = this.generateToken();
        if (!validatePresenceOf(this.password || this.hashed_password)) {
          next(new Error('Invalid password'));
        } else {
          next();
        }
      });

      return mongoose.model('User', UserSchema);
    }

    function validatePresenceOf(value) {
      return value && value.length;
    }



    <참조>

      - mongoosse virtual 사용법

      - Action function과 Callback function의 이해 

      - 샘플소스의 GitHub 저장소

    posted by Peter Note
    2013. 7. 9. 18:02 Middleware, Cloud/WAS

    Apache-WebLogic간의 연결시 Timeout 설정에 대한 부분을 체크해 보자.


    1. Apache-WebLogic간의 연결

      - AJP를 사용하지 않고 직접 WebLogic module을 httpd.conf 에 설정한다 (참조)

      - 환경설정 예

    LoadModule weblogic_module    modules/mod_wl_22.so


    <Location /services>
        SetHandler weblogic-handler
    </Location>

    <IfModule mod_weblogic.c>
    WebLogicCluster 127.0.0.1:8881,127.0.0.1:8882
    MatchExpression *.jsp
    Idempotent OFF
    DynamicServerList OFF
    KeepAliveEnabled OFF
    ConnectTimeoutSecs 16
    ConnectRetrySecs 2
    FileCaching OFF
    </IfModule>



    2. Apache Timeout 설정

      - ajp 연결이 아니므로 workers.properties의 socket_timeout 또는 reply_timeout과 관련이 없다

      - apache/httpd/conf/extra/httpd-default.conf의 Timeout 과 관련 (참조)

    Timeout 300
    클라이언트의 요청에 의해 서버와 연결이 되었을 때 클라이언트와 서버간에 아무런 메시지가 발생하지 않았을 때 오류로 처리될 시간을 초단위로 설정. 초기값은 1200초(20분)이며 보통은 300초(5분)로 지정한다. 네트워크의 속도가 나쁠수록 수치값은 높게 설정하는 것이 좋다.



    3. WebLogic Timeout 설정

      - httpd.conf에 timeout 관련 설정을 한다

      - WebLogic안에서 request<->response에 대한 직접적인 처리 - WLIOTimeoutSecs 설정 (참조1, 참조2)

    WLIOTimeoutSecs 300

      - default : 300 초

      - 웹로직으로 request를 보내고 response를 받기 위해서 대기하는 시간

      - post 방식으로 대량의 데이터를 WebLogic으로 보낼 때 timeout이 발생하면 plug-ins에 "POST_TIMEOUT"에러가 발생한다


      - WebLogic을 클러스터링 환경으로 구성하였을 경우는 idempotent 환경에 대하여 고려한다. (참조)

    Idempotent OFF

      - WebLogic서버로 부터 request전송시 에러가 발생하거나, 서버로부터 결과를 기다리는 중에
         위에 정의된 WLIOTimeoutSecs 시간 초과되어서 에러 발생시 요청을 다시 보낼 것인가를 지정.
      - 서버와 연결은 되었는데 그 이후에 에러가 발생 하였을 경우 해당 옵션이 ON이면 다시 연결을 시도하고
        요청을 보내게 되므로 중복 요청의 가능성이 있다. OFF권장.


    posted by Peter Note
    2013. 6. 28. 21:33 Languages/JavaScript

    오늘은 강남토즈에서 김영보선생님의 자바스크립트 객체지향 세미나를 듣고 있다. 간단히 요약해 본다 




    1. OOP

      - object.method() : 전형적인 OOP 형태 

      - Object is "{}" 즉, JSON 포멧

         object is "new Function"

      - 자바스크립트에서 function은 함수가 아니라 키워드일 뿐이다 

        ex) function sales() {}  -->  { "sales" : function(){} } 으로 대치가능하다

      - 수행 순서

         + 소스

           function A() {

       function B() {}

           } 

         + A() 호출하면 A안의 내용만 { "A" : function(){} } 만 만든다 { "B": function(){} } 은 안만든다.

           즉 수행하는 시점에 해석되고 객체로 적재되어 수행한다 

         + 초기 랜더링에 필요한 부분만 해석되어 수행하면 성능 향상을 할 수 있다

      - oop의 information hiding을 위하여 closure를 사용한다 



    2. 메커니즘

      - 메모리 stack 생성 -> Execution Context 저장하고 EC단위로 수행한다 

      - Executable Code type : global code, function code, eval code (eval 코드는 쓰지말라! 5차부터 에러남)

      - Execution Context : Executable code의 실행 단위.  Context : 문맥, 처리단위, 묶음 

      - Stack안에 EC가 들어가는데 가장 먼저 만들어진것이 stack의 바닥부터 위로 채워넣는다. 수행은 위에서 빼서 수행 그때 GC 발생

      - object를 EC에 바인딩 : EC = { VO : { key: value } }   *VO = Variable Object

         모든 EC는 VO와 연동한다 

      - VO 구성요소 : variable, function, function parameter 

        예) 펑션을 만나면 Variable Object를 만든다. { key: value } 이런 형태임



    3. VO 메커니즘

      - Global Context, function context로 분리  

      - Global Context : 하나만 존재, Global object도 VO와 연동. 즉, Global object와 VO는 같음

      - 코드가 Hoisting되어서 function -> variable 순으로 호출됨. 즉, function 호출

      - VO의 function context는 AO와 같음 *AO = Activation Object : function 호출시 AO를 만들어 수행하는 것이다 

      - function 실행되면

        + AO 생성 : function & AO 바인딩

        + function에 아규먼트 갯수와 상관이 없으므로 arguments 객체를 만들어줌 (배열아님)

        + 내부 function을 설정, 실행하는 것이 아니다 { key: value } 로 설정

      - scope chain은 scope binding의 추상개념이다



    4. Property 탐색 & 클로져

      - property = { key: value } 형태 추상개념

      - Global Context -> Inner Function AO에서 탐색 

      - 클로져 (참조)

        + 내부변수를 참조하는 함수를 리턴함 == function code + [[Scope]]의 조합

        + function 생성 시점에 클로져 설정 



    5. This

      - 모든 EC와 this와 관련이 있다

      - function단위로 this 오브젝트를 만든다 (this value)

      - this는 AO에 생긴다. AO는 function이다. 따라서 this는 function안에 존재한다 

      - EC = {VO/AO, value, this: value} 형태  

      - null : 프로세싱 한것. 값이 undefine에서 null이 된것이다 

        undefine : 프로세싱 안한것

      - this.a 했을 때 a가 undefine이면 this생성이 안된 경우일 것이다 (참조)



    6. Prototype 

      - object는 prototype을 갖음 

      - [[function]].prototype.property_name 형식

      - this.property_name 으로 접근가능

      - prototype chain이 된다 : 상속개념 사용가능 -> 사용자제 

      - 렌더링시에 생성되어 수행되게 할려면 new 사용을 자제한다?

      - 사용이유 : prototype을 사용하면 new이후 this로 정의한 것을 접근할 수 있기 때문이다 

      - 객체를 1차레벨로 수평화 하라 -> 오브젝트를 불러서 사용한다 (Node.js의 require와 비슷하겠다) -> 접근성이 용이해 진다 


    다음 강좌가 있으면 또 교육을 받아봐야 겠다. 정말 설명을 명확하게 잘 해주신다.



    <참조>

      - MSDN 자바스크립트 객체지향 이야기

      - NHN이 말하는 자바스크립트의 클로져 이야기

    posted by Peter Note
    2013. 6. 22. 12:35 Meteor

    오늘은 마지막 수업날. 미티어의 개념과 아키텍쳐 그리고 실업무 프로젝트를 위한 디렉토리 구조에 대해 프로토타입핑해 보고, Twitter Bootstrap이나 Font-Awesome을 접목시켜본다.



    1. 미티어 개념 핵심

      - 웹앱의 진화 개념에서 기존의 다른 프레임워크와 차이를 보인다

      - 미티어는 클라이언트와 서버사이에 스토어인 MongoDB가 존재한다

        + WebApp v1.0 : 서버단의 rendering pc 기술

        + WebApp v1.5 : client는 SPA로 진화, server+db의 통합

        + WebApp v2.0 : client <-> db + db <-> server 로 묶인다

      

      - FireBase의 서비스를 보면서 WebApp 2.0 Meteor와 맵핑이 된다 

       + How it works

      


      - 미티어는 이것이다!

        + client <-> db 사이에서 미티어가 하는 일이 핵심 개념이다. 그러나 db <-> server 까지도 통합해 놓았다

        + server는 웹서버 또는 데이터 전달의 역할을 수행한다

        + 미티어를 중심으로 MVC가 구현된다. 

           Model - DX Area (Data eXperience)

           View  - UX Area (User or UI eXperience) 

           Controller - BX Area (Business eXperience)

       

                          <KOSTA 이복영강사님이 생각하시는 미티어의 X 영역들>



    2. 프로젝트 기본 구조

      - 미티어를 설치하고 간단한 myapp 을 시작해 보자

        + myapp 디렉토리를 들어가 보면 간단 3개의 파일이 존재한다 : myapp.js, myapp.css, myapp.html

        + 단 3개의 파일을 통하여 client <-> server 코딩이 완료되었다

    $ meteor create myapp

    myapp: created.

    To run your new app:

       cd myapp

       meteor


      - myapp 프로젝트안에서 미티어가 인식하는 디렉토리 구조

        + client, server 디렉토리 밑으로 하위 디렉토리를 만들어서 프로젝트 업무 controller별, 기능별로 나눌 수 있고, 자동 인식된다

        + 각 디렉토리를 만들고 myapp을 실업무 구조로 만들어 본다

    · client – 클라이언트에서 수행되는 JavaScript 와 HTML 파일

    · server – 서버에서 수해되는 JavaScript 와 HTML 파일

    · common – 클라이언트와 서버에서 수행되는 JavaScript 파일

    · lib –  다른 모든 JavaScript 파일보다 먼저 수행 할 JavaScript 파일

    · public – static application assets such as images.



    3. 실업무 구조로 만들어 보기 

      - 링크 사이트의 실습을 따라해 본다

     1) client/movies.html : html 태그를 사용하지 않고 head 와 body 만 존재한다 

    <head>

      <title>myapp</title>

    </head>


    <body>

      <h1>Movies</h1>

      {{> moviesTemplate }}

    </body>  


      2) client/moviesTemplate.html 파일 생성 : movies.html안에 포함된다 

    <template name="moviesTemplate">

      <ul>

        {{#each movies}}

        <li>

          {{title}}

        </li>

        {{/each}}

      </ul>

    </template>


      3) client/movies.js 파일 생성 : moview 컬렉션을 글로벌로 만든다. moviesTemplate.movies 확장 메소드를 정의한다 

    Movies = new Meteor.Collection("movies");

    Template.moviesTemplate.movies = function () {

      return Movies.find();

    };


     4) server/movies.js 파일 생성 : 데이터가 없으면 테스트용 값을 넣는다  

    // Declare server Movies collection

    Movies = new Meteor.Collection("movies");


    // Seed the movie database with a few movies

    Meteor.startup(function () {

      if (Movies.find().count() == 0) {

        Movies.insert({ title: "Star Wars", director: "Lucas" });

        Movies.insert({ title: "Memento", director: "Nolan" });

        Movies.insert({ title: "King Kong", director: "Jackson" });

      }

    });


      5) client/movieForm.html 파일 생성 및 movies.html 갱신: 무비 등록

    // movieForm.html

    <template name="movieForm">

      <fieldset>

        <legend>Add New Movie</legend>

        <form>

          <div>

            <label>

              Title:

              <input id="title" />

            </label>

          </div>

          <div>

            <label>

              Director:

              <input id="director" />

            </label>

          </div>

          <div>

            <input type="submit" value="Add Movie" />

          </div>

        </form>

      </fieldset>

    </template>


    // movies.html 

      {{> moviesTemplate }}

      {{> movieForm }}  <-- 추가



      6) client/movies.js 내역을 갱신한다 : movieForm.events 헬퍼메소드를 정의한다

    Template.moviesTemplate.movies = function () {

      return Movies.find();

    };


    // Handle movieForm events

    Template.movieForm.events = {

      'submit': function (e, tmpl) {

        // Don't postback

        e.preventDefault();


        // create the new movie

        var newMovie = {

          title: tmpl.find("#title").value,

          director: tmpl.find("#director").value

        };


        // add the movie to the DB

        Movies.insert(newMovie);

      }

    };


      7) 실제값을 넣어본다 : 화면이 갱신되며, MongoDB에도 데이터가 새롭게 insert된다 : meteor의 몽고 쉘로 들어가서 확인함


    $ meteor mongo

    MongoDB shell version: 2.4.3

    connecting to: 127.0.0.1:3002/meteor

    > use meteor

    switched to db meteor

    > show collections

    movies

    system.indexes

    > db.movies.find()

    { "title" : "Star Wars", "director" : "Lucas", "_id" : "xmTvZ6Lv4CazosgGi" }

    { "title" : "Memento", "director" : "Nolan", "_id" : "M6jf2LgXMhsvTXboB" }

    { "title" : "King Kong", "director" : "Jackson", "_id" : "xxZ6ynrxFPwB7jCoD" }

    { "title" : "hi ", "director" : "dowon", "_id" : "Cwri8WHudNq8sMyXe" }


      8) 심화학습

      + Movies 와 동일하게 Persons를 확장해 보자

    $ meteor mongo 

    > db.persons.find()

    { "name" : "Yun DoWon", "phone" : "010-1004", "_id" : "7e2Buco4sREFgjDCw" }


      

      + Meteor.Collection 생성을 lib 디렉토리로 옮기게 되면 client/movies.js, server/movies.js 에서 중복 코드를 제거할 수 있다. 

           lib/collections.js 만들기 

    Movies = new Meteor.Collection("movies");

    Persons = new Meteor.Collection("persons");


      + movies, persons 디렉토리로 구별한다 

      



    4. Twitter Bootstrap 입히기

      - http://twitter.github.io/bootstrap/ 사이트에서 파일을 다운로드 받는다

      - bootstrap.zip 파일을 client/bootstrap 디렉토리에 푼다

      - client/persons/personsTemplate.html에서 css를 적용해 본다 

    // personsTemplate.html 

    <template name="personsTemplate">

      <ul>

        {{#each persons}}

        <li class="btn">

          {{name}}

        </li>

        <li class="alert">

          {{phone}}

        </li>

        {{/each}}

      </ul>

    </template> 


    // personForm.html

     <input class="btn" type="submit" value="Add Person" />

     


      - Font Awesome css도 넣어보자. Twitter Bootstrap처럼 수동으로 설치하지 않고 meteorite를 통해 설치한다 

        + https://github.com/nate-strauser/meteor-font-awesome 해당 사이트에서 font-awesome 을 설치해야하는 함정이... ^^

        + meteorite는 node.js의 npm과 유사하게 meteor의 package 를 관리해 준다

    $ npm install -g meteorite

    $ mrt add font-awesome

    ✓ font-awesome

        tag: https://github.com/nate-strauser/meteor-font-awesome.git#v3.2.0


    Done installing smart packages


    // packages 디렉토리 밑으로 font-awesome이 설치되었다

    // smart.json과 smart.lock 파일은 meteorite 환경파일


      -  client/personForm.html 에 아이콘을 넣는다 

    <template name="personForm">

    <div class="container">

      <fieldset>

        <legend>Add New Person</legend>

        <form>

          <div>

            <label>

              Name:

              <input id="name" />

            </label>

          </div>

          <div>

            <label>

              Phone:

              <input id="phone" />

            </label>

          </div>

          <div>

            <i class="icon-male"></i> <input class="btn" type="submit" value="Add Person" />

          </div>

        </form>

      </fieldset>


      <!-- test -->

      <a class="btn" href="#">

        <i class="icon-repeat"></i> Reload</a>

      <a class="btn btn-success" href="#">

        <i class="icon-shopping-cart icon-large"></i> Checkout</a>

      <a class="btn btn-large btn-primary" href="#">

        <i class="icon-comment"></i> Comment</a>

      <a class="btn btn-small btn-info" href="#">

        <i class="icon-info-sign"></i> Info</a>

      <a class="btn btn-danger" href="#">

        <i class="icon-trash icon-large"></i> Delete</a>

      <a class="btn btn-small" href="#">

        <i class="icon-cog"></i> Settings</a>

      <a class="btn btn-large btn-danger" href="#">

        <i class="icon-flag icon-2x pull-left"></i> Font Awesome<br>Version 3.2.1</a>

      <a class="btn btn-primary" href="#">

        <i class="icon-refresh icon-spin"></i> Synchronizing Content...</a>




    <참조>

      - 미티어 구조 설계하기

      - 미티어 한글번역 : http://docs-ko.meteor.com/

      - 아이콘 확장은 Font Awesome을 사용한다 : http://fortawesome.github.io/Font-Awesome/

      - 심화학습 코드 : .meteor는 포함되지 않았으니 meteor create을 하고서 첨부한다

    myapp.tar



    posted by Peter Note

    JetBrains의 WebStorm v6 을 설치하고, Sublime Text 2와 같은 검은색 바탕의 스킨을 사용하고 싶다면 다음과 같이 조정을 한다 



    1. 이미 만들어진 커스텀 스킨사용

      - Darcula 스킨사용 : 최신버전에 포함되어 있으나 editor 부분이 회색으로 가시성이 약간 떨어진다

      

      코드 에디터 상의 스킨 색감 : Warning 표기 (점선)이 너무 많이 나온다. 알거덩 없어져라...^^;

      



    2. 에디터를 Sublime Text 2 와 같은 스킨으로 변경하기 

      - 검정색 바탕으로 변경하여 가시성을 주고, 색감도 원색으로 변경한다

      - Warning 점선등의 보고 싶지않은 선들을 없앤다

      


      - 첨부파일을 Import 한다 (참조에 첨부파일)

        + WebStorm -> File -> Import Settings... 

        + 첨부파일을 선택하고 Color와 관련된 것만 선택하여 설정한다

        



    <참조>

      - Sublime Text 2 형태로 수정된 환경파일 (단, WebStorm v6 최신버전만 가능) 

    Webstorm-Dracular-Dowon-Setting_Full.jar

      - WebStorm Import/Export Setting 메뉴얼


    posted by Peter Note
    2013. 6. 7. 14:16 Dev Environment/Sublime Text

    1. 맥

    General

    ⌘Tgo to file
    ⌘⌃Pgo to project
    ⌘Rgo to methods
    ⌃Ggo to line
    ⌘KBtoggle side bar
    ⌘⇧Pcommand prompt
    ⌃ `python console
    ⌘⇧Nnew window (useful for new project)

    Editing

    ⌘Lselect line (repeat select next lines)
    ⌘Dselect word (repeat select others occurrences in context for multiple editing)
    ⌃⇧Mselect content into brackets
    ⌘⇧↩insert line before
    ⌘↩inter line after
    ⌃⇧Kdelete line
    ⌘KKdelete from cursor to end of line
    ⌘K⌫delete from cursor to start of line
    ⌘⇧Dduplicate line(s)
    ⌘Jjoin lines
    ⌘KUupper case
    ⌘KLlower case
    ⌘ /comment
    ⌘⌥ /block comment
    ⌘Yredo or repeat
    ⌘⇧Vpast and ident
    ⌃ spaceautocomplete (repeat to select next suggestion)
    ⌃Mjump to matching brackets
    ⌘Usoft undo (movement undo)
    ⌘⇧Usoft redo (movement redo)

    XML/HTML

    ⌘⇧Aselect content into tag
    ⌘⌥ .close tag

    Find/Replace

    ⌘Ffind
    ⌘⌥Freplace
    ⌘⌥Gfind next occurrence of current word
    ⌘⌃Gselect all occurrences of current word for multiple editing
    ⌘⇧Ffind in files

    Splits/Tabs

    ⌘⌥1single column
    ⌘⌥2two columns
    ⌘⌥5grid (4 groups)
    ⌃[1,2,3,4]focus group
    ⌃⇧[1,2,3,4]move file to group
    ⌘[1,2,3…]select tab

    Bookmarks

    ⌘F2toggle bookmark
    F2next bookmark
    ⇧F2previous bookmark
    ⌘⇧F2clear bookmarks

    Marks

    ⌘K spaceset mark // ⌘K; for me
    ⌘KWdelete from cursor to mark
    ⌘KAselect from cursor to mark
    ⌘KGclear mark




    2. 윈도우

    Sublime Text 2 shortcut
    영어한글단축키설명
    New File새파일Ctrl+N새문서나 새파일을 만듬.
    Open File열기Ctrl+O새문서나 새파일을 열기
    Open Folder폴더열기폴더열기
    Open Recent최근문서열기최근문서열기
    Reopen with Encoding인코딩해서 다시열기인코딩해서 다시열기
    New View into File새로보기현재의 문서를 새탭에 열러서 새로보기
    Save저장Ctrl+S저장
    Save with Encoding인코딩해서 저장현재의 문서 인코딩변경해서 저장
    Save as새로 저장Ctrl+Shift+S다른 이름으로 저장
    Save All모두저장모두저장
    New Window새창으로 열기Ctrl+Shift+N에디터를 두개이상 실행하고자 할때 새창으로 열기
    Close Window새창 닫기Ctrl+Shift+W탭이 아닌 창으로 닫기
    Close File닫기Ctrl+W탭 또는 창 닫기
    Revert File파일되돌리기수정되기전으로 파일을 되돌립니다.
    Colse All Files모든파일닫기모든 파일 닫기
    Exit나가기나가기
    Undo Insert Characters문자삽입취소Ctrl+Z삽입한 문자를 취소할때 사용합니다
    Repeat Insert Characters문자삽입반복Ctrl+Y문자 삽입 반복
    Undo Insert Characters문자삽입취소Ctrl+U문자 삽입 취소
    Soft RedoCtrl+Shift+U소프트 다시 실행
    Copy복사Ctrl+C복사
    Cut자르기Ctrl+X자르기
    Paste붙여넣기Ctrl+V붙여넣기
    Paste and indent붙여 넣기 및 들여 쓰기Ctrl+Shfte+V붙여 넣기 및 들여 쓰기
    Indent들여쓰기Ctrl+]들여쓰기
    Unindent내어 쓰기Ctrl+[내어 쓰기
    Reindent다시들여쓰기들어쓰기나 내어쓰기한 경우 다시 되돌리는 기능
    Swap Line Up한줄위로Ctrl+Shift+Up현재의 행을 윗행과 교체합니다
    Swap Line Down한줄아래로Ctrl+Shift+Down현재의 행을 아랫행과 교체합니다
    Duplicate Line행 복사Ctrl+Shift+D현재의 행을 아래에 복사해서 붙여넣어줌
    Delete Line행 삭제Ctrl+Shift+K현재의 행을 삭제하고 위로 이동함.
    Join Lines행 합침Ctrl+J다음줄을 현재의 줄에 합류시킵니다.
    Toggle Comment주석 전환Ctrl+/주석을 만들고 없애는 기능
    Toggle Block CommentCtrl+Shift+/요소가 포함된 블럭 전체를 주석처리함.
    Insert Line BeforeCtrl+Shift+Enter블럭 앞에 행 삽입
    Insert Line AfterCtrl+Enter블럭 뒤에 행 삽입
    Delete Word ForwardCtrl+Delete커서 뒤 단어 삭제
    Delete Word BackwardCtrl+Backspace커서 앞 단어 삭제
    Delete Line한줄삭제Ctrl+Shift+K한줄을 삭제합니다
    Delete to End끝단어삭제Ctrl+K,Ctrl+k커서 다음부터 끝줄까지 삭제
    Delete to Beginning앞단어삭제Ctrl+k,Ctrl+Backspace커서 앞에 있는줄까지 삭제
    Transpose바꾸기Ctrl+T커서 왼쪽과 오른쪽 단어를 바꿈
    Close Tag태그닫기Alt+.열려있는 태그요소 닫기
    Expand Selection to TagCtrl+Shift+A현재 커서가 위치한 요소의 전체 블럭을 선택영역으로 만들기
    Wrap Selection With Tag태그 묶음 선택Alt+Shift+W
    Set Mark마크설정Ctrl+K,Ctrl+Space번호 마크를 생성합니다
    Select To Mark마크 선택Ctrl+K,Ctrl+A현재커서부터 마크까지 선택
    Delete To Mark마크삭제Ctrl+K,Ctrl+W만들어놓은 마크를 삭제합니다
    Swap With Mark마크교체Ctrl+K,Ctrl+X전에있던 마크를 현재있던 곳으로 교체합니다
    Clear Mark마크삭제Ctrl+K,Ctrl+G있던 마크를 삭제합니다
    YankCtrl+k,Ctrl+Y마크영역을 현재 요소안에 삽입합니다
    Fold접기Ctrl+Shfit+[바로 위 부모까지 접기
    Unfold펴기Ctrl+Shift+]바로 아래 자식까지 펴기
    Unfold All모두 펴기Ctrl+K,Ctrl+j모두 펴기
    Fold All모두접기Ctrl+K,Ctrl+1빈줄없이 모두 접습니다
    Fold Level 2Ctrl+K,Ctrl+2
    Fold Level 3Ctrl+K,Ctrl+3
    Fold Level 4Ctrl+K,Ctrl+4
    Fold Level 5Ctrl+K,Ctrl+5
    Fold Level 6Ctrl+K,Ctrl+6
    Fold Level 7Ctrl+K,Ctrl+7
    Fold Level 8Ctrl+K,Ctrl+8
    Fold Level 9Ctrl+K,Ctrl+9
    Fold Tag AttributesCtrl+K,Ctrl+T현재 블럭에 있는 어트리뷰트 태그요소를 접습니다
    Title Case첫문자만 대문자로 만듭니다
    Upper CaseCtrl+K,Ctrl+U대문자로 만듭니다
    Lower Case소문자화Ctrl+K,Ctrl+L소문자로 만듭니다
    Swap Case대문자를 소문자로, 소문자를 대문자로 변환
    Wrap Paragraph at RulerAlt+Q들여쓰기가 모아짐
    Show CompletionsCtrl+Space자동완성 툴팁 표시
    Sort LinesF9라인에 맞쳐정렬
    Sort Lines(Case Sensitive)Ctrl+F9라인에 맞쳐정렬(대소문자 구분)
    Split into LinesCtl+Shift+L선으로 분할
    Add Previous LineCtrl+Alt+Up커서를 위로 한행 추가하여 준비합니다
    Add Next LineCtrl+Alt+Down커서를 아래로 한행 추가하여 준비합니다
    Single Selection단일선택Escape단일 선택
    Select All모두선택Ctrl+A모두 선택
    Expand Selection to Line행선택Ctrl+L행으로 선택영역을 확장합니다
    Expand Selection to Word단어선택Ctrl+D단어로 선택영역을 확장합니다
    Expand Selection to ScopeCtrl+Shift+Space범위에 있는 모든것으로 선택을 확장합니다
    Expand Selection to BracketsCtrl+Shift+M
    Expand Selection to IndentationCtrl+Shift+J들여 쓰기로 선택영역 확장
    Expand Selection to TagCtrl+Shift+A태그영역안까지 선택영역 확장
    Find찾기Ctrl+F찾기
    Find Next다음찾기F3다음찾기
    Find PreviousShift+F3
    Incremental Find이전찾기Ctrl+I이전 찾기
    Replace대체Ctrl+H문자열을 대체할때 사용합니다.
    Replace Next전부대체Ctrl+Shift+H한번에 모든 문자열을 대체합니다
    Quick Find빨리찾기Ctrl+F3빨리찾기
    Quick Find AllAlt+F3빠른 모두 찾기
    Quick Add NextCtrl+K,Ctrl+D빠른 다음 추가
    Use Selection for FindCtrl+E
    Use Selection for ReplaceCtrl+Shift+E
    Find in FilesCtrl+Shift+F파일에서 원한는 영역찾고, 대체하기
    Show Results Panel결과 패널 표시
    Next ResultF4다음 결과
    Previous ResultShift+F4이전 결과
    Side BarCtrl+K,Ctrl+B사이드바 열기 닫기
    Show Console콘솔 보기Ctrl+`에디터에서 사용하는 콘솔 보기
    Enter Full ScreenF11전체 화면으로 전환
    Enter Distraction Free ModeShift+F11전체화면에서 가운데에 위치한 모드로 전환
    Single싱글Alt+Shift+1에디터 하나로 보기
    Columns:2컬럼:2Alt+Shift+2좌우로 두개의 컬럼으로 보기
    Columns:3컬럼:3Alt+Shift+3좌우로 세개의 컬럼으로 보기
    Columns:4컬럼:4Alt+Shift+4좌우로 네개의 컬럼으로 보기
    Rows:2Alt+Shift+8상하로 두개의 컬럼으로 보기
    Rows:3Alt+Shift+9상하로 세개의 컬럼으로 보기
    Grid:4Alt+Shift+5상하로 네개의 컬럼으로 보기
    Group 1Ctrl+1
    Group 1Ctrl+Shift+1
    Spell CheckF6맞춤법 검사
    Next MisspellingCtrl+F6다음 철자 오류
    Prev MisspellingCtrl+Shift+F6이전 철자 오류
    Goto AnythingCtrl+P바로가기
    Goto SymbolCtrl+R심볼 바로가기
    Goto LineCtrl+G행 바로가기
    Next FileCtrl+Pagedown다음 탭으로 가기
    Previous FileCtrl+Pageup이전 탭으로 가기
    Next File in StackCtrl+Tab다음문서에서 스택으로 바로가기
    Previous File in StackCtrl+Shift+Tab이전문서에서 스택으로 바로가기
    Switch HeaderAlt+O해더 타이틀 변경
    Scroll to SelectionCtrl+K,Ctrl+C커서가 있는 곳으로 스크롤
    Line Up한줄올림Ctrl+Up보여지는 영역이 한줄 올라감
    Line Down한줄내림Ctrl+Down보여지는 영역이 한줄 내려감
    toggle BookmarkCtrl+F2책갈피 전환
    Next BookmarkF2다음 책갈피
    Prev BookmarkShift+F2이전 책갈피
    Clear BookmarksCtrl_Shift+F2책갈피 삭제
    Select All BookmarksAlt+F2모든 책갈피를 선택
    Jump to Matching BracketCtrl+M일치하는 브라켓으로 이동
    Command Palette..명령 팔레트Ctrl+Shift+P명령 팔레트를 불러옴
    Build생성Ctrl+B새로운 형식으로 생성함
    Cancel Build생성취소Ctrl+Break생성취소
    Show Build Results생성한 결과 보기
    Next ResultF4다음 결과 보기
    Previous ResultShift+F4이전 결과 보기
    Record Macro매크로기록Ctrl+Q매크로 기록을 시작함.
    Playback MacroCtrl+Shift+Q매크로 재생
    Save Macro매크로 저장
    Macro매크로
    Open Project프로젝트열기프로젝트 열기
    Clear Items아이템 삭제
    Switch Project in WindowCtrl+Alt+P새로운 윈도우를 열어서 프로젝트 전환함
    Save Project As..프로젝트 저장
    Close Project프로젝트 닫기
    Edit Project프로젝트 편집
    Add Folder to Project프로젝트에 폴더 추가
    Remove all Folders..모든 폴더를 삭제
    Refresh Folders폴더 새로 고침
    Browse Packages브라우져패키지플러그인이 들어있는 폴더 열기
    Settings-Default기본 설정
    Settings-User사용자 설정
    Syntax Specific-User사용자 문법
    Distraction Free-User
    Key Bindings-Default키 바인딩 기본설정
    Key Bindings-User키 바이딩 사용자설정
    Create Public Gist..Ctrl+K,Ctrl+I발행할 Gist 만들기
    Create Private Gist..Ctrl+K,Ctrl+P개인적인 Gist 만들기
    Open Gist..Ctrl+K,Ctrl+OGist 열기
    Insert Gist..Ctrl+K,Ctrl+[Gist 삽입
    Add File to Gist..Ctrl+K,Ctrl+]

    Gist에 파일 첨부


    <참조>

      - 원문 : http://demun.tistory.com/2239

    posted by Peter Note