Collection2

-----------


Collection2는 Mongo.Collection 에 스키마를 지원하는 미티어 패키지이다.

컬렉션에 데이터를 클라이언트 나 서버 코드에서 삽입하거나 업데이트 할때 

자동적으로 스키마에 적합한 데이터인가를 검증해 준다. 


Collection2 패키지는 aldeed:simple-schema 패키지를 기반으로 작성되어 있다. 

그래서 이 패키지는 Collection2 패키지를 설치할 때 자동으로 설치된다. 

Collection2 패키지에 포함된 aldeed:simple-schema 는 스키마 문법처리와 검증 로직을 담당한다. 


설치

----


Collection2 패키지를 설치하고 싶으면 미티어 앱 디렉토리에서 다음과 같이 입력한다. 


$ meteor add aldeed:collection2

왜 Collection2 패키지를 사용해야 할까?

--------------------------------------


- allow/deny 규칙을 사용하는 방식은 허가된 사용자가 클라이언트에서 도큐먼트를 조작하는 것에 대한 

     제어만이 가능하지만 Collection2를 사용하면 단순히 스키마를 추가하는 것만으로도

 

도큐먼트의 세부적인 속성(properties)과 값을 조작 대상으로 지정할수 있다. 

이말은 무결성을 손상시키지 않고 클라이언트에서 삽입 및 업데이트를 섬세하게 처리할 수 있다는 말이다.  

 

- Collection2는 모든 삽입 및 업데이트에 대하여 반응성을 제공하기 때문에, 

 이것은 특별히 이벤트 처리와 같은 기법을 사용하지 않고도 

 

 쉽게 사용자가 정의한 유효성 검사 오류 메시지를 표시 할 수 있다. 

 

- 모든 삽입과 업데이트의 스키마 검증은 클라이언트와 서버 양측에 자동으로 처리되고,

 빠른 처리와 보안성 모두를 충족 시킨다. 

 

- aldeed:autoform 패키지에는 Collection2 스키마를 이용하여 HTML5 폼을 자동으로 만든다. 

 이 AutoForm은 데이터베이스 조작, 메소드 요청, 검증 그리고 사용자 인터페이스 반응성을 처리하는 

 

 입력 폼을 자동으로 만들어 주는데 

 

 원래는 이벤트 처리 루틴을 작성하여야 하지만 

 

 몇 줄 안되는 작은 마크업 형식의 코딩만으로 처리 할 수 있다.

 

 AutoForm에 대한 자세한 내용은 AutoForm 문서를 참조할 것.

컬렉션에 스키마 적용

--------------------


여러분의 Common.js에 아래와 같이 "books" 라는 이름을 갖는 Books 컬렉션을 만들었다면 


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

SimpleSchema() 함수를 이용하여 다음 예와 같은 형식으로 Books 컬렉션에 대한 스키마를 구성할 수 있다. 

common.js 에 다음과 같이 만들었다고 가정하자. 


var Schemas = {};


Schemas.Book = new SimpleSchema({

title: {

type: String,

label: "Title",

max: 200

},

author: {

type: String,

label: "Author"

},

copies: {

type: Number,

label: "Number of copies",

min: 0

},

lastCheckedOut: {

type: Date,

label: "Last date this book was checked out",

optional: true

},

summary: {

type: String,

label: "Brief summary",

optional: true,

max: 1000

}

});

위 예처럼 SimpleSchema() 의 인스턴스를 만들었다면, 

attachSchema() 메쏘드를 이용해서 컬렉션에 연결 할 수 있다. 

이렇게 하려면 common.js에 아래와 같이 코딩하여야 한다.

Books.attachSchema(Schemas.Book);


이렇게 컬렉션에 스키마를 적용하고 나면, 

다음과 같이 서버나 클라이언트 아무 곳이나 삽입에 대한 유효성을 검증할수 있거나 

Books.insert({title: "Ulysses", author: "James Joyce"}, function(error, result) {

 // Books 컬렉션의 스키마에서  "copies" 는 

 // 삽입에 대하여 반드시 요구 되고 있기 때문에 

 // 이 명령 문장은 삽입에 실패한다 

 // 따라서 error 값이 설정되고, 

 // result 는 삽입 요청에 대한 처리 결과로 undefined 또는 false 값을 갖는다. 

 //

 // 에러에 대한 내용들은 `error.invalidKeys` 을 참조하거나 

 // Books.simpleSchema().namedContext().invalidKeys() 함수를 호출하여 

 // 파악할수 있다. 

});


아니면 업데이트에 대한 유효성을 검증할 수 있다. 


Books.update(book._id, {$unset: {copies: 1}}, function(error, result) {

 // Books 컬렉션의 스키마에서  "copies" 는 

 // 업데이트에 대하여 반드시 요구 되었지만 $unset 을 통해 제외를 요구 했기 때문에 

 // 이 명령 문장은 업데이트에 실패한다 

 // 따라서 error 값이 설정되고, 

 // result 는 삽입 요청에 대한 처리 결과로 undefined 또는 false 값을 갖는다. 

 //

 // 에러에 대한 내용들은 `error.invalidKeys` 을 참조하거나 

 // Books.simpleSchema().namedContext().invalidKeys() 함수를 호출하여 

 // 파악할수 있다. 

});


attachSchema() 옵션

--------------------


(*) 변환처리


유효성 검증에 앞서 컬렉션의 변환 처리가 필요하면, 

attachSchema() 를 사용하여 스키마를 연결할 때 transform 옵션을 true로 설정하면 된다. 


Books.attachSchema(Schemas.Book, {transform: true});

(*) 교체


attachSchema()의 디폴트 동작은 컬렉션에 이전 스키마가 있다면 추가되는 스키마와 합친다. 

이전의 스키마를 버리고 새로운 스키마로 교체하려면 replace 옵션을 true 로 설정하면 된다. 


Meteor.users에 스키마 설정

-------------------------------


솔찍히, 스키마를 적용할 때는 스키마가 뭘 하는지는 모르고 무언가 한다는 것은 말도 안된다. 

만약 Meteor.users에 여러분이 필요한 스키마를 추가 하고 싶다면 

다음 예가 좋은 제안이 될수 있다. 

Schema = {};


Schema.UserCountry = new SimpleSchema({

name: {

type: String

},

code: {

type: String,

regEx: /^[A-Z]{2}$/

}

});


Schema.UserProfile = new SimpleSchema({

firstName: {

type: String,

regEx: /^[a-zA-Z-]{2,25}$/,

optional: true

},

lastName: {

type: String,

regEx: /^[a-zA-Z]{2,25}$/,

optional: true

},

birthday: {

type: Date,

optional: true

},

gender: {

type: String,

allowedValues: ['Male', 'Female'],

optional: true

},

organization : {

type: String,

regEx: /^[a-z0-9A-z .]{3,30}$/,

optional: true

},

website: {

type: String,

regEx: SimpleSchema.RegEx.Url,

optional: true

},

bio: {

type: String,

optional: true

},

country: {

type: Schema.UserCountry,

optional: true

}

});


Schema.User = new SimpleSchema({

username: {

type: String,

regEx: /^[a-z0-9A-Z_]{3,15}$/

},

emails: {

type: [Object],

// Facebook 같은 다른 로그인 서비스를 사용하는 경우 이것은 반드시 옵션처리로 설정해야 한다. 

// 반면에 accounts-password 만 사용하다면 옵션처리를 하면 안된다. 

optional: true

},

"emails.$.address": {

type: String,

regEx: SimpleSchema.RegEx.Email

},

"emails.$.verified": {

type: Boolean

},

createdAt: {

type: Date

},

profile: {

type: Schema.UserProfile,

optional: true

},

services: {

type: Object,

optional: true,

blackbox: true

},

// meteor-roles 패키지를 사용하려면, 스키마에 'roles' 속성을 추가 해야 한다. 

// 이 패키지를 사용할 때 주의 할 점은 ,

// Roles에 사용자를 추가 할 때마다 `Roles.GLOBAL_GROUP` 그룹을 반드시 지정해야 한다는 것이다.

// 예:  Roles.addUsersToRoles(userId, ["admin"], Roles.GLOBAL_GROUP);

// 어떤 경우에는 유효성 검증이 실패를 할 것이므로,그룹이 있든 없든 더하여 혼합하거나 맞출 수 없다

roles: {

type: Object,

optional: true,

blackbox: true

}

});


Meteor.users.attachSchema(Schema.User);


위 예는 account 패키지를 이용할때 어떤 내용이 스키마에 추가 될지 모르기 때문에 

위에 제시된 방법이 완벽한 해법이라고 말하기는 어렵다. 

더욱이, 여러분은 추가하려고 하는 다른 패키지가 부가적인 속성을 설정하려고 할지도 모른다.

만약 위의 같은 형식으로 추가하고 나서 콘솔에 삭제되는 키가 있다고 경고가 표시되면 

그것은 추가된 패키지가 스키마에 추가 할 키가 있다는 것을 알리는 좋은 표시이다. 

간략화 처리를 위해 blackbox 속성에 true 를 설정한 이 스키마에서 주의 할 것은 

더 많은 특별한 스키마를 알아내는 대신 여러분이 기존 것에서 선택해야 할지도 모른다


(좀 더 필요한 Meteor.users 스키마 구조에 대해서 알았다면 , 해당 문서를 요청하는 것에 대하여 환영한다.)


스키마 포맷 

-------------


사용 가능한 모든 스키마 표현 규칙이나 검증 메쏘드에 대한 것들은 simple-schema 패키지의 문서를 참조할 것.


Mongo.Collection 인스턴스에 대한 SimpleSchema 인스턴트 설정 처리는 MyCollection.simpleSchema()를 사용할 것.

For example:

예를 들면 :

check(doc, MyCollection.simpleSchema());

검증 컨텍스트 

-------------


기술된 예에서,

SimpleSchema의 반응형 유효성 검증 메서드를 액세스하기 위해 인수없는 namedContext()가 잠정적으로 

호출되고 있다는 점에 주의 해야 한다. 

컨텍스트는 해당 컬렉션에 대한 유효하지 않은 키들을 여러개로 나뉘어진 목록으로 유지 관리한다. 

일반적으로 디폴트 컨텍스트만을 사용해도 대부분의 실질적인 문제들을 해결 할 수 있다. 

물론 뭘 하는 냐에 따라 달라지기는 한다. 

UI 요소를 업데이트하기 위해서 컨텍스트의 반응형 메소드를 사용하는 경우라면,

여러 컨텍스트를 사용해야할지 모른다. 

예를 들어, 

삽입에 대한 컨텍스트와 업데이트에 대한 컨텍스트를 원하거나,

페이지에 각 폼마다 서로 다른 컨테스트를 원하는 경우가 이에 해당한다. 

특정 이름을 갖는 유효성 검증 컨텍스트를 사용하려면,

삽입 또는 업데이트를 호출할 때 validationContext 옵션을 사용한다. 


Books.insert({title: "Ulysses", author: "James Joyce"}, { validationContext: "insertForm" }, function(error, result) {

 // 에러 목록을 얻고 싶으면 Books.simpleSchema().namedContext("insertForm").invalidKeys()를 호출한다. 

});


Books.update(book._id, {$unset: {copies: 1}}, { validationContext: "updateForm" }, function(error, result) {

 // 에러 목록을 얻고 싶으면 Books.simpleSchema().namedContext("updateForm").invalidKeys()를 호출한다. 

});

삽입 또는 업데이트 없는 유효성 검증

-----------------------------------


실제 삽입 또는 업데이트 처리 없이 문서의 유효성 검증도 가능하다. 


Books.simpleSchema().namedContext().validate({title: "Ulysses", author: "James Joyce"}, {modifier: false});

도큐먼트가 Mongo의 수정 가능한 객체라면 modifier 옵션값을 true로 설정한다. 


도큐먼트의 한개의 키에 대해서도 유효성 검증이 가능하다. 


Books.simpleSchema().namedContext().validateOne({title: "Ulysses", author: "James Joyce"}, "title", {modifier: false});

유효성 검증 메소드중 하나를 호출 할 때도 특정한 유효성 검증 컨텍스트를 지정할 수 있다.


Books.simpleSchema().namedContext("insertForm").validate({title: "Ulysses", author: "James Joyce"}, {modifier: false});

Books.simpleSchema().namedContext("insertForm").validateOne({title: "Ulysses", author: "James Joyce"}, "title", {modifier: false});


이러한 메소들에 대한 좀 더 자세한 내용은 simple-schema 패키지 문서를 참조 할것. 


유효성 검증 없이 삽입 또는 업데이트

----------------------------------------


유효성 검증을 생략하려면, 삽입과 업데이트를 호출하기 전에 validate 옵션을 false 로 설정한다. 

이렇게 설정하면 

신뢰할 수 없는 코드로 볼수 있는 클라이언트의 유효성 검증은 처리되지 않는다. 

신뢰할 수있는 코드로 볼수 있는 서버의 모든 유효성 검증은 생략된다. 

이런 처리에 의해서 객체는 클리어한 상태로 autoValues 처리는 계속된다. 


깔끔하지 않은 삽입 또는 업데이트가 필요할 때 

-------------------------------------------


(*) 스키마에 포함되지 않은 속성 제거에 대한 생략 하고 싶을 때 

객체의 속성 필터링을 생략하려면 삽입 또는 업데이트 할때 filter 옵션을 false 로 설정한다. 


(*) 스키마가 기대하는 것과 매칭되도록 값의 변환을 생략 하고 싶을 때 


자동 값 변환을 생략하려면 삽입 또는 업데이트 할때 autoConvert 옵션을 false 로 설정한다. 


(*) 빈 문자열을 제거 생략 하고 싶을 때 

빈 문자열을 제거를 생략하려면, 삽입 또는 업데이트 할때 removeEmptyStrings 옵션을 false 로 설정한다.


(*) 자동 값을 생성 생략 하고 싶을 때 

자동 값 추가를 생략하려면 삽입 또는 업데이트 할때 getAutoValues 옵션을 false 로 설정한다. 

이 작업은 서버의 코드에서만 동작된다. 


추가적인 SimpleSchema 옵션

-------------------------------


simple-schema 패키지가 다루는 유효성 검사 옵션 말고

이 섹션에서는 collection2 패키지에 추가된 옵션들을 설명한다. 


(*) denyInsert 와 denyUpdate


denyUpdate를 true로 설정한다면, 해당 필드를 수정하는 어떤 컨렉션 업데이트는 실패한다. 

예를 들면 :


var PostSchema = new SimpleSchema({

 title: {

type: String

 },

 content: {

type: String

 },

 createdAt: {

type: Date,

denyUpdate: true

 }

});


Posts = new Mongo.Collection('posts');

Posts.attachSchema(PostSchema);


var postId = Posts.insert({title: 'Hello', content: 'World', createdAt: new Date});

denyUpdate 과 마찬가지로 denyInsert 옵션도 삽입에 대하여 동리한 동작을 한다. 

denyInsert 옵션을 true 로 설정한다면, optional 옵션을 true 로 해야 한다. 

(*) autoValue


autoValue 옵션 기능은 SimpleSchema 패키지에서 자세한 사용법과 함께 제공하는 기능이다. 

Collection2 는 C2 데이터베이스 작업중에 호출되는 autoValue함수에 대하여  다음과 같은 속성을 지원한다. 

* isInsert: 삽입 작업이면 이 값은 True 이다. 

* isUpdate: 업데이트 작업이면 이 값은 True 이다.

* isUpsert: 업서트 작업이면 이 값은 True 이다. (upsert () 또는 upsert : true 중 하나)

* userId: 현재 로그인 한 사용자의 ID. (서버 시작시에는 항상 null)

* isFromTrustedCode :  신뢰할 수있는 (서버) 코드의 초기화 과정중에 삽입, 업데이트 또는 업서트 작업이면 이 값은 True 이다.

* docId: 업데이트 중인 도큐먼트 _id. 

        이값은 셀렉터가 _id를 포함했을 때이거나 클라이언트가 초기화 처리를 할때에 

 

업데이트 또는 업서트 에 작업에 대해서만 설정된다.


autoValue 함수는 유효성 검사 목적으로 클라이언트에서 수행되고,

저장된 실제 값은 항상 서버에서 생성되어진다는 점을 주의해야 한다. 

autoValue는 삽입/업데이트에 상관없이 클라이언트나 서버로부터 초기화된다.


autoValue에 대한 많은 사용 가능성 사례가 있는데 

다음 예와 같이 여러 가지 예로 하는 것이 대체로 가장 쉽게 설명 될 듯 싶다. 


{

 // 삽입시에 현재 시간을(서버 시간) 설정하고 나서 업데이트 동작을 금지한다. 

 createdAt: {

type: Date,

 autoValue: function() {

if (this.isInsert) {

 return new Date;

} else if (this.isUpsert) {

 return {$setOnInsert: new Date};

} else {

 this.unset();

}

 }

 },

 // 업데이트시에 현재 시간을(서버 시간) 설정하고 나서 삽입시 설정을 금지한다. 

 updatedAt: {

type: Date,

autoValue: function() {

 if (this.isUpdate) {

return new Date();

 }

},

denyInsert: true,

optional: true

 },

 // content 필드가 업데이트 될때 마다 자동적으로 firstWord 필드에 content 필드이 첫번째 단어를 설정한다. 

 firstWord: {

type: String,

optional: true,

autoValue: function() {

 var content = this.field("content");

 if (content.isSet) {

return content.value.split(' ')[0];

 } else {

this.unset(); // Prevent user from supplying her own value

 }

}

 },

 // content 필드가 업데이트 될때마다 자동적으로 history 배열을 업데이트 한다. 

 updatesHistory: {

type: [Object],

optional: true,

autoValue: function() {

 var content = this.field("content");

 if (content.isSet) {

if (this.isInsert) {

 return [{

 date: new Date,

 content: content.value

}];

} else {

 return {

$push: {

 date: new Date,

 content: content.value

}

 };

}

 } else {

this.unset();

 }

}

 },

 'updatesHistory.$.date': {

type: Date,

optional: true

 },

 'updatesHistory.$.content': {

type: String,

optional: true

 },

 // 마크다운 컨텐트가 설정될때마다 자동적으로 HTML 컨텐트로 변환된다. 

 htmlContent: {

type: String,

optional: true,

autoValue: function(doc) {

 var markdownContent = this.field("markdownContent");

 if (Meteor.isServer && markdownContent.isSet) {

return MarkdownToHTML(markdownContent.value);

 }

}

 }

}

(*) index 와 unique


특정 필드에 MongoDB의 인덱스처리를 하기 위해서는 index 옵션을 사용한다. 


{

 title: {

type: String,

index: 1

 }

}

오름차순 인덱스일 경우에는 1 또는 true 로 설정한다. 

내림차순 인덱스일 경우에는 -1 로 설정한다. 

이런 형식 뿐만 아니라 "2d" 같은 특별한 MongoDB 인덱스 타입에 대해서도 설정할 수 있다. 

또한 인덱스 처리는 하위 내장 도큐먼트 대해서도 동작한다.


실수로 필드에 인덱스를 작성하였다가, 그것을 삭제하고 싶으면, index를 false로 설정한다. 


{

 "address.street": {

type: String,

index: false

 }

}


unique 옵션이 true 로 설정 되어 있는 필드가 있다면 MongoDB 인덱스는 unique 인덱스가 될 것이다. 

이런 unique 서버측에서 동작하는 Collection2 처리는 해당 필드의 고유성을 체크하기 위해서 MongoDB 에서 제공하는 기능에 의존한다. 

이것은 직접 체크하는 것보다 효과적이다. 

{

 "pseudo": {

type: String,

index: true,

unique: true

 }

}

unique 옵션 처리를 하기 위해서는 반드시 index 옵션을 true, 1, -1 중 하나로 설정하여야 한다. 

고유성 검사에 관련된 에러 메시지는 매우 일반적 메세지로 이루어져 있다. 


MyCollection.simpleSchema().messages() 함수를 사용하면 

원하는 좀 더 나은 에러 메세지를 표출할 수 있다.

에러 타입 문자열은 "notUnique" 이다.

인덱싱처리 과정이 다른 데이터베이스 쿼리를 차단하지 않도록 

인덱스와 관련된 처리는 백그라운드로 처리된다. 


(*) custom


SimpleSchema 패키지는 custom 옵션을 제공하고 관련된 설명 문서 역시 패키지에 포함되어 있다. 

C2 데이터베이스 작업중에 호출되는 custom 함수에 대하여 Collection2 는 아래와 같은 속성을 지원한다. 


* isInsert: 삽입 작업이면 이 값은 True 이다. 

* isUpdate: 업데이트 작업이면 이 값은 True 이다.

* isUpsert: 업서트 작업이면 이 값은 True 이다. (upsert () 또는 upsert : true 중 하나)

* userId: 현재 로그인 한 사용자의 ID. (서버 시작시에는 항상 null)

* isFromTrustedCode :  신뢰할 수있는 (서버) 코드의 초기화 과정중에 삽입, 업데이트 또는 업서트 작업이면 이 값은 True 이다.


* docId: 업데이트 중인 도큐먼트 _id. 

        이값은 셀렉터가 _id를 포함했을 때이거나 클라이언트가 초기화 처리를 할때에 

업데이트 또는 업서트 에 작업에 대해서만 설정된다.


도큐먼트가 유효하지 않을 경우는 어떤일이 일어나나?

--------------------------------------------------


삽입 또는 업데이트 함수 호출시에 마지막 인자로 지정한 콜백함수는 

에러를 처리할수 있도록 첫번째 인자(error)에 에러 인스턴스를 제공한다. 

유효하지 않은 첫번째 키와 관련된 오류 메시지는 error.message 에 설정되고,

invalidKeys 전체 배열은 error.invalidKeys 에 설정된다. 

    도큐먼트가 유효하지 않는 것이 서버에서 확인 될 때까지,

클라이언트가 시작한 작업에 대한 유효성 검사가 실패하지 않더라도 

클라이언트와 서버 모두에서 처리된다. 


서버 코드에서 동기화를 시도할 때는 

처리할 콜백이 없기 때문에 같은 검증 오류가 발생된다. 

Meteor.methods 를 이용하여 정의된 서버 메소드에서 이런일이  발생하면, 

Meteor.Error는 클라이언트 콜백을 통해 전달된다. 

이 에러는 invalidKeys 속성를 가지지 않는다. 

대신 error.reason에 설정된 첫 번째 유효하지 않은 키에 대한 에러 메세지를 가진다. 

보통 이곳에 표시된 Error 는 사용되지 않고 

UI 어딘가에서서 사용자에게 해당 에러 메세지를 표시하기 위해서 

SimpleSchema 유효성 검사 컨텍스트가 제공하는 반응형 메쏘드를 대신 사용한다. 

autoform 패키지는 이런 목적을 위해 UI 컴포넌트와 헬퍼를 제공한다. 


좀 더 자세한 내용들 

-------------------


좀 더 깊은 동작 원리에 관심있는 분들을 위해서, 

아래에 Collection2가 매번 삽입 또는 업데이트를 하기 전에 정확히 뭘 하는지 설명할 것이다. 


1. 명시적으로 스키마에 나열되어 있지 않다면, 

  도큐먼트나 Mongo의 한정자 객체에서 속성을 제거한다. 

  

  (이것을 생략하려면 , 삽입 또는 업데이트를 호출 할 때 filter 옵션에 false 를 설정한다.)

2. 가능하면, 자동으로 스키마가 기대하는 것과 일치하도록 몇 가지 속성을 변형한다. 

  (이것을 생략하려면 , 삽입 또는 업데이트를 할때 autoConvert 옵션에 false 를 설정한다.)

3. 빈 문자열 값이 저장되지 않도록, 최적화 한다. 

  (이것을 생략하려면 , 삽입 또는 업데이트를 할때 removeEmptyStrings 옵션에 false 를 설정한다.)

4. 여러분의 스키마를 근거로 자동(강제 또는 디폴트)값을 추가한다.

  값은 서버에서만 추가되고 클라이언트에서 구독이 업데이트 될 때 실제 데이터가 전달된다. 

  

  (서버 코드에서 이것을 생략하려면 , 삽입 또는 업데이트를 할때 getAutoValues 옵션에 false 를 설정한다.)

5. 도큐먼트나 Mongo의 한정자 객체에 대한 유효성 검증를 한다 

  (이것을 생략하려면 , 삽입 또는 업데이트를 할때 validate 옵션에 false 를 설정한다.)

6. 유효성 검증에 문제가 없다면 평상시처럼 삽입 또는 업데이트를 처리한다. 


Collection2는 이런 일을 하도록 SimpleSchema 메소드를 간단히 호출하고 있다.

클라이언트 초기화 처리에 대하여 유효성 검증은 클라이언트 와 서버 양쪽에서 발생하며,

서버측 유효성 검증의 보안적측면과 더블어 클라이언트 측의 유효성 검증의 신속성을 보장한다. 


문제점?

---------


여러분은 마치 검증이 제대로 작동하지 않는 것처럼 보이는 상황을 겪을지도 모른다.

이럴땐 먼저, 

어떤 추가적인 정보를 로그하기 위해서 SimpleSchema.debug = true 문장을 통하여 

SimpleSchema 디버그 모드를 활성화 한다. 

그럼에도 불구하고 여전히 제가 해결되지 않는다면, 

다음과 같은 까다롭고, 혼란스런 상황을 통해 이해해 보자. 

(*) 서브 객체와 객체 배열


Collection2 와 SimpleSchema 대해 알기 위한 중요한 것 중 하나는 

요청된 도큐먼트 삽입이나 업데이트 한정자 보다도 

저장된 도규먼트에 대한 유효성 검증을 더 하지 않는다는 것이다. 

업데이트의 경우에, 

변경하고자하는 배열 객체가 이미 존재하는지 여부 등 같은 

SimpleSchema가 모르는 어떤 정보가 있다는 것을 의미한다.

만약 없다면, MongoDB는 새로 생성한다. 

그리고 SimpleSchema는 보수적인 방식으로 검사한다. 

그것은 한정자에 의해 어떤 속성도 설정되지 않고 업데이트 후에 존재하지 않는다는 것을 의미한다. 

이것은  동일한 개체에서 필요한 키가 업데이트 한정자에 명시적으로 설정되어 않는다면,

한정자가 무효화 된다는 것을 의미한다. 


예를 들어, 

"books" 스키마에 다음과 같은 형식의 키들을 추가 한다고 할 때 

{

borrowedBy: {

type: [Object]

},

"borrowedBy.$.name": {

type: String

},

"borrowedBy.$.email": {

type: String,

regEx: SimpleSchema.RegEx.Email

},

}


borrowedBy 배열에 있는 모든 객체는 name 과 email 속성를 가져야 한다. 


자 이제 전자 메일 주소가 정확하지만 항목 1 의 name 에 잘못된 것을 발견한다고 하자.


그래서 다음과 같이 올바른 값으로 name 만을 설정 하고자 했다 


Books.update(id, {$set: {"borrowedBy.1.name": "Frank"}});

그러나 이것은 유효성 검증을 통과 하지 못한다. 

왜냐하면, 이미 존재하는 borrowedBy 배열에 항목 1이 있는지를 알 수 없기 때문이다. 

그래서 업데이트가 완료 된 후 email 속성이 요구되는지도 알 수 가 없을 것이다. 


이런 상황을 만드는 세가지 경우가 있다. 


* $set 전체 객체 

* $set 객체에서 필요한 모든 키

    * 서버에서 업데이트를 실행하고, 유형성 검사를 생략하기 위한 validate 옵션을 false 하는 것을 무시한 경우 

autoForm에서 클라이언트 측에서 이런 상황이 발생했을 때,

대개는 어떤 문제도 발생하지 않는다. 

전체 객체에 $set 한정장에 대하여 AutoForm은 생각보다 똑똑하게 처리하고,

이 잠재적인 이슈를 알아차리기 때문이다.

그러나,

이것은 모든 요청된 속성들이 form 의 input 태그에 표현되어지는 것을 확실하게 할 필요가 있다는 의미이다.

 

위 예에서,

borrowedBy의 name 의 변경에 대하여 필드가 보여지고 email은 그렇지 않도록 하고 싶은 autoForm을 원한다면, 

email 필드는 숨겨진 상태로 만들고 두 필드를 포함하여야 한다. 

다른 방법으로는,

autoForm을 서버의 메쏘드로 제출하고, 유효성 검증없이 서버에서 업데이트를 할 수 있다. 

이 예제에서는 객체의 배열에 포커스를 맞추고 있지만, 하위 개체는 기본적으로 같은 방법으로 취급되어진다. 

기여하기

------------


이 프로젝트에 기여하고자 하는 모든 분들을 환영합니다. 

Fork, make and test your changes (mrt test-packages ./), 

and then submit a pull request.


주요 기여자들 

-------------


@mquandalle


(여러분을 이곳에 나열하고 싶으면 여기에 추가 하세요)