고객들은 종종 MongoDB에서 Couchbase로 마이그레이션을 준비 중이라고 말합니다. 그 이유는 부분적으로는 MongoDB 쿼리 방법을 배우면서 겪었던 문제에 지쳤기 때문입니다. 특히 최신 애플리케이션을 확장하는 데 있어 N1QL이 포함된 Couchbase가 더 나은 대안을 제공합니다.
안타깝게도 몽고DB를 사용하면 마이그레이션 옵션이 제한될 수 있습니다. 제가 최근에 작성한 마이그레이션 옵션 중 하나는 에서 몽구스를 사용한 MongoDB에서 오스만을 사용한 카우치베이스로의 전환. 이 튜토리얼의 핵심은 동일한 API를 공유하는 Node.js에서 서로 다른 두 가지 ODM 도구를 사용하여 거의 원활하게 전환하는 것이었습니다. 하지만 MongoDB에서 ODM을 사용하지 않고 있고 관심이 없는 경우에는 어떻게 해야 할까요?
이번에는 MongoDB와 MongoDB 쿼리 언어를 사용하는 Node.js 애플리케이션을 N1QL을 사용하여 Couchbase로 옮기는 방법을 살펴보겠습니다. 간단히 말해, N1QL은 복잡한 JSON 데이터에 대해 SQL 쿼리를 실행할 수 있는 기술입니다. 따라서 사용하기 쉬울 뿐만 아니라 애플리케이션 계층에서 매우 깔끔하게 사용할 수 있습니다. N1QL에 대한 자세한 내용은 카우치베이스 개발자 포털.
예제 문제에서 사용된 것과 동일한 예제 문제를 사용하겠습니다. 이전 기사를 보셨겠지만 못 보셨더라도 괜찮습니다. 여기의 모든 것은 깨끗한 백지 상태에서 시작됩니다.
요구 사항
이 가이드를 성공적으로 사용하려면 몇 가지 요구 사항을 충족해야 합니다. 다음과 같이 볼 수 있습니다:
MongoDB와 Couchbase를 모두 살펴볼 것이므로 두 데이터베이스를 모두 사용할 수 있어야 합니다. 이미 MongoDB 개발자이시라면 많은 부분이 익숙하실 수도 있지만, 그것은 여러분의 선택입니다.
NoSQL 데이터 모델 이해
두 기술 중 하나를 사용하여 RESTful API를 개발하기 전에 먼저 사용할 데이터 모델을 이해하는 것이 좋습니다.
MongoDB와 Couchbase는 모두 문서 데이터베이스이지만 완전히 동일하지는 않습니다. MongoDB는 데이터를 BSON으로 저장하는 반면, Couchbase는 데이터를 JSON으로 저장합니다. 모델링 관점에서 볼 때 이는 크게 중요하지 않습니다.
학생이 있고 코스가 있는 학교의 데이터 모델을 예로 들어 보겠습니다. 학교에서 제공되는 모든 코스에 대해 다음과 같은 문서가 있을 수 있습니다:
1 2 3 4 5 6 7 8 9 10 |
{ "id": "course-1", "type": "코스", "이름": "컴퓨터 과학 101", "학기": "F2017", "학생": [ "student-1", "student-2" ] } |
각 코스에는 등록한 모든 학생의 목록이 유지됩니다. 이 경우 목록은 다른 문서를 참조하는 ID 값으로 구성됩니다. 우리는 자체 문서 관계를 설정하고 있습니다.
학교의 모든 학생에게는 다음과 같은 NoSQL 문서가 있을 수 있습니다:
1 2 3 4 5 6 7 8 9 10 |
{ "id": "student-1", "type": "학생", "이름": "닉", "성": "라보이", "코스": [ "course-1", "course-25" ] } |
위의 문서가 코스 모델링 방식과 유사하다는 것을 알 수 있습니다. 각 학생은 자신이 등록한 모든 코스의 목록을 유지합니다. 이러한 코스는 해당 코스 문서를 참조하는 ID입니다.
문서를 모델링하는 방법은 수백 가지가 있으며, 이것은 한 가지 예일 뿐입니다. 데이터 모델링에 대한 자세한 내용은 다음을 참조하세요. 문서.
이제 문서에 대한 모델이 생겼으니 각 기술로 API를 구축하는 데 집중할 수 있습니다.
MongoDB 쿼리 언어로 API 개발하기
자체 MongoDB 애플리케이션 코드가 있을 수 있지만, 마이그레이션을 매우 쉽게 이해할 수 있도록 처음부터 새로 만들겠습니다.
명령 프롬프트 또는 터미널에서 새 프로젝트를 생성하는 것으로 시작하겠습니다:
1 2 |
npm init --y npm 설치 express body-파서 mongodb --저장 |
위의 명령은 새로운 package.json 파일을 열고 필요한 프레임워크 및 데이터베이스 종속성을 설치합니다.
결국, 우리는 MongoDB 프로젝트가 다음과 같은 구조를 갖기를 원합니다:
1 2 3 4 5 6 7 8 9 |
app.js 경로/ courses.js students.js models/ student.js course.js package.json node_modules/ |
데이터베이스와의 모든 상호 작용은 각 데이터베이스에서 이루어집니다. 모델 에서 모든 API 라우팅 및 클라이언트와의 상호 작용을 수행합니다. 경로 파일에 저장합니다. 애플리케이션을 부트스트랩하고 데이터베이스에 연결하는 작업은 애플리케이션의 app.js 파일을 만듭니다.
애플리케이션 내에서 MongoDB 데이터베이스 모델 만들기
이제 데이터베이스 모델 중 하나를 살펴보겠습니다. 프로젝트의 models/course.js 파일을 열고 다음 코드를 포함하세요:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
var 데이터베이스 = require("../../app").데이터베이스; var ObjectId = require("mongodb").ObjectId; 함수 코스 모델() { }; 코스 모델.저장 = 함수(데이터, 콜백) { 데이터베이스.컬렉션("코스").insertOne(데이터, 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); }); } 코스 모델.업데이트학생 = 함수(id, 학생, 콜백) { 데이터베이스.컬렉션("코스").updateOne({ "_id": new ObjectId(id) }, { $set: { "students": 학생 } }, 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); } ); } 코스 모델.getById = 함수(documentId, 콜백) { var 커서 = 데이터베이스.컬렉션("코스").집계([ { "$match": { "_id": new ObjectId(documentId) } }, { "$unwind": { "경로": "$students", "보존Null및비어있는 배열": true } }, { "$lookup": { "from": "students", "localField": "students", "foreignField": "_id", "as": "학생 개체" } }, { "$unwind": { "경로": "$학생 개체", "보존Null및비어있는 배열": true} }, { "$group": { "_id": { "_id": "$_id", "name": "$name" }, "students": { "$push": "$학생 개체" } }}, { "$project": { "_id": "$_id._id", "name": "$_id.name", "students": "$students" } }, { "$limit": 1 } ]); 커서.toArray(콜백); }; 코스 모델.getAll = 함수(콜백) { var 커서 = 데이터베이스.컬렉션("코스").집계([ { "$unwind": { "경로": "$students", "보존Null및비어있는 배열": true} }, { "$lookup": { "from": "students", "localField": "students", "foreignField": "_id", "as": "학생 개체" } }, { "$unwind": { "경로": "$학생 개체", "보존Null및비어있는 배열": true} }, { "$group": { "_id": { "_id": "$_id", "name": "$name" }, "students": { "$push": "$학생 개체" } }}, { "$project": { "_id": "$_id._id", "name": "$_id.name", "students": "$students" } } ]); 커서.toArray(콜백); }; 모듈.수출 = 코스 모델; |
위의 데이터베이스 모델에는 많은 일이 일어나고 있습니다. 이해하기 쉽도록 세분화해야 합니다. 더 많이 이해할수록 Couchbase로의 마이그레이션 프로세스가 더 쉬워집니다.
문서를 저장하고자 할 때는 저장
메서드를 사용합니다:
1 2 3 4 5 6 7 8 |
코스 모델.저장 = 함수(데이터, 콜백) { 데이터베이스.컬렉션("코스").insertOne(데이터, 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); }); } |
개방형 데이터베이스를 사용하여 단일 문서를 원하는 컬렉션에 삽입할 수 있습니다. insertOne
함수입니다. 이 함수에서는 다음을 전달합니다. 데이터
저장하려는 복잡한 자바스크립트 객체가 될 수 있습니다. 저장되면 결과는 이를 호출한 부모 메서드로 반환됩니다.
이미 존재하는 문서를 업데이트하려면 어떻게 해야 할까요? 특히 이미 존재하는 코스에 학생을 추가하려면 어떻게 해야 할까요?
이 특정 예제에서는 전체 학생
배열을 사용할 수 있습니다:
1 2 3 4 5 6 7 8 9 10 11 12 |
코스 모델.업데이트학생 = 함수(id, 학생, 콜백) { 데이터베이스.컬렉션("코스").updateOne({ "_id": new ObjectId(id) }, { $set: { "students": 학생 } }, 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); } ); } |
위의 코드는 updateOne
메서드를 사용하여 특정 문서를 ID로 조회하고 학생
배열을 통해 제공하는 새로운 배열로 대체합니다. 업데이트학생
함수입니다.
아직까지 너무 어렵지도 않고 개발자에게 실질적인 스트레스를 주는 일도 없습니다.
여기서부터 상황이 달라집니다. 데이터를 저장할 때는 ID 값의 배열을 저장합니다. 이것은 쿼리 작업에서 보고자 하는 데이터가 아닙니다. 대신 이러한 ID 값을 해당 문서에 해당하는 값으로 채우거나 확장하려고 합니다:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
코스 모델.getAll = 함수(콜백) { var 커서 = 데이터베이스.컬렉션("코스").집계([ { "$unwind": { "경로": "$students", "보존Null및비어있는 배열": true} }, { "$lookup": { "from": "students", "localField": "students", "foreignField": "_id", "as": "학생 개체" } }, { "$unwind": { "경로": "$학생 개체", "보존Null및비어있는 배열": true} }, { "$group": { "_id": { "_id": "$_id", "name": "$name" }, "students": { "$push": "$학생 개체" } }}, { "$project": { "_id": "$_id._id", "name": "$_id.name", "students": "$students" } } ]); 커서.toArray(콜백); }; |
이를 가능하게 하려면 먼저 배열을 평평하게 만들기 위해 $unwind
를 통해 가입하고 $조회
연산이 필요합니다. 여기서 멈추지 않는 이유는 결과의 서식을 동일한 방식으로 지정하고 개체의 ID만 바꾸고 싶기 때문입니다. 이 때문에 추가 평탄화, 그룹화 및 조작을 수행해야 합니다.
MongoDB의 데이터 조인과 Couchbase의 데이터 조인에 대한 전체 설명은 다음 문서에서 확인할 수 있습니다. 이전에 작성한 철저한 기사 주제에 대해 설명합니다.
간단히 말해, 데이터가 복잡할수록 집계 쿼리도 더 복잡해집니다. 유연한 데이터 모델의 경우 애플리케이션 개발자에게는 그다지 유연하지 않습니다.
학생 데이터를 관리할 다른 모델에 대해 간단히 살펴보겠습니다. 프로젝트의 models/student.js 파일을 열고 다음 자바스크립트 코드를 포함합니다:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
var 데이터베이스 = require("../../app").데이터베이스; var ObjectId = require("mongodb").ObjectId; 함수 학생 모델() { }; 학생 모델.저장 = 함수(데이터, 콜백) { 데이터베이스.컬렉션("students").insertOne(데이터, 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); }); } 학생 모델.업데이트 코스 = 함수(id, 코스, 콜백) { 데이터베이스.컬렉션("students").updateOne({ "_id": new ObjectId(id) }, { $set: { "코스": 코스 } }, 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); } ); } 학생 모델.getById = 함수(documentId, 콜백) { var 커서 = 데이터베이스.컬렉션("students").집계([ { "$match": { "_id": new ObjectId(documentId) } }, { "$unwind": { "경로": "$courses", "보존Null및비어있는 배열": true } }, { "$lookup": { "from": "코스", "localField": "코스", "foreignField": "_id", "as": "courseObjects" } }, { "$unwind": { "경로": "$courseObjects", "보존Null및비어있는 배열": true } }, { "$group": { "_id": { "_id": "$_id", "name": "$name" }, "코스": { "$push": "$courseObjects" } }}, { "$project": { "_id": "$_id._id", "name": "$_id.name", "코스": "$courses" } }, { "$limit": 1 } ]); 커서.toArray(콜백); }; 학생 모델.getAll = 함수(콜백) { var 커서 = 데이터베이스.컬렉션("students").집계([ { "$unwind": { "경로": "$courses", "보존Null및비어있는 배열": true } }, { "$lookup": { "from": "코스", "localField": "코스", "foreignField": "_id", "as": "courseObjects" } }, { "$unwind": { "경로": "$courseObjects", "보존Null및비어있는 배열": true } }, { "$group": { "_id": { "_id": "$_id", "이름": "$firstname", "성": "$lastname", "주소": "$address" }, "코스": { "$push": "$courseObjects" } }}, { "$project": { "_id": "$_id._id", "이름": "$_id.firstname", "성": "$_id.lastname", "주소": "$_id.address", "코스": "$courses" } } ]); 커서.toArray(콜백); }; 모듈.수출 = 학생 모델; |
위의 모델과 코스 데이터를 나타내는 모델에는 거의 동일한 규칙이 적용됩니다. 이는 두 문서 모델이 처음부터 매우 유사했기 때문입니다. 대부분의 경우 ID 값 배열로 평평합니다.
이제 이러한 데이터베이스 메서드를 사용하는 API 엔드포인트를 살펴봅니다.
애플리케이션을 위한 RESTful API 경로 만들기
이것은 데이터베이스에 종속되지 않기 때문에 가장 쉬운 부분이며 실제로 두 데이터베이스 기술 간에 가장 일관성이 있는 부분입니다.
이 프로젝트의 routes/courses.js file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
var 코스 모델 = require("../모델/코스"); var 라우터 = 함수(앱) { 앱.get("/courses", 함수(요청, 응답) { 코스 모델.getAll(함수(오류, 결과) { 만약(오류) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": 오류}); } 응답.보내기(결과); }); }); 앱.get("/코스/:ID", 함수(요청, 응답) { 코스 모델.getById(요청.매개변수.id, 함수(오류, 결과) { 만약(오류) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": 오류}); } 응답.보내기(결과[0]); }); }); 앱.post("/courses", 함수(요청, 응답) { 만약(!요청.body.이름) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": "`이름`이 필요합니다."}); } 코스 모델.저장(요청.body, 함수(오류, 코스) { 만약(오류) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": 오류}); } 응답.보내기(코스); }); }); } 모듈.수출 = 라우터; |
위 코드에는 세 가지 API 경로가 있습니다. 외부 클라이언트에서 모든 코스를 나열하거나, 특정 코스를 찾거나, 새 코스를 저장할 수 있습니다.
어떤 엔드포인트에 도달하느냐에 따라 적절한 데이터베이스 모델 함수가 실행됩니다. 이름에 따라 라우팅 전용인 경로에서는 많은 작업이 수행되지 않습니다.
다른 라우팅 파일은 조금 다를 것입니다. 프로젝트의 경로/학생.js 파일을 열고 다음 자바스크립트 코드를 포함합니다:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
var 학생 모델 = require("../모델/학생"); var 코스 모델 = require("../모델/코스"); var 라우터 = 함수(앱) { 앱.get("/학생", 함수(요청, 응답) { 학생 모델.getAll(함수(오류, 결과) { 만약(오류) { 응답.상태(401).보내기({ "성공": false, "메시지": 오류}); } 응답.보내기(결과); }); }); 앱.get("/학생/:ID", 함수(요청, 응답) { 학생 모델.getById(요청.매개변수.id, 함수(오류, 결과) { 만약(오류) { 응답.상태(401).보내기({ "성공": false, "메시지": 오류}); } 응답.보내기(결과); }); }); 앱.post("/학생", 함수(요청, 응답) { 만약(!요청.body.이름) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": "`이름`이 필요합니다."}); } else 만약(!요청.body.성) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": "`성`이 필요합니다."}); } else 만약(!요청.body.주소) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": "`주소`가 필요합니다."}); } 학생 모델.저장(요청.body, 함수(오류, 학생) { 만약(오류) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": 오류}); } 응답.보내기(학생); }); }); 앱.post("/학생/코스", 함수(요청, 응답) { 만약(!요청.body.student_id) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": "`학생 아이디`가 필요합니다." }); } else 만약(!요청.body.course_id) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": "`코스 아이디`가 필요합니다." }); } 코스 모델.getById(요청.body.course_id, 함수(오류, 코스) { 만약(오류) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": 오류}); } 학생 모델.getById(요청.body.student_id, 함수(오류, 학생) { 만약(오류) { 반환 응답.상태(401).보내기({ "성공": false, "메시지": 오류}); } 만약(코스 != null && 학생 != null) { 만약(!학생[0].코스) { 학생[0].코스 = []; } 만약(!코스[0].학생) { 코스[0].학생 = []; } var 코스 = []; var 학생 = []; 에 대한(var i = 0; i < 학생[0].코스.길이; i++) { 코스.push(학생[0].코스[i]._id); } 에 대한(var i = 0; i < 코스[0].학생.길이; i++) { 학생.push(코스[0].학생[i]._id); } 코스.push(코스[0]._id); 학생.push(학생[0]._id); 학생 모델.업데이트 코스(학생[0]._id, 코스, 함수(오류, 결과) {}); 코스 모델.업데이트학생(코스[0]._id, 학생, 함수(오류, 결과) {}); 응답.보내기(학생[0]); } else { 반환 응답.상태(401).보내기({ "성공": false, "메시지": "`학생 아이디` 또는 `코스 아이디`가 유효하지 않습니다."}); } }); }); }); } 모듈.수출 = 라우터; |
다른 경로와 마찬가지로 많은 일이 일어나고 있지만 대부분은 거의 동일합니다. 차이점이 있다면 /학생/코스
학생에게 코스를 추가하고 코스에 학생을 추가하는 역할을 하는 엔드포인트입니다.
이 엔드포인트를 호출할 때 먼저 전달된 ID 값을 기반으로 학생 및 코스 정보를 가져옵니다. 둘 다 존재해야 하며, 그렇지 않으면 오류가 발생합니다. 둘 다 존재하는 경우 학생 ID를 학생
배열과 코스 문서의 코스 ID를 코스
배열을 추가합니다. 그런 다음 업데이트 메서드를 호출하여 최종 사용자에게 결과를 반환합니다.
애플리케이션 통합 및 부트스트랩하기
이제 API를 사용할 준비가 되었습니다. Node.js 애플리케이션을 부트스트랩하고 데이터베이스에 연결하기만 하면 됩니다. 이것은 쉬운 부분입니다.
프로젝트의 app.js 파일을 열고 다음 코드를 포함하세요:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
var 몽고클라이언트 = require("mongodb").몽고클라이언트; var Express = require("express"); var 바디파서 = require("body-parser"); var 앱 = Express(); 앱.사용(바디파서.json()); 몽고클라이언트.연결("mongodb://localhost:27017/example", 함수(오류, 데이터베이스) { 만약(오류) { 반환 콘솔.로그("MongoDB에 연결할 수 없습니다."); } 모듈.수출.데이터베이스 = 데이터베이스; var 학생 경로 = require("./몽고DB/경로/학생")(앱); var 코스 경로 = require("./mongodb/routes/courses")(앱); var 서버 = 앱.듣기(3000, 함수() { 콘솔.로그("포트 3000에 연결됨..."); }); }); |
위의 코드에서는 다운로드한 각 종속 요소를 가져오고 Express Framework를 초기화하고 있습니다. API 서비스를 시작하기 전에 MongoDB에 대한 연결을 설정해야 합니다. 연결이 설정되면 경로가 연결되고 애플리케이션이 서비스를 시작합니다.
현재 RESTful API는 http://localhost:3000 에서 확인할 수 있으며 다음과 같은 인기 도구로 테스트할 수 있습니다. 우편 배달원 또는 피들러.
카우치베이스와 N1QL로 API 개발하기
그래서 우리는 MongoDB와 Node.js에 대해 작업할 수 있는 예제를 가지고 있습니다. 이 예제에서는 데이터베이스와 통신할 때 MongoDB 쿼리 언어를 사용했습니다.
이제 해당 애플리케이션을 다음 위치로 이동하겠습니다. 카우치베이스. 이렇게 하는 이유는 Couchbase의 확장성과 성능이 더 우수할 뿐만 아니라 쿼리 언어가 훨씬 더 간단하고 애플리케이션 내에서 유지 관리가 쉽기 때문입니다.
MongoDB 애플리케이션과 마찬가지로, 표시되는 내용은 대부분 동일하지만 처음부터 다시 시작하겠습니다. 명령 프롬프트 또는 터미널에서 다음을 실행합니다:
1 2 |
npm init --y 엔피엠 설치 익스프레스 바디-파서 카우치베이스 --save |
위의 명령은 익숙하게 보일 것입니다. 우리는 package.json 파일을 생성하고 종속 요소를 설치하지만, MongoDB 대신 Couchbase를 사용하고 있습니다.
프로젝트는 이전 프로젝트에서 본 것과 동일한 구조를 유지합니다. 다음과 같이 보일 것입니다:
1 2 3 4 5 6 7 8 9 |
app.js 경로/ courses.js students.js models/ course.js student.js package.json node_modules/ |
앞서 살펴본 것과 동일한 로직이 각 파일에 적용됩니다. 차이점은 Couchbase의 구문입니다.
애플리케이션 내에서 카우치베이스 데이터베이스 모델 만들기
같은 순서로 데이터베이스 모델 함수를 만들어 보겠습니다. 앞서 언급했듯이 SQL 쿼리를 작성할 수 있다는 점에서 Couchbase의 가장 큰 특징인 N1QL을 사용할 것입니다. 이러한 쿼리는 Node.js 애플리케이션이 아닌 데이터베이스에서 실행됩니다.
프로젝트의 models/course.js 파일을 열고 다음 코드를 포함하세요:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
var Uuid = require("uuid"); var 버킷 = require("../../app").버킷; var N1qlQuery = require("couchbase").N1qlQuery; 함수 코스 모델() { }; 코스 모델.저장 = 함수(데이터, 콜백) { 데이터.id = Uuid.v4(); 데이터.유형 = "course"; 데이터.학생 = []; var 문 = "`에 삽입" + 버킷._name + "` (키, 값) 값 ($1, $2) 반환 `" + 버킷._name + "`.*"; var 쿼리 = N1qlQuery.fromString(문); 버킷.쿼리(쿼리, [데이터.id, 데이터], 함수(오류, 결과) { 만약(오류) { 콜백(오류, null); 반환; } 콜백(null, 결과); }); } 코스 모델.업데이트학생 = 함수(id, 코스, 콜백) { var 문 = "업데이트 `" + 버킷._name + "` USE KEYS $1 SET students = $2 RETURNING `" + 버킷._name + "`.*"; var 쿼리 = N1qlQuery.fromString(문); 버킷.쿼리(쿼리, [id, 코스], 함수(오류, 결과) { 만약(오류) { 콜백(오류, null); 반환; } 콜백(null, 결과); }); } 코스 모델.getById = 함수(documentId, 콜백) { var 문 = "SELECT s.id, s.type, s.name, " + "(SELECT t.* FROM `" + 버킷._name + "` AS t 사용 키 s.students) 학생으로 " + "FROM `" + 버킷._name + "` AS s " + "WHERE s.type = 'course' AND s.id = $1"; var 쿼리 = N1qlQuery.fromString(문); 버킷.쿼리(쿼리, [documentId], 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); }); }; 코스 모델.getAll = 함수(콜백) { var 문 = "SELECT s.id, s.type, s.name, " + "(SELECT t.* FROM `" + 버킷._name + "` AS t 사용 키 s.students) 학생으로 " + "FROM `" + 버킷._name + "` AS s " + "WHERE s.type = 'course'"; var 쿼리 = N1qlQuery.fromString(문).일관성(N1qlQuery.일관성.REQUEST_PLUS); 버킷.쿼리(쿼리, 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); }); }; 모듈.수출 = 코스 모델; |
위의 코드에는 MongoDB 예제에서 보았던 것과 동일한 데이터베이스 관련 함수 집합이 있습니다. 이러한 각 함수 안에는 N1QL 쿼리가 있습니다. 단순한 N1QL 쿼리가 아니라 SQL 인젝션 공격을 방어하는 데 도움이 되는 매개변수화된 N1QL 쿼리도 있습니다.
다음 내용을 살펴보십시오. getAll
메서드에서 이전 버전에서는 매우 복잡했던 메서드입니다:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
코스 모델.getAll = 함수(콜백) { var 문 = "SELECT s.id, s.type, s.name, " + "(SELECT t.* FROM `" + 버킷._name + "` AS t 사용 키 s.students) 학생으로 " + "FROM `" + 버킷._name + "` AS s " + "WHERE s.type = 'course'"; var 쿼리 = N1qlQuery.fromString(문).일관성(N1qlQuery.일관성.REQUEST_PLUS); 버킷.쿼리(쿼리, 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); }); }; |
이번에는 하위 쿼리를 포함하는 간단한 쿼리를 예로 들어보겠습니다. 데이터 요구 사항이 더 복잡해지면 쿼리의 크기나 복잡성을 크게 늘리지 않고도 쿼리를 변경할 수 있습니다.
이제 다른 데이터베이스 모델을 살펴보겠습니다. 프로젝트의 models/student.js 파일을 열고 다음 자바스크립트 코드를 포함합니다:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
var Uuid = require("uuid"); var 버킷 = require("../../app").버킷; var N1qlQuery = require("couchbase").N1qlQuery; 함수 학생 모델() { }; 학생 모델.저장 = 함수(데이터, 콜백) { 데이터.id = Uuid.v4(); 데이터.유형 = "student"; 데이터.코스 = []; var 문 = "`에 삽입" + 버킷._name + "` (키, 값) 값 ($1, $2) 반환 `" + 버킷._name + "`.*"; var 쿼리 = N1qlQuery.fromString(문); 버킷.쿼리(쿼리, [데이터.id, 데이터], 함수(오류, 결과) { 만약(오류) { 콜백(오류, null); 반환; } 콜백(null, 결과); }); } 학생 모델.업데이트 코스 = 함수(id, 코스, 콜백) { var 문 = "업데이트 `" + 버킷._name + "` 사용 키 $1 세트 코스 = $2 반환`" + 버킷._name + "`.*"; var 쿼리 = N1qlQuery.fromString(문); 버킷.쿼리(쿼리, [id, 코스], 함수(오류, 결과) { 만약(오류) { 콜백(오류, null); 반환; } 콜백(null, 결과); }); } 학생 모델.getById = 함수(documentId, 콜백) { var 문 = "SELECT t.id, t.type, t.firstname, t.lastname, t.address, " + "(SELECT s.* FROM `" + 버킷._name + "` AS s USE KEYS t.courses) AS 코스" + "FROM `" + 버킷._name + "` AS t " + "WHERE t.type = 'student' AND t.id = $1"; var 쿼리 = N1qlQuery.fromString(문); 버킷.쿼리(쿼리, [documentId], 함수(오류, 결과) { 만약(오류) { 콘솔.로그(오류); 반환 콜백(오류, null); } 콜백(null, 결과); }); }; 학생 모델.getAll = 함수(콜백) { var 문 = "SELECT t.id, t.type, t.firstname, t.lastname, t.address, " + "(SELECT s.* FROM `" + 버킷._name + "` AS s USE KEYS t.courses) AS 코스" + "FROM `" + 버킷._name + "` AS t " + "WHERE t.type = 'student'"; var 쿼리 = N1qlQuery.fromString(문).일관성(N1qlQuery.일관성.REQUEST_PLUS); 버킷.쿼리(쿼리, 함수(오류, 결과) { 만약(오류) { 반환 콜백(오류, null); } 콜백(null, 결과); }); }; 모듈.수출 = 학생 모델; |
익숙해 보이시나요? 두 데이터베이스 모델이 비슷한 이유는 두 문서 모델이 비슷하기 때문입니다. 다시 말하지만, 복잡성이 변경되더라도 애플리케이션 계층은 여전히 N1QL 쿼리로 쉽게 관리할 수 있습니다.
API 경로에는 데이터베이스에 대한 종속성이 없기 때문에 MongoDB 애플리케이션과 Couchbase 애플리케이션 간의 코드를 공유할 수 있습니다. 명확히 말씀드리자면, 저는 여기서는 경로 디렉터리로 이동합니다.
애플리케이션 부트스트랩 및 카우치베이스에 연결하기
엔드포인트가 준비되고 데이터베이스 모델이 N1QL을 통해 Couchbase와 통신하면 애플리케이션을 완성할 수 있습니다.
프로젝트의 app.js 파일을 열고 다음 자바스크립트 코드를 포함합니다:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var 카우치베이스 = require("couchbase"); var Express = require("express"); var 바디파서 = require("body-parser"); var 앱 = Express(); 앱.사용(바디파서.json()); 모듈.수출.버킷 = (new 카우치베이스.클러스터("couchbase://localhost")).오픈버킷("예제"); var 학생 경로 = require("./couchbase/routes/students")(앱); var 코스 경로 = require("./couchbase/routes/courses")(앱); var 서버 = 앱.듣기(3000, 함수() { 콘솔.로그("포트 3000에 연결됨..."); }); |
위의 코드에서는 설치한 종속성을 가져오고 Express Framework를 초기화하고 있습니다. 그런 다음 데이터베이스에 대한 연결을 설정하고, 경로를 통합하고, Node.js 서버를 시작하고 있습니다.
N1QL을 사용하고 있으므로 Couchbase 버킷에 인덱스를 하나 이상 생성하는 것을 잊지 마세요. 다음과 같이 간단하게 만들 수 있습니다:
1 |
'예제'에 기본 인덱스를 생성합니다; |
이 시점에서 MongoDB와 동일한 방식으로 애플리케이션에 액세스할 수 있어야 합니다. 웹 브라우저에서 또는 Postman이나 Fiddler와 같은 도구를 사용하여 http://localhost:3000 을 방문하세요.
결론
방금 몽고DB와 몽고DB 쿼리 언어를 사용하는 Node.js 애플리케이션을 가져와서 대신 N1QL을 사용하여 Couchbase로 변환하는 방법을 살펴보았습니다. 이것은 몽구스에서 오스만 ODM으로 솔루션에 대해 설명한 적이 있습니다.
그렇다면 왜 MongoDB에서 Couchbase로 전환하고 싶으신가요? Couchbase는 훨씬 더 빠르고 확장하기 쉽지만, 복잡한 데이터로 작업할 때 N1QL도 매우 간단합니다. 코드를 대폭 줄이고 유지보수를 더 쉽게 할 수 있습니다. Couchbase와 MongoDB 쿼리 비교를 확인해 보세요. 튜토리얼 두 데이터베이스 간의 데이터 조인에 대해 설명했습니다.
Node.js 애플리케이션에서 Couchbase를 사용하는 방법에 대한 자세한 내용을 참조하세요:
-
- 다음 내용을 확인하세요. 카우치베이스 개발자 포털.
- 다음 중 하나를 사용해 보세요. 카우치베이스 개발자 IDE - JetBrains, VSCode-플러그인이 있습니다.
[...] MongoDB 기반 Node.js 애플리케이션을 Couchbase로 변환하는 방법에 대해 설명합니다. 여기에는 MongoDB 쿼리 언어에서 N1QL로 튜토리얼과 몽구스에서 오스만 튜토리얼이 포함되어 있습니다. 이들은 [...]의 훌륭한 마이그레이션 자습서였습니다.