0.3.9 • Published 4 years ago

mares-mongoose-model v0.3.9

Weekly downloads
-
License
ISC
Repository
-
Last release
4 years ago

mares-mongoose-model

슬로그업에서 사용하는 node.js DDD패턴 구현 시 필요합니다. mongoose 모델 생성시 반드시 해당 모듈을 상속받아야 합니다.

Installation

npm install --save mares-mongoose-model

Examples

const MaresMongooseModel = require('mares-mongoose-model')

// 다음과 같이 몽구스 모델을 상속받아 추가 함수를 구현해서 사용합니다.
class TestModel extends MaresMongooseModel {  
	/**
	 * 문자열로 몽구스 프로젝션에 필요한 필드를 정의합니다.
	 * @override
	 */
	static getAttributes() {  
		return 'id a b' 
	} 
	
	/**
	 * 다음함수는 기본 몽구스의 함수를 오버라이딩 하는 경우입니다.
	 * @override
	 * @static
	 */
	static findById() {
		//todo
	}
	
	static doSomething() {}  
}  

Action

모든 개발 패턴을 통일하기 위하여 에러핸들링, parameter 핸들링, return data의 정규화 등을 내부 지정된 함수를 이용해서 조작해야 합니다.

Mongoose error object handling

몽구스에서 나는 모든 에러는 catch 후 해당 함수를 통해서 전파해야 합니다. 내부적으로 throw를 하기 때문에 명시적으로 throw를 적을 필요가 없습니다.

class TestModel extends MaresMongooseModel {  
    static doSomething() {  
        try { 
            // call mongoose built-in method
        } catch (e) {
            this.throwRefineError(e)  
        }
    }
}  

404 error handling

데이터가 없는 경우 404에러를 throw 해줍니다.

class TestModel extends MaresMongooseModel {  
	static async doSomething() {  
		let data = await get()  
		if (data === null) {
			// 데이터가 없다면 바로 404 error를 throw한다.
			this.throwNotfoundError()
		} 
	}
}  

Parameter normalization

infra / repository 에는 domain layer의 PO가 넘어오는 경우가 많기 때문에 반드시 일반객체로 정규화 한 후 사용해야 합니다.

class TestModel extends MaresMongooseModel {  
	static async doSomething(domainObject) {
	  
		// object 인경우
		let pureObject = this.cleanObject(domainObject)
		
		// array 인경우
		let pureArray = this.cleanArray(domainObject)
	}
}  

Return mongoose object

mongoose object를 pure함수를 통해 po로 변형 후 return 해야 합니다.

class TestModel extends MaresMongooseModel {  
	static async doSomething(domainObject) {  
		let data = await get()  
		return this.toPure(data)
	}
}  

Get projection query

몽고디비의 프로젝션에 필요한 쿼리를 만들어 줍니다. 해당 함수는 내부적으로 getAttributes() 함수를 이용합니다.

class TestModel extends MaresMongooseModel {
	static getAttributes() {
		return 'id test value app.a app.b app.c.a app.c.b'  
	}
	static async doSomething(domainObject) {  
		let data = await get()  
		let projection = this.getProjection('', 'prefix') //빈문자열을 이용하면 getAttributes 함수를 이용합니다.
		/**
		 * prjection 객체는 다음과 같이 변환됩니다. 
		 * {
		 *  	'prefix.id': 1,  
		 *  	'prefix.test': 1,  
		 *  	'prefix.value': 1,  
		 *  	'prefix.app.a': 1,  
		 *  	'prefix.app.b': 1,  
		 *  	'prefix.app.c.a': 1,  
		 *  	'prefix.app.c.b': 1
		 * }
		 */
		// todo
	}
}  

Build group query

조인을 위한 쿼리를 생성하기 위한 함수를 제공합니다. 몽구스에서 조인을 하게 되면, 응답형태를 다시 객체로 만들어야 하는데 이를 자동으로 해주는 함수를 제공합니다. 아래는 order-orderItem-inventory 3개를 조인하는 예제코드 입니다. (왼쪽에서 부터 오른쪽으로 1:N 관계입니다.)

class TestModel extends MaresMongooseModel {
	static async findFullOrder(appKey, order, orderItem = null) {
		// 최초 모든 프로젝션 값을 얻어옵니다.
		const orderItemAttr = mongoose.models.OrderItem.getAttributes()  
		const inventoryAttr = mongoose.models.Inventory.getAttributes()  
		const orderAttr = this.getAttributes()  
		
		// 쿼리작성을 시작합니다.
		let aggregateQuery = []
		
		// 먼저 appKey라는 필드를 검색합니다.
		aggregateQuery.push({  
            $match: {  
                appKey  
            }  
		})
		
		// join을 합니다. $lookup 키워드를 이용합니다.
		// from은 N관계의 join할 컬렉션명입니다.
		// foreignField는 OrderItem에서 들고있는 외래키의 이름입니다.
		// localField는 order의 고유키입니다. (primary Key)
		// as는 해당 N관계의 값들이 포함될 필드명입니다. 아래 배열로 들어갑니다.
		aggregateQuery.push({  
            $lookup: {  
                from: 'OrderItem',  
                foreignField: 'order',  
                localField: '_id',  
                as: 'orderItems'  
            }  
		})
		
		// unwind를 하게 되면 orderItems안의 배열의 값들이 모두 펼쳐지면서 각각의 로우로 변경됩니다. orderItems를 들고 있는 객체의 모든 필드는 중복됩니다.
		aggregateQuery.push({$unwind: '$orderItems'})  
		
		aggregateQuery.push({  
            $match: {  
                'orderItems.canceledAt': {$exists: false},  
            }  
		})  
		
		aggregateQuery.push({  
            $lookup: {  
                from: 'Inventory',  
                foreignField: 'orderItem',  
                localField: 'orderItems._id',  
                as: 'orderItems.inventories'  
            }
		})  
		aggregateQuery.push({$unwind: '$orderItems.inventories'})  
		aggregateQuery.push({  
            $match: {  
                'orderItems.inventories.canceledAt': {$exists: false}  
            }  
		})  
		aggregateQuery.push({$limit: 1})

		// buildGroupQuery를 이용하여 실제로 그룹핑을 위한 쿼리를 만듭니다.
		// 앞에 문자열은 root collection명을 제외한 depth 구조입니다. 닷(점)으로 구분합니다. 또한 최종 lookup 구문의 as와 동일합니다.
		// 두번째 인자는 프로젝션 스트링 값입니다. 만일 위에 depth의 닷이 1개라면 총 3개의 프로젝션 값이 필요합니다.
		aggregateQuery = [...aggregateQuery, ...this.buildGroupQuery('orderItems.inventories', [orderAttr, orderItemAttr, inventoryAttr])]  
		try {  
            let orders = await this.aggregate(aggregateQuery)  
            if (!orders || orders.length === 0) this.throwNotfoundError()  
            return this.toPure(orders[0])  
		} catch (e) {  
            this.throwRefineError(e)  
		}  
	}
}

Remove null fields

클라이언트에서 생성시(POST) 생성할 필드가 없을때 null을 보낼 수 있는데 이때 null 값을 모두 제거하여 생성시 $set의 필드에 null이 들어가는 것을 방지하기 위한 함수 입니다.

class TestModel extends MaresMongooseModel {
	static async doSomething(domainObject) {  
		// obj의 null값을 제거해줍니다.
		// 만일 모든 sub object 혹은 sub array의 값이 모두 null이면 해당 객체나 배열은 단순 null로 바뀝니다.
		// 두번째 인자는 undefined or {}, []값을 없애줄지 여부 입니다.
		this.removeNullFields(obj, true)
	}
}  

Generate unset query

값을 수정할 때 null을 보내면 해당 필드를 unset으로 제거하여 주고 싶을 때 사용합니다.

class TestModel extends MaresMongooseModel {
	static async doSomething(domainObject) {  
		// null 값을 찾아서 unset 쿼리를 만들어 줍니다.
		// 두번째 인자는 unset 쿼리 객체를 만들 때 배열의 원소까지 체크할지 여부입니다. 만일 true 라면 'array.0.a' 와같은 형태로 만들어 주며, false일 경우에는 해당 array 키값을 무시합니다.
		this.toUnsetFromNullFields(obj, true)
	}
}  
0.3.9

4 years ago

0.3.8

4 years ago

0.3.7

5 years ago

0.3.6

5 years ago

0.3.5

5 years ago

0.3.4

5 years ago

0.3.3

5 years ago

0.3.2

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.0

5 years ago

0.1.0

5 years ago

0.0.3

5 years ago