{"id":3841,"date":"2017-07-20T07:00:11","date_gmt":"2017-07-20T14:00:11","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=3841"},"modified":"2025-06-13T18:46:03","modified_gmt":"2025-06-14T01:46:03","slug":"couchbase-meetup-project-ocean-stack-available","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/ko\/couchbase-meetup-project-ocean-stack-available\/","title":{"rendered":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ubc0b\uc5c5 \ud504\ub85c\uc81d\ud2b8\uac00 OCEAN \uc2a4\ud0dd\uc5d0\uc11c \uc9c4\ud589\ub429\ub2c8\ub2e4."},"content":{"rendered":"<p>\uc800\ub294 \ucd5c\uadfc \ub0a8\ubd80 \uce98\ub9ac\ud3ec\ub2c8\uc544\uc5d0\uc11c \uc5f4\ub9b0 \ub450 \uac1c\uc758 \ub2e4\ub978 \ubc0b\uc5c5 \uadf8\ub8f9\uc5d0\uc11c Ottoman.js\ub85c \uad6c\uc131\ub41c OCEAN \uc2a4\ud0dd\uc5d0 \ub300\ud574 \ubc1c\ud45c\ud588\uc2b5\ub2c8\ub2e4, <a href=\"https:\/\/www.couchbase.com\/blog\/ko\/\" target=\"_blank\" rel=\"noopener noreferrer\">\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \uc11c\ubc84<\/a>, Express Framework, Angular \ubc0f Node.js.<\/p>\n<p>NoSQL \uc2a4\ud0dd\uc744 \uc0ac\uc6a9\ud558\ub294 JavaScript\uc5d0 \ub300\ud574 \ubc30\uc6b0\uace0 \uc2f6\uc5b4\ud558\ub294 \uac1c\ubc1c\uc790\ub4e4\uc774 \ub9ce\uc774 \ucc38\uc5ec\ud588\uc2b5\ub2c8\ub2e4.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3854 size-full\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/07\/oc-angular-meetup.jpg\" alt=\"OC Angular Meetup\" width=\"1200\" height=\"549\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/07\/oc-angular-meetup.jpg 1200w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/07\/oc-angular-meetup-300x137.jpg 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/07\/oc-angular-meetup-1024x468.jpg 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/07\/oc-angular-meetup-768x351.jpg 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/07\/oc-angular-meetup-20x9.jpg 20w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/p>\n<p>\uadf8\ub8f9\uacfc\uc758 \uc57d\uc18d\uc5d0 \ub530\ub77c \uc81c\uac00 \uacf5\uc720\ud55c \ub0b4\uc6a9\uc744 \ud29c\ud1a0\ub9ac\uc5bc\ub85c \uc791\uc131\ud558\uc5ec \ubaa8\ub450\uac00 \ub3c4\uc6c0\uc744 \ubc1b\uc744 \uc218 \uc788\ub3c4\ub85d \ud588\uc2b5\ub2c8\ub2e4. \ub2e4\uc591\ud55c \uc790\ubc14\uc2a4\ud06c\ub9bd\ud2b8 \uae30\uc220\uacfc NoSQL\uc744 \uc0ac\uc6a9\ud558\uc5ec \uae30\ub2a5\uc801\uc778 \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uac1c\ubc1c\ud558\ub294 \ubc29\ubc95\uc744 \uc0b4\ud3b4\ubcf4\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n<p><!--more--><\/p>\n<p>\ucf54\ub4dc\ub97c \uc0b4\ud3b4\ubcf4\uae30 \uc804\uc5d0 Couchbase Server\uc640 Node.js\uac00 \uc124\uce58 \ubc0f \uad6c\uc131\ub418\uc5b4 \uc788\ub2e4\uace0 \uac00\uc815\ud569\ub2c8\ub2e4. \uc5ec\uae30\uc11c\ub294 \ud658\uacbd \uad6c\uc131\uc774 \uc544\ub2cc \uac1c\ubc1c\uc5d0 \ucd08\uc810\uc744 \ub9de\ucd9c \uac83\uc785\ub2c8\ub2e4.<\/p>\n<p>Ottoman.js\ub97c \uc0ac\uc6a9\ud558\uc5ec API\ub97c \ube4c\ub4dc\ud55c \ub2e4\uc74c Ottoman.js \ub300\uc2e0 N1QL\uc744 \uc0ac\uc6a9\ud558\uc5ec API\ub97c \ube4c\ub4dc\ud558\uaca0\uc2b5\ub2c8\ub2e4. \ub450 API \ubaa8\ub450 Angular\ub85c \uac1c\ubc1c\ub41c \ud504\ub7f0\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \uc0ac\uc6a9\ud558\uac8c \ub429\ub2c8\ub2e4.<\/p>\n<h2>Ottoman.js, Express \ud504\ub808\uc784\uc6cc\ud06c \ubc0f Couchbase NoSQL\ub85c API \uac1c\ubc1c\ud558\uae30<\/h2>\n<p>Node.js \ud504\ub85c\uc81d\ud2b8\uc758 \uccab \ubc88\uc9f8 \ub2e8\uacc4\ub294 \ud504\ub85c\uc81d\ud2b8\ub97c \uad6c\uc131\ud558\uace0 \ubaa8\ub4e0 \uc885\uc18d \uc694\uc18c\ub97c \ub2e4\uc6b4\ub85c\ub4dc\ud558\ub294 \uac83\uc785\ub2c8\ub2e4. \uc0c8 \ud504\ub85c\uc81d\ud2b8\ub97c \uc0dd\uc131\ud558\uace0 \uc885\uc18d \uc694\uc18c\ub97c \ub2e4\uc6b4\ub85c\ub4dc\ud558\ub294 \uc791\uc5c5\uc740 \ub2e4\uc74c \uba85\ub839\uc5b4\ub85c \ucc98\ub9ac\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">npm init --y\r\nnpm install ottoman couchbase express body-parser cors --save<\/pre>\n<p>\uccab \ubc88\uc9f8 \uba85\ub839\uc740 \ud504\ub85c\uc81d\ud2b8\uc758\u00a0<strong>package.json<\/strong> \ub450 \ubc88\uc9f8 \uba85\ub839\uc740 \uc885\uc18d\uc131\uc744 \uac00\uc838\uc624\ub294\ub370, \uc5ec\uae30\uc5d0\ub294\u00a0<code>\ubcf8\ubb38 \ud30c\uc11c<\/code> \uc694\uccad\uc5d0\uc11c JSON \ubcf8\ubb38\uc744 \uc218\ub77d\ud558\uace0\u00a0<code>cors<\/code> \ud328\ud0a4\uc9c0\ub97c \uc0ac\uc6a9\ud558\uc5ec \ub2e4\ub978 \ub3c4\uba54\uc778\uc774\ub098 \ud3ec\ud2b8\uc5d0\uc11c Angular\ub97c \uc0ac\uc6a9\ud560 \ub54c \ubc1c\uc0dd\ud560 \uc218 \uc788\ub294 \uad50\ucc28 \ucd9c\ucc98 \uad00\ub828 \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uc138\uc694.<\/p>\n<p>\uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \ubd80\ud2b8\uc2a4\ud2b8\ub7a9\ud558\uae30 \uc704\ud574 \ub2e4\uc74c\uacfc \uac19\uc740 \ud30c\uc77c\uc744 \ub9cc\ub4e4\uaca0\uc2b5\ub2c8\ub2e4.\u00a0<strong>app.js<\/strong> \uc5d0 \ub2e4\uc74c \uc790\ubc14\uc2a4\ud06c\ub9bd\ud2b8 \ucf54\ub4dc\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">var Couchbase = require(\"couchbase\");\r\nvar Express = require(\"express\");\r\nvar Cors = require(\"cors\");\r\nvar BodyParser = require(\"body-parser\");\r\nvar Ottoman = require(\"ottoman\");\r\n\r\nvar app = Express();\r\n\r\napp.use(BodyParser.json());\r\napp.use(BodyParser.urlencoded({ extended: true }));\r\napp.use(Cors());\r\n\r\nvar cluster = new Couchbase.Cluster(\"couchbase:\/\/localhost\");\r\nvar bucket = cluster.openBucket(\"default\", \"\");\r\nOttoman.store = new Ottoman.CbStoreAdapter(bucket, Couchbase);\r\n\r\napp.get(\"\/people\", function(request, response) { });\r\napp.get(\"\/person\/:id\", function(request, response) { });\r\napp.post(\"\/person\/:id?\", function(request, response) { });\r\napp.delete(\"\/person\/:id\", function(request, response) { });\r\n\r\nvar server = app.listen(3000, function() {\r\n    console.log(\"Listening on port \" + server.address().port + \"...\");\r\n});<\/pre>\n<p>\uae30\ubcf8\uc801\uc73c\ub85c \ub2e4\uc6b4\ub85c\ub4dc\ud55c \uc885\uc18d\uc131\uc744 \uac00\uc838\uc624\uace0, API \uc5d4\ub4dc\ud3ec\uc778\ud2b8\ub97c \uc815\uc758\ud558\uace0, Couchbase Server\uc5d0 \uc5f0\uacb0\uc744 \uc124\uc815\ud558\uace0, \uc560\ud50c\ub9ac\ucf00\uc774\uc158 \uc11c\ube44\uc2a4\ub97c \uc2dc\uc791\ud588\uc2b5\ub2c8\ub2e4.<\/p>\n<p>API \uc5d4\ub4dc\ud3ec\uc778\ud2b8\ub294 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0 \ub300\ud55c \uae30\ubcf8\uc801\uc778 CRUD \uc791\uc5c5\uc744 \uc704\ud55c \uac83\uc785\ub2c8\ub2e4. \uac1d\uccb4 \ubb38\uc11c \ubaa8\ub378\ub7ec(ODM)\uc778 Ottoman.js\ub97c \uc0ac\uc6a9\ud558\ubbc0\ub85c \ubaa8\ub378\uc744 \uc815\uc758\ud574\uc57c \ud569\ub2c8\ub2e4. \uc5d4\ub4dc\ud3ec\uc778\ud2b8 \uc815\uc758 \uc704\uc5d0 \ub2e4\uc74c\uc744 \ucd94\uac00\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">var Person = Ottoman.model(\"Person\", {\r\n    firstname: \"string\",\r\n    lastname: \"string\",\r\n    social_media: {\r\n        website: \"string\",\r\n        twitter: \"string\"\r\n    }\r\n});<\/pre>\n<p>\uc774 \ubaa8\ub378\uc740 \ubb34\ud55c\ud788 \ubcf5\uc7a1\ud560 \uc218 \uc788\uc9c0\ub9cc \uc5ec\uae30\uc11c\ub294 \uac04\ub2e8\ud55c \uc0ac\uc6a9\uc790 \ud504\ub85c\ud544\uc744 \ud45c\ud604\ud558\uaca0\uc2b5\ub2c8\ub2e4. \uc774\uac83\uc774 \uc6b0\ub9ac\uac00 \ucf54\ub4dc\uc640 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0\uc11c \uc870\uc791\ud560 \ubaa8\ub378\uc785\ub2c8\ub2e4.<\/p>\n<p>\ud604\uc7ac \ub370\uc774\ud130\ubca0\uc774\uc2a4\uac00 \ube44\uc5b4 \uc788\uc73c\ubbc0\ub85c \ub370\uc774\ud130\ub97c \uc0dd\uc131\ud558\uae30 \uc704\ud55c \uc5d4\ub4dc\ud3ec\uc778\ud2b8\uc5d0\uc11c \uc791\uc5c5\ud558\ub294 \uac83\uc774 \uc88b\uc2b5\ub2c8\ub2e4. \ud504\ub85c\uc81d\ud2b8 \ub0b4\uc5d0\uc11c \ub2e4\uc74c \uc790\ubc14\uc2a4\ud06c\ub9bd\ud2b8 \uccad\ud06c\ub97c \ud3b8\uc9d1\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">app.post(\"\/person\/:id?\", function(request, response) {\r\n    if(!request.body) {\r\n        return response.status(401).send({ \"message\": \"A POST body is required!\" });\r\n    }\r\n    Person.getById(request.params.id, function(error, result) {\r\n        if(error) {\r\n            result = new Person(request.body);\r\n        } else {\r\n            Object.assign(result, request.body);\r\n        }\r\n        result.save(function(error) {\r\n            if(error) {\r\n                return response.status(500).send(error);\r\n            }\r\n            response.send(request.body);\r\n        });\r\n    });\r\n});<\/pre>\n<p>\uc704\uc758 \uc5d4\ub4dc\ud3ec\uc778\ud2b8\ub294 \uc544\ub9c8\ub3c4 \uc6b0\ub9ac \ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c \uac00\uc7a5 \ubcf5\uc7a1\ud55c \ubd80\ubd84\uc77c \uac83\uc785\ub2c8\ub2e4. \uc6b0\ub9ac\ub294 POST \ubcf8\ubb38\uc774 \ud544\uc694\ud558\ub2e4\uace0 \ub9d0\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. \uadf8\uac83\uc774 \ubb34\uc5c7\uc774\ub4e0 \uc874\uc7ac\ud558\uae30\ub9cc \ud55c\ub2e4\uba74 \uc0c1\uad00\uc5c6\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\uc774 \uc5d4\ub4dc\ud3ec\uc778\ud2b8\uc5d0\uc11c\ub294 \ub450 \ub9c8\ub9ac \ud1a0\ub07c\ub97c \uc7a1\uc558\uc2b5\ub2c8\ub2e4. \uc6b0\ub9ac\ub294 \uc5c5\ub370\uc774\ud2b8\ubfd0\ub9cc \uc544\ub2c8\ub77c \uc0dd\uc131\uc744 \uc218\ud589\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. \uba3c\uc800 \uc804\ub2ec\ub41c ID\ub85c \uc870\ud68c\ub97c \uc218\ud589\ud569\ub2c8\ub2e4. ID\uac00 \uc804\ub2ec\ub418\uc5c8\ub294\uc9c0 \uc5ec\ubd80\ub294 \uc911\uc694\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. ID\uac00 \uc874\uc7ac\ud558\uc9c0 \uc54a\ub294 \ub4f1\uc758 \uc774\uc720\ub85c \uc624\ub958\uac00 \ubc1c\uc0dd\ud558\uba74 \uc815\uc758\uc5d0 \ub530\ub77c \uc0c8 ODM \ubaa8\ub378\uc774 \uc0dd\uc131\ub418\uace0, \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74 ID\ub97c \uae30\uc900\uc73c\ub85c \uc870\ud68c\ud55c \uacb0\uacfc\uc640 \ubcd1\ud569\ub429\ub2c8\ub2e4.<\/p>\n<p>\ubaa8\ub378\uc774 \uc644\uc131\ub418\uba74 \uacb0\uacfc\ub97c \uc800\uc7a5\ud558\uace0 \uc0ac\uc6a9\uc790\uc5d0\uac8c \ubc18\ud658\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ub2e4\uc74c \ub17c\ub9ac\uc801 \ub2e8\uacc4\ub294 ID \uac12\uc73c\ub85c \ud2b9\uc815 \uc0ac\ub78c\uc744 \ucc3e\uae30 \uc704\ud55c \uc5d4\ub4dc\ud3ec\uc778\ud2b8\ub97c \uc644\uc131\ud558\ub294 \uac83\uc785\ub2c8\ub2e4. \ud504\ub85c\uc81d\ud2b8\uc5d0 \ub2e4\uc74c JavaScript\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">app.get(\"\/person\/:id\", function(request, response) {\r\n    if(!request.params.id) {\r\n        return response.status(401).send({ \"message\": \"An `id` is required!\" });\r\n    }\r\n    Person.getById(request.params.id, function(error, result) {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        response.send(result);\r\n    });\r\n});<\/pre>\n<p>\uc804\ub2ec\ub41c ID \uac12\uc744 \uc0ac\uc6a9\ud558\uc5ec \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0\uc11c \uc0ac\ub78c\uc744 \uac00\uc838\uc640 \uc694\uccad\uc744 \ubc1c\ud589\ud55c \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\uac8c \ub2e4\uc2dc \ubc18\ud658\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ubaa8\ub378\uacfc \uc77c\uce58\ud558\ub294 \ubaa8\ub4e0 \ub808\ucf54\ub4dc\ub97c \uac00\uc838\uc624\uace0 \uc2f6\uc744 \ub54c\uac00 \uc788\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4. ID \uac12 \uc774\uc678\uc758 \uc18d\uc131\uc744 \uae30\ubc18\uc73c\ub85c \ucffc\ub9ac\ud558\uace0 \uc2f6\uc744 \ub54c\ub3c4 \uc788\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \uacbd\uc6b0\u00a0<code>\ucc3e\uae30<\/code> \uba85\ub839\uc744 \uc0ac\uc6a9\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">app.get(\"\/people\", function(request, response) {\r\n    Person.find({}, { consistency: Ottoman.Consistency.LOCAL }, function(error, result) {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        response.send(result);\r\n    });\r\n});<\/pre>\n<p>\uba85\ub839\uc5d0 \ube48 \uac1d\uccb4\ub97c \uc81c\uacf5\ud568\uc73c\ub85c\uc368 \ubaa8\ub378\uacfc \uc77c\uce58\ud558\ub294 \ubaa8\ub4e0 \ubb38\uc11c\ub97c \uc694\uccad\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. \uc774\uac83\uc740 \ud2b9\uc815 \uc77c\uce58\ud558\ub294 \uc18d\uc131\uc73c\ub85c \uc27d\uac8c \ud655\uc7a5\ud560 \uc218 \uc788\uc5c8\uc2b5\ub2c8\ub2e4. \ub610\ud55c \ucffc\ub9ac\ub97c \uc644\ub8cc\ud558\uae30 \uc804\uc5d0 \uc778\ub371\uc2a4\uac00 \uc5c5\ub370\uc774\ud2b8\ub418\uc5c8\ub294\uc9c0 \ud655\uc778\ud558\uace0 \uc2f6\uc2b5\ub2c8\ub2e4. \uae30\ubcf8\uc801\uc73c\ub85c Couchbase\ub294 \uc131\ub2a5\uc5d0 \uc911\uc810\uc744 \ub450\ubbc0\ub85c \uc778\ub371\uc2a4\uac00 \uc544\uc9c1 \uc5c5\ub370\uc774\ud2b8\ub418\uc9c0 \uc54a\uc740 \uacbd\uc6b0 \uacb0\uacfc\uc5d0 \uc77c\ubd80 \ub370\uc774\ud130\uac00 \ub204\ub77d\ub420 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc0c1\ud669\uc5d0 \ub530\ub77c \uc704\uc640 \uac19\uc774 \uc2a4\uce94 \uc77c\uad00\uc131\uc744 \ubcc0\uacbd\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ub9c8\uc9c0\ub9c9\uc73c\ub85c \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0\uc11c \ubb38\uc11c\ub97c \uc81c\uac70\ud558\uae30 \uc704\ud55c \uc5d4\ub4dc\ud3ec\uc778\ud2b8\ub97c \uad6c\ucd95\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">app.delete(\"\/person\/:id\", function(request, response) {\r\n    if(!request.params.id) {\r\n        return response.status(401).send({ \"message\": \"An `id` is required!\" });\r\n    }\r\n    Person.getById(request.params.id, function(error, result) {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        result.remove(function(error) {\r\n            response.send({ \"message\": \"Deleted `\" + request.params.id  + \"`\"});\r\n        });\r\n    });\r\n});<\/pre>\n<p>\uba3c\uc800 \uc804\ub2ec\ub41c \uc544\uc774\ub514\ub85c \ubb38\uc11c\ub97c \uac00\uc838\uc624\uace0, \ubb38\uc11c\uac00 \uc874\uc7ac\ud558\uba74\u00a0<code>\uc81c\uac70<\/code> \ub97c \ud074\ub9ad\ud558\uc5ec \uc0ad\uc81c\ud569\ub2c8\ub2e4.<\/p>\n<p>\uc774 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uc2e4\ud589\ud558\uace0 \ub2e4\uc74c\uacfc \uac19\uc740 \ub3c4\uad6c\ub97c \uc0ac\uc6a9\ud558\ub294 \uacbd\uc6b0 <a href=\"https:\/\/www.thepolyglotdeveloper.com\/2015\/01\/using-postman-troubleshoot-restful-api-requests\/\" target=\"_blank\" rel=\"noopener noreferrer\">\uc6b0\ud3b8 \ubc30\ub2ec\uc6d0<\/a>\ub97c \uc0ac\uc6a9\ud558\uc5ec \uae30\ubcf8\uc774\uc9c0\ub9cc \ubaa8\ub4e0 \uae30\ub2a5\uc744 \uac16\ucd98 API\ub97c \ud14c\uc2a4\ud2b8\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<h2>Express \ud504\ub808\uc784\uc6cc\ud06c, N1QL \ubc0f Couchbase NoSQL\ub85c API \uac1c\ubc1c\ud558\uae30<\/h2>\n<p>Ottoman.js\uc640 \uac19\uc740 ODM\uc744 \uc0ac\uc6a9\ud558\ub294 \uac83\uc774 \ub9c8\uc74c\uc5d0 \ub4e4\uc9c0 \uc54a\uace0 \uc9c1\uc811 \ucffc\ub9ac\ub97c \uc81c\uc791\ud558\uace0 \uc2f6\ub2e4\uace0 \uac00\uc815\ud574 \ubcf4\uaca0\uc2b5\ub2c8\ub2e4. Ottoman.js\ub97c \uc81c\uac70\ud558\uba74 CEAN \uc2a4\ud0dd\uc744 \uc5bb\uc744 \uc218 \uc788\uc73c\uba70, \uc774\ub294 N1QL\uc744 \ud1b5\ud574 \uac00\ub2a5\ud569\ub2c8\ub2e4.<\/p>\n<p>\ud504\ub85c\uc81d\ud2b8 \uad6c\uc870\ub294 \ub9e4\uc6b0 \uc720\uc0ac\ud558\uc9c0\ub9cc, \uc800\ud76c\ub9cc\uc758 \uc0c8\ub85c\uc6b4 \ud504\ub85c\uc81d\ud2b8\ub97c \ub9cc\ub4e4\ub824\uace0 \ud569\ub2c8\ub2e4.<\/p>\n<pre class=\"lang:default decode:true\">npm init --y\r\nnpm install couchbase express body-parser cors uuid --save<\/pre>\n<p>\uc774\uc804 \ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c \ubcf4\uc558\ub358 \uac83\uacfc \ube44\uc2b7\ud55c \uc885\uc18d\uc131\uc744 \uac00\uc9c0\uace0 \uc788\uc9c0\ub9cc \uc774\ubc88\uc5d0\ub294 UUID \uac12\uc744 \uc0dd\uc131\ud558\uae30 \uc704\ud55c \ud328\ud0a4\uc9c0\ub97c \uac00\uc838\uc635\ub2c8\ub2e4. Ottoman.js\ub294 \uc6b0\ub9ac\ub97c \uc704\ud574 ID \uac12\uc744 \uc0dd\uc131\ud588\uc9c0\ub9cc N1QL\uc744 \uc0ac\uc6a9\ud558\uba74 \uac1c\ubc1c\uc790\uc758 \ubaab\uc785\ub2c8\ub2e4. \uc544\uc774\ub514\ub97c \uc0dd\uc131\ud558\ub294 \uc5ec\ub7ec \uac00\uc9c0 \ubc29\ubc95 \uc911 \ud558\ub098\ub294 UUID\ub97c \uc0ac\uc6a9\ud558\ub294 \uac83\uc785\ub2c8\ub2e4.<\/p>\n<p>\uc0c8\ub85c\uc6b4\u00a0<strong>app.js<\/strong> \ud30c\uc77c\uc5d0 \ub2e4\uc74c\uacfc \uac19\uc740 \uc0c1\uc6a9\uad6c \ucf54\ub4dc\uac00 \uc788\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">var Express = require(\"express\");\r\nvar Couchbase = require(\"couchbase\");\r\nvar BodyParser = require(\"body-parser\");\r\nvar UUID = require(\"uuid\");\r\nvar Cors = require(\"cors\");\r\n\r\nvar app = Express();\r\nvar N1qlQuery = Couchbase.N1qlQuery;\r\n\r\napp.use(BodyParser.json());\r\napp.use(BodyParser.urlencoded({ extended: true }));\r\napp.use(Cors());\r\n\r\nvar cluster = new Couchbase.Cluster(\"couchbase:\/\/localhost\");\r\nvar bucket = cluster.openBucket(\"default\", \"\");\r\n\r\napp.get(\"\/people\", function(request, response) { });\r\napp.get(\"\/person\/:id?\", function(request, response) { });\r\napp.post(\"\/person\/:id?\", function(request, response) { });\r\napp.delete(\"\/person\/:id?\", function(request, response) { });\r\n\r\nvar server = app.listen(3000, function() {\r\n    console.log(\"Listening on port \" + server.address().port + \"...\");\r\n});<\/pre>\n<p>\uaf64 \uc775\uc219\ud574 \ubcf4\uc774\uc9c0\ub9cc \uc774\ubc88\uc5d0\ub294 Ottoman.js\ub97c N1QL \uc900\ube44\ub85c \uad50\uccb4\ud588\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\uc774\uc804 \uc608\uc81c\uc640 \ub9c8\ucc2c\uac00\uc9c0\ub85c \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0\uc11c \uc77d\uae30\ub97c \uc2dc\ub3c4\ud558\uae30 \uc804\uc5d0 \ub370\uc774\ud130 \uc800\uc7a5\uc5d0 \ub300\ud574 \uace0\ubbfc\ud574 \ubcf4\uaca0\uc2b5\ub2c8\ub2e4. \ub2e4\uc74c \uc5d4\ub4dc\ud3ec\uc778\ud2b8 \ucf54\ub4dc\ub97c \ud655\uc778\ud558\uc138\uc694:<\/p>\n<pre class=\"lang:default decode:true\">app.post(\"\/person\/:id?\", function(request, response) {\r\n    if(!request.body) {\r\n        return response.status(401).send({ \"message\": \"A POST body is required!\" });\r\n    }\r\n    var id = request.params.id ? request.params.id : UUID.v4();\r\n    request.body._id = id;\r\n    var statement = N1qlQuery.fromString(\"UPSERT INTO `\" + bucket._name + \"` (KEY, VALUE) VALUES ($id, $data) RETURNING `\" + bucket._name + \"`.*\");\r\n    bucket.query(statement, { \"id\": id, \"data\": request.body }, function(error, result) {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        response.send(result);\r\n    });\r\n});<\/pre>\n<p>\uc694\uccad\uacfc \ud568\uaed8 ID\ub97c \ubc1b\uc73c\uba74 \uc774\ub97c \uc0ac\uc6a9\ud558\uace0 \uc5c5\ub370\uc774\ud2b8\ub97c \uc218\ud589\ud55c\ub2e4\uace0 \uac00\uc815\ud558\uace0, \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74 \uc0c8 ID\ub97c \uc0dd\uc131\ud558\uace0 \ub9cc\ub4e4\uae30\ub97c \uc218\ud589\ud569\ub2c8\ub2e4. \ub450 \uc791\uc5c5 \ubaa8\ub450 \ud558\ub098\uc758\u00a0<code>UPSERT<\/code> \ucffc\ub9ac\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4. SQL \uc778\uc81d\uc158 \uacf5\uaca9\uc744 \ubc29\uc9c0\ud558\uae30 \uc704\ud574 \ub9e4\uac1c\ubcc0\uc218\ud654\ub41c \ucffc\ub9ac\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc0ac\uc6a9\uc790 \uc815\uc758 \ub370\uc774\ud130\ub97c \ub9e4\uac1c\ubcc0\uc218\ud654\ud560 \uac83\uc785\ub2c8\ub2e4.<\/p>\n<p>ID\ub97c \uc54c\uace0 \uc788\uace0 \ud2b9\uc815 \ubb38\uc11c\ub97c \ucc3e\uace0\uc790 \ud558\ub294 \uacbd\uc6b0 \ub2e4\uc74c\uc744 \uc0ac\uc6a9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\u00a0<code>\uc120\ud0dd<\/code> \uc791\uc5c5\uc5d0 \ub300\ud55c \ucffc\ub9ac\ub97c \uc791\uc131\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">app.get(\"\/person\/:id?\", function(request, response) {\r\n    if(!request.params.id) {\r\n        return response.status(401).send({ \"message\": \"An `id` is required!\" });\r\n    }\r\n    var statement = N1qlQuery.fromString(\"SELECT `\" + bucket._name + \"`.* FROM `\" + bucket._name + \"` WHERE META().id = $id\");\r\n    bucket.query(statement, { \"id\": request.params.id }, function(error, result) {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        response.send(result);\r\n    });\r\n});<\/pre>\n<p>\ub450 \ucffc\ub9ac \ubaa8\ub450\uc5d0\uc11c \uc624\ub958 \ub610\ub294 \uacb0\uacfc\ub97c \uc694\uccad\uc744 \ubc1c\ud589\ud55c \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0 \ubc18\ud658\ud569\ub2c8\ub2e4.<\/p>\n<p>\ubaa8\ub4e0 \ubb38\uc11c\uc5d0 \ub300\ud574 \ucffc\ub9ac\ud558\ub824\ub294 \uacbd\uc6b0\u00a0<code>\uc5b4\ub514<\/code> \uc870\uac74\uc744 \uc124\uc815\ud558\uace0 \uc2a4\uce94 \uc77c\uad00\uc131\uc744 \ub2e4\uc74c\uacfc \uac19\uc774 \uc815\uc758\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">app.get(\"\/people\", function(request, response) {\r\n    var statement = N1qlQuery.fromString(\"SELECT META().id, `\" + bucket._name + \"`.* FROM `\" + bucket._name + \"`\").consistency(N1qlQuery.Consistency.REQUEST_PLUS);\r\n    bucket.query(statement, function(error, result) {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        response.send(result);\r\n    });\r\n});<\/pre>\n<p>N1QL\uc740 SQL\uc758 \ub610 \ub2e4\ub978 \ud615\ud0dc\uc774\uae30 \ub54c\ubb38\uc5d0 \ucffc\ub9ac \uac00\ub2a5\uc131\uc740 \ub9e4\uc6b0 \ud07d\ub2c8\ub2e4. \uc774 API \uc608\uc81c\uc5d0\uc11c\ub294 \uac00\ub2a5\ud55c \uac83\uc758 \uc77c\ubd80\ub3c4 \ub2e4\ub8e8\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ub9c8\uc9c0\ub9c9\uc73c\ub85c ID \uac12\uc73c\ub85c \ubb38\uc11c\ub97c \uc81c\uac70\ud558\ub824\uba74 \ub2e4\uc74c\uacfc \uac19\uc774 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">app.delete(\"\/person\/:id?\", function(request, response) {\r\n    if(!request.params.id) {\r\n        return response.status(401).send({ \"message\": \"An `id` is required!\" });\r\n    }\r\n    var statement = N1qlQuery.fromString(\"DELETE FROM `\" + bucket._name + \"` WHERE META().id = $id\");\r\n    bucket.query(statement, { \"id\": request.params.id }, function(error, result) {\r\n        if(error) {\r\n            return response.status(500).send(error);\r\n        }\r\n        response.send(result);\r\n    });\r\n});<\/pre>\n<p>\uc774\ub7ec\ud55c N1QL \uae30\ubc18 \uc5d4\ub4dc\ud3ec\uc778\ud2b8 \uc911 \uc5b4\ub290 \uac83\ub3c4 \uc5b4\ub835\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. Ottoman.js\uc640 N1QL \uc911 \uc5b4\ub290 \uac83\uc744 \uc120\ud0dd\ud558\ub4e0 \uc798\ubabb\ub41c \uc120\ud0dd\uc740 \uc5c6\uc73c\uba70, \ub2e8\uc9c0 \uc120\ud638\ub3c4\uc5d0 \ub530\ub77c \ub2ec\ub77c\uc9c8 \ubfd0\uc785\ub2c8\ub2e4.<\/p>\n<h2>Angular \ubc0f TypeScript\ub85c \ud074\ub77c\uc774\uc5b8\ud2b8 \ud504\ub860\ud2b8\uc5d4\ub4dc \uad6c\ucd95\ud558\uae30<\/h2>\n<p>\ubc31\uc5d4\ub4dc API\ub97c \uc81c\uac70\ud558\uba74 \ub9e4\uc6b0 \uac04\ub2e8\ud558\uc9c0\ub9cc \uae30\ub2a5\uc801\uc778 \ud074\ub77c\uc774\uc5b8\ud2b8 \ud504\ub860\ud2b8\uc5d4\ub4dc\uc5d0 \uc9d1\uc911\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \ud504\ub860\ud2b8\uc5d4\ub4dc\ub294 OCEAN \uc2a4\ud0dd\uacfc CEAN \uc2a4\ud0dd \uc608\uc81c \ubaa8\ub450\uc5d0\uc11c \uc791\ub3d9\ud569\ub2c8\ub2e4. \ubaa8\ub4c8\ud654\ub41c \uac83\uc744 \uc0ac\uc6a9\ud558\ub294 \uac83\uc740 \uc5b8\uc81c\ub098 \uc88b\uc740 \uc77c\uc785\ub2c8\ub2e4.<\/p>\n<p>\ub2e4\uc74c\uacfc \uac19\uc774 \uac00\uc815\ud569\ub2c8\ub2e4. <a href=\"https:\/\/cli.angular.io\/\" target=\"_blank\" rel=\"noopener noreferrer\">\uc575\uade4\ub7ec CLI<\/a> \uc124\uce58 \ubc0f \uad6c\uc131\uc774 \uc644\ub8cc\ub418\uba74 \uc0c8 \ud504\ub85c\uc81d\ud2b8\uac00 \ud544\uc694\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">ng new couchbase-project<\/pre>\n<p>\uc704\uc758 \uba85\ub839\uc740 \ud544\uc694\ud55c \ubaa8\ub4e0 Angular \uc885\uc18d\uc131\uc744 \ud3ec\ud568\ud558\ub294 \uc0c8 \ud504\ub85c\uc81d\ud2b8\ub97c \uc0dd\uc131\ud569\ub2c8\ub2e4.<\/p>\n<p>\uc774 \uc2dc\uc810\uc5d0\uc11c CLI\ub97c \uc0ac\uc6a9\ud558\uc5ec \uac01 \ud398\uc774\uc9c0\ub97c \uc0dd\uc131\ud558\uac70\ub098 \uc218\ub3d9\uc73c\ub85c \uc0dd\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \ub450 \uac00\uc9c0 \ubc29\ubc95 \ubaa8\ub450 \uac19\uc740 \uc704\uce58\uc5d0 \ub193\uc774\uac8c \ub429\ub2c8\ub2e4.<\/p>\n<p>\ud504\ub85c\uc81d\ud2b8\uc5d0 \ub2e4\uc74c \ud30c\uc77c\uacfc \ub514\ub809\ud130\ub9ac\ub97c \uc6d0\ud558\ub294 \ub300\ub85c \uc0dd\uc131\ud558\uc138\uc694:<\/p>\n<pre class=\"lang:default decode:true\">mkdir -p src\/app\/list\r\nmkdir -p src\/app\/alter\r\ntouch src\/app\/list\/list.component.ts\r\ntouch src\/app\/list\/list.component.html\r\ntouch src\/app\/alter\/alter.component.ts\r\ntouch src\/app\/alter\/alter.component.html<\/pre>\n<p>\ubb34\uc5c7\ubd80\ud130 \uc2dc\uc791\ud560\uae4c\uc694?\u00a0<code>\uc54c\ud130 \ucef4\ud3ec\ub10c\ud2b8<\/code>\ub97c \ud074\ub9ad\ud558\uace0 \ud504\ub85c\uc81d\ud2b8\uc758\u00a0<strong>src\/app\/alter\/alter.component.ts<\/strong> \ud30c\uc77c\uc744 \uc5f4\uace0 \ub2e4\uc74c TypeScript \ucf54\ub4dc\ub97c \ud3ec\ud568\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">import { Component, OnInit } from \"@angular\/core\";\r\nimport { Http, Headers, RequestOptions } from \"@angular\/http\";\r\nimport { Location } from \"@angular\/common\";\r\nimport { ActivatedRoute } from \"@angular\/router\";\r\nimport \"rxjs\/Rx\";\r\n\r\n@Component({\r\n    moduleId: module.id,\r\n    templateUrl: \"alter.component.html\"\r\n})\r\nexport class AlterComponent implements OnInit {\r\n\r\n    public id: string;\r\n    public input: any;\r\n\r\n    public constructor(private http: Http, private location: Location, private route: ActivatedRoute) {\r\n        this.id = \"\";\r\n        this.input = {\r\n            \"firstname\": \"\",\r\n            \"lastname\": \"\",\r\n            \"social_media\": {\r\n                \"website\": \"\",\r\n                \"twitter\": \"\"\r\n            }\r\n        };\r\n    }\r\n\r\n    public ngOnInit() {\r\n        this.route.params.subscribe(params =&gt; {\r\n            this.id = params[\"id\"];\r\n            if(this.id) {\r\n                this.http.get(\"https:\/\/localhost:3000\/person\/\" + this.id)\r\n                    .map(result =&gt; result.json())\r\n                    .subscribe(result =&gt; {\r\n                        this.input = result instanceof Array ? result[0] : result;\r\n                    });\r\n            }\r\n        });\r\n    }\r\n\r\n    public save() {\r\n        let headers = new Headers({ \"Content-Type\": \"application\/json\" });\r\n        let options = new RequestOptions({ headers: headers });\r\n        let url = \"https:\/\/localhost:3000\/person\/\";\r\n        if(this.id) {\r\n            url += this.id;\r\n        }\r\n        if(this.input.firstname &amp;&amp; this.input.lastname) {\r\n            this.http.post(url, JSON.stringify(this.input), options)\r\n                .map(result =&gt; result.json())\r\n                .subscribe(result =&gt; {\r\n                    this.location.back();\r\n                });\r\n        }\r\n    }\r\n\r\n}<\/pre>\n<p>\uc704\uc758 \ucf54\ub4dc\uc5d0\ub294 \ub9ce\uc740 \uc77c\uc774 \uc77c\uc5b4\ub098\uace0 \uc788\uc73c\ubbc0\ub85c \uc774\ub97c \uc138\ubd84\ud654\ud574 \ubcf4\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ub0b4\ubd80\u00a0<code>\uc0dd\uc131\uc790<\/code> \uba54\uc11c\ub4dc\uc5d0\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \uac83\uc774 \uc788\uc2b5\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">public constructor(private http: Http, private location: Location, private route: ActivatedRoute) {\r\n    this.id = \"\";\r\n    this.input = {\r\n        \"firstname\": \"\",\r\n        \"lastname\": \"\",\r\n        \"social_media\": {\r\n            \"website\": \"\",\r\n            \"twitter\": \"\"\r\n        }\r\n    };\r\n}<\/pre>\n<p>\uc591\uc2dd \ub370\uc774\ud130\ub97c \ub098\ud0c0\ub0b4\ub294 \uacf5\uac1c \ubcc0\uc218\uc640 \uae30\uc874 \ubb38\uc11c\uc758 \uac00\ub2a5\ud55c ID\ub97c \ub098\ud0c0\ub0b4\ub294 \uacf5\uac1c \ubcc0\uc218\ub97c \ucd08\uae30\ud654\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \uc678\uc5d0\ub3c4 \ucef4\ud3ec\ub10c\ud2b8\uc5d0\uc11c \uc0ac\uc6a9\ud560 \uc5ec\ub7ec Angular \uc11c\ube44\uc2a4\ub3c4 \uc8fc\uc785\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ub2e4\uc2dc \ud55c \ubc88, \uc6b0\ub9ac\ub294 \uc77c\uc11d\uc774\uc870\uc758 \ud6a8\uacfc\ub97c \ub178\ub9ac\ub824\uace0 \ud569\ub2c8\ub2e4. \uc774 \uad6c\uc131 \uc694\uc18c\ub294 \ubb38\uc11c\ub97c \ub9cc\ub4e4\uace0 \uc5c5\ub370\uc774\ud2b8\ud558\ub294 \ud654\uba74\uc744 \ub098\ud0c0\ub0c5\ub2c8\ub2e4.<\/p>\n<p>\ub0b4\u00a0<code>ngOnInit<\/code> \uba54\uc11c\ub4dc\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc7a0\uc7ac\uc801\uc778 \ubb38\uc11c ID\ub97c \uac00\uc838\uc640 \ud574\ub2f9 \ubb38\uc11c\uc5d0 \uc788\ub294 \ub370\uc774\ud130\ub97c \uc870\ud68c\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">public ngOnInit() {\r\n    this.route.params.subscribe(params =&gt; {\r\n        this.id = params[\"id\"];\r\n        if(this.id) {\r\n            this.http.get(\"https:\/\/localhost:3000\/person\/\" + this.id)\r\n                .map(result =&gt; result.json())\r\n                .subscribe(result =&gt; {\r\n                    this.input = result instanceof Array ? result[0] : result;\r\n                });\r\n        }\r\n    });\r\n}<\/pre>\n<p>\uc544\uc774\ub514\uac00 \uc5c6\uc73c\uba74 \uc544\ubb34 \uc77c\ub3c4 \uc77c\uc5b4\ub098\uc9c0 \uc54a\uc73c\uba70, \uc800\ud76c\uc758\u00a0<code>\uc785\ub825<\/code> \ubcc0\uc218\ub294 \ube48 \ubb38\uc790\uc5f4 \uc678\uc5d0\ub294 \uc544\ubb34\uac83\ub3c4 \ucc44\uc6cc\uc9c0\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. \uc870\ud68c\ub294 \uc774\uc804\uc5d0 Ottoman.js \ub610\ub294 N1QL\ub85c \uc0dd\uc131\ud55c API \uc5d4\ub4dc\ud3ec\uc778\ud2b8\uc5d0 \ub300\ud55c HTTP \uc694\uccad\uc774 \ub429\ub2c8\ub2e4.<\/p>\n<p>\uc774 \uad6c\uc131 \uc694\uc18c\uc758 \ub9c8\uc9c0\ub9c9 \uc791\uc5c5\uc740 \uc800\uc7a5\uc785\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">public save() {\r\n    let headers = new Headers({ \"Content-Type\": \"application\/json\" });\r\n    let options = new RequestOptions({ headers: headers });\r\n    let url = \"https:\/\/localhost:3000\/person\/\";\r\n    if(this.id) {\r\n        url += this.id;\r\n    }\r\n    if(this.input.firstname &amp;&amp; this.input.lastname) {\r\n        this.http.post(url, JSON.stringify(this.input), options)\r\n            .map(result =&gt; result.json())\r\n            .subscribe(result =&gt; {\r\n                this.location.back();\r\n            });\r\n    }\r\n}<\/pre>\n<p>ID\uac00 \uc788\ub294 \uacbd\uc6b0 POST \uc694\uccad\uacfc \ud568\uaed8 \uc804\ub2ec\ud569\ub2c8\ub2e4. POST \uc694\uccad\uc5d0\ub294 \uc9c1\ub82c\ud654\ub41c \uc591\uc2dd \ub370\uc774\ud130\uac00 \ud3ec\ud568\ub429\ub2c8\ub2e4. \uc694\uccad\uc774 \uc131\uacf5\ud558\uba74 \uc774\uc804 \ud654\uba74\uc73c\ub85c \uc774\ub3d9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\uc774 \ud0c0\uc785\uc2a4\ud06c\ub9bd\ud2b8 \ub85c\uc9c1\uacfc \ud568\uaed8 \uc0ac\uc6a9\ub418\ub294 HTML\uc740 \ud504\ub85c\uc81d\ud2b8\uc758\u00a0<strong>src\/app\/alter\/alter.component.html<\/strong> \ud30c\uc77c\uc744 \uc5f4\uba74 \ub2e4\uc74c\uacfc \uac19\uc774 \ud45c\uc2dc\ub429\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">&lt;form&gt;\r\n    &lt;input type=\"text\" name=\"firstname\" placeholder=\"First Name\" [(ngModel)]=\"input.firstname\" \/&gt;\r\n    &lt;input type=\"text\" name=\"lastname\" placeholder=\"Last Name\" [(ngModel)]=\"input.lastname\" \/&gt;\r\n    &lt;input type=\"text\" name=\"website\" placeholder=\"Website\" [(ngModel)]=\"input.social_media.website\" \/&gt;\r\n    &lt;input type=\"text\" name=\"twitter\" placeholder=\"Twitter\" [(ngModel)]=\"input.social_media.twitter\" \/&gt;\r\n    &lt;button type=\"button\" (click)=\"save()\"&gt;Save&lt;\/button&gt;\r\n&lt;\/form&gt;<\/pre>\n<p>\uc800\ub294 \uc544\ud2f0\uc2a4\ud2b8\uac00 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc774 HTML\uc740 \ub9e4\uc6b0 \uae30\ubcf8\uc801\uc774\uace0 \uc2a4\ud0c0\uc77c\uc774 \uc804\ud600 \uc801\uc6a9\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \uac01 \uc591\uc2dd \uc694\uc18c\ub294 \uacf5\uac1c\uc801\uc73c\ub85c \ubc14\uc778\ub529\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.\u00a0<code>\uc785\ub825<\/code> \uac1d\uccb4\uc785\ub2c8\ub2e4.<\/p>\n<p>\ud504\ub85c\uc81d\ud2b8\uc758 \ub450 \ubc88\uc9f8\uc774\uc790 \ub9c8\uc9c0\ub9c9 \uad6c\uc131 \uc694\uc18c\ub294 \uc800\uc7a5\ub41c \ubb38\uc11c\ub97c \ub098\uc5f4\ud558\ub294 \uac83\uc785\ub2c8\ub2e4. \ud504\ub85c\uc81d\ud2b8\uc758\u00a0<strong>src\/app\/list\/list.component.ts<\/strong> \ud30c\uc77c\uc744 \uc5f4\uace0 \ub2e4\uc74c TypeScript \ucf54\ub4dc\ub97c \ud3ec\ud568\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">import { Component, OnInit } from \"@angular\/core\";\r\nimport { Http } from \"@angular\/http\";\r\nimport { Location } from \"@angular\/common\";\r\nimport \"rxjs\/Rx\";\r\n\r\n@Component({\r\n    moduleId: module.id,\r\n    templateUrl: \"list.component.html\"\r\n})\r\nexport class ListComponent implements OnInit {\r\n\r\n    public people: Array&lt;any&gt;;\r\n\r\n    public constructor(private http: Http, private location: Location) {\r\n        this.people = [];\r\n    }\r\n\r\n    public ngOnInit() {\r\n        this.location.subscribe(() =&gt; {\r\n            this.getPeople();\r\n        });\r\n        this.getPeople();\r\n    }\r\n\r\n    private getPeople() {\r\n        this.http.get(\"https:\/\/localhost:3000\/people\")\r\n            .map(result =&gt; result.json())\r\n            .subscribe(result =&gt; {\r\n                this.people = result;\r\n            });\r\n    }\r\n\r\n    private delete(id: string) {\r\n        this.http.delete(\"https:\/\/localhost:3000\/person\/\" + id)\r\n            .map(result =&gt; result.json())\r\n            .subscribe(result =&gt; {\r\n                for(let i = 0; i &lt; this.people.length; i++) {\r\n                    if(this.people[i]._id == id) {\r\n                        this.people.splice(i, 1);\r\n                        break;\r\n                    }\r\n                }\r\n            });\r\n    }\r\n\r\n}<\/pre>\n<p>\ub2e4\uc2dc \ud55c \ubc88 \uc790\uc138\ud788 \uc124\uba85\ud574 \ub4dc\ub9ac\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ub0b4\u00a0<code>\uc0dd\uc131\uc790<\/code> \uba54\uc11c\ub4dc\ub97c \uc0ac\uc6a9\ud558\uc5ec \uacf5\uc6a9 \ubcc0\uc218\ub97c \ucd08\uae30\ud654\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">public constructor(private http: Http, private location: Location) {\r\n    this.people = [];\r\n}<\/pre>\n<p>\uc774 \uacbd\uc6b0 \uacf5\uac1c \ubcc0\uc218\ub294 \ud654\uba74\uc5d0 \ud45c\uc2dc\ub418\ub294 \ubb38\uc11c \ubaa9\ub85d\uc785\ub2c8\ub2e4. \ub2e4\uc74c \ub2e8\uacc4\ub294 \uc874\uc7ac\ud560 \uac00\ub2a5\uc131\uc774 \uc788\ub294 \uc0ac\ub78c\uc744 \ucffc\ub9ac\ud558\uc5ec \ud604\uc7ac \ube44\uc5b4 \uc788\ub294 \ubc30\uc5f4\uc744 \ucc44\uc6b0\ub294 \uac83\uc785\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">private getPeople() {\r\n    this.http.get(\"https:\/\/localhost:3000\/people\")\r\n        .map(result =&gt; result.json())\r\n        .subscribe(result =&gt; {\r\n            this.people = result;\r\n        });\r\n}<\/pre>\n<p>\uc9c0\uae08\ucbe4\uc774\uba74 \ud504\ub860\ud2b8\uc5d4\ub4dc\ub294 \ub300\ubd80\ubd84 API\uc5d0 \ub300\ud55c HTTP \uc694\uccad\uc5d0 \ubd88\uacfc\ud558\ub2e4\ub294 \uac83\uc744 \ub208\uce58\ucc44\uc168\uc744 \uac83\uc785\ub2c8\ub2e4. \ubc31\uc5d4\ub4dc\ub294 \ub300\ubd80\ubd84\uc758 \ubb34\uac70\uc6b4 \uc791\uc5c5\uc744 \ucc98\ub9ac\ud569\ub2c8\ub2e4.<\/p>\n<p>\uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc774 \ub85c\ub4dc\ub420 \ub54c\uc640 Angular \ud0d0\uc0c9 \uc2a4\ud0dd\uc5d0\uc11c \ub4a4\ub85c \uc774\ub3d9\ud560 \ub54c \ubaa8\ub450 \ubb38\uc11c\ub97c \ucffc\ub9ac\ud574\uc57c \ud569\ub2c8\ub2e4. \uc774\ub294\u00a0<code>ngOnInit<\/code> \uba54\uc11c\ub4dc\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">public ngOnInit() {\r\n    this.location.subscribe(() =&gt; {\r\n        this.getPeople();\r\n    });\r\n    this.getPeople();\r\n}<\/pre>\n<p>\uac70\uafb8\ub85c \uc774\ub3d9\ud55c \uc2dc\uc810\uc744 \ud655\uc778\ud560 \uc218 \uc788\ub3c4\ub85d \uc704\uce58 \ub9ac\uc2a4\ub108\ub97c \uad6c\ub3c5\ud574\uc57c \ud569\ub2c8\ub2e4. \uc774\ub807\uac8c \ud558\ub294 \uc774\uc720\ub294\u00a0<code>\uc0dd\uc131\uc790<\/code> \uadf8\ub9ac\uace0\u00a0<code>ngOnInit<\/code> \uba54\uc11c\ub4dc\ub294 \ud0d0\uc0c9\ud560 \ub54c\ub9cc \ud2b8\ub9ac\uac70\ub418\uace0 \ub2e4\uc2dc \ud0d0\uc0c9\ud560 \ub54c\ub294 \ud2b8\ub9ac\uac70\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ubb38\uc11c \uc81c\uac70\ub85c \uc774\ub3d9\ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">private delete(id: string) {\r\n    this.http.delete(\"https:\/\/localhost:3000\/person\/\" + id)\r\n        .map(result =&gt; result.json())\r\n        .subscribe(result =&gt; {\r\n            for(let i = 0; i &lt; this.people.length; i++) {\r\n                if(this.people[i]._id == id) {\r\n                    this.people.splice(i, 1);\r\n                    break;\r\n                }\r\n            }\r\n        });\r\n}<\/pre>\n<p>HTML\uc5d0\uc11c\ub294 \ubaa8\ub4e0 \ubaa9\ub85d \ud56d\ubaa9 \uc606\uc5d0 \ubc84\ud2bc\uc774 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \ubc84\ud2bc\uc744 \uc0ac\uc6a9\ud558\uba74 \ubb38\uc11c\ub97c \uc81c\uac70\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\u00a0<code>\uc0ad\uc81c<\/code> \uba54\uc11c\ub4dc\ub97c \ud638\ucd9c\ud558\uace0 \ud2b9\uc815 \ubb38\uc11c ID\ub97c \uc804\ub2ec\ud569\ub2c8\ub2e4. \uc131\uacf5\ud558\uba74 \ud574\ub2f9 \ud56d\ubaa9\uc774 \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc640 \ubc30\uc5f4\uc5d0\uc11c \ub85c\uceec\ub85c \uc81c\uac70\ub429\ub2c8\ub2e4.<\/p>\n<p>\uc774 \ub85c\uc9c1 \ub4a4\uc5d0 \uc788\ub294 HTML\uc740 \ud504\ub85c\uc81d\ud2b8\uc758\u00a0<strong>src\/app\/list\/list.component.html<\/strong> \ub2e4\uc74c\uacfc \uac19\uc774 \ud45c\uc2dc\ub429\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\">&lt;a [routerlink]=&quot;[&#039;\/alter&#039;]&quot;&gt;\uc2e0\uaddc&lt;\/a&gt;\r\n&lt;ul&gt;\r\n    &lt;li *ngfor=&quot;let person of people&quot;&gt;\r\n        &lt;a [routerlink]=&quot;[&#039;\/alter&#039;, person._id]&quot;&gt;{{ person.firstname }}&lt;\/a&gt; - &lt;a style=&quot;cursor: pointer&quot; (click)=&quot;delete(person._id)&quot;&gt;\uc0ad\uc81c&lt;\/a&gt;\r\n    &lt;\/li&gt;\r\n&lt;\/ul&gt;<\/pre>\n<p>\uadf8\ub9ac\uace0\u00a0<code>\ub77c\uc6b0\ud130\ub9c1\ud06c<\/code> \uc18d\uc131\uc740 \ub370\uc774\ud130\ub97c \uc0dd\uc131\ud558\uac70\ub098 \uc5c5\ub370\uc774\ud2b8\ud560 \uc218 \uc788\ub294 \ud398\uc774\uc9c0\ub85c \uc774\ub3d9\ud569\ub2c8\ub2e4. \uadf8\ub7f0 \ub2e4\uc74c \ubc30\uc5f4\uc744 \ubc18\ubcf5\ud558\uc5ec \uac01 \ubb38\uc11c\ub97c \ud654\uba74\uc5d0 \ud45c\uc2dc\ud569\ub2c8\ub2e4. \ud56d\ubaa9\uc744 \ud074\ub9ad\ud558\uba74 \uc5c5\ub370\uc774\ud2b8 \ud398\uc774\uc9c0\ub85c \uc774\ub3d9\ud558\uc5ec \ud074\ub9ad\ud55c \ubb38\uc11c\uc758 ID\ub97c \uc804\ub2ec\ud569\ub2c8\ub2e4. \uc774\ub807\uac8c \ud558\uba74 \uc591\uc2dd\uc744 \ubbf8\ub9ac \ucc44\uc6b8 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74 \ubb38\uc11c\ub97c \uc0ad\uc81c\ud558\ub824\uba74 \ub2e4\ub978 \ubc84\ud2bc\uc744 \ud074\ub9ad\ud569\ub2c8\ub2e4.<\/p>\n<p>\ud575\uc2ec \ucf58\ud150\uce20\ub294 \uc575\uade4\ub7ec\ub97c \ud1b5\ud574 \uc774\ub8e8\uc5b4\uc9c0\uc9c0\ub9cc, \uc575\uade4\ub7ec \ub77c\uc6b0\ud130\ub97c \ud1b5\ud574 \uc774\ub97c \ud1b5\ud569\ud574\uc57c \ud569\ub2c8\ub2e4.<\/p>\n<p>\ud504\ub85c\uc81d\ud2b8\uc758\u00a0<strong>src\/app\/app.module.ts<\/strong> \ud30c\uc77c\uc744 \uc5f4\uace0 \ub2e4\uc74c\uc744 \ud3ec\ud568\ud558\uc138\uc694:<\/p>\n<pre class=\"lang:default decode:true\">import { BrowserModule } from '@angular\/platform-browser';\r\nimport { NgModule } from '@angular\/core';\r\nimport { RouterModule } from \"@angular\/router\";\r\nimport { HttpModule } from \"@angular\/http\";\r\nimport { FormsModule } from \"@angular\/forms\";\r\n\r\nimport { AppComponent } from '.\/app.component';\r\nimport { ListComponent } from \".\/list\/list.component\";\r\nimport { AlterComponent } from \".\/alter\/alter.component\";\r\n\r\nconst routes = [\r\n    { path: \"\", component: ListComponent },\r\n    { path: \"alter\", component: AlterComponent },\r\n    { path: \"alter\/:id\", component: AlterComponent }\r\n];\r\n\r\n@NgModule({\r\n    declarations: [\r\n        AppComponent,\r\n        ListComponent,\r\n        AlterComponent\r\n    ],\r\n    imports: [\r\n        BrowserModule,\r\n        HttpModule,\r\n        RouterModule,\r\n        FormsModule,\r\n        RouterModule.forRoot(routes)\r\n    ],\r\n    providers: [],\r\n    bootstrap: [AppComponent]\r\n})\r\nexport class AppModule { }<\/pre>\n<p>\ubc29\uae08 \ucef4\ud3ec\ub10c\ud2b8\ub97c \uac00\uc838\uc624\uace0 \uac01 \ucef4\ud3ec\ub10c\ud2b8\uc5d0 \ub300\ud55c \uacbd\ub85c\ub97c \uc815\uc758\ud55c \uac83\uc744 \uc54c \uc218 \uc788\uc2b5\ub2c8\ub2e4. \ub108\ubb34 \uac70\ucc3d\ud55c \uac83\uc740 \uc5c6\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\uc0ac\uc6a9 \uc911\uc778 Angular CLI \ubc84\uc804\uc5d0 \ub530\ub77c \ud504\ub85c\uc81d\ud2b8\uc758\u00a0<strong>src\/app\/app.component.html<\/strong>\u00a0\ud30c\uc77c\uc5d0 \ub2e4\uc74c\uc744 \ud3ec\ud568\ud558\ub3c4\ub85d \ud569\ub2c8\ub2e4:<\/p>\n<pre class=\"lang:default decode:true\"><\/\ub77c\uc6b0\ud130-\uc544\uc6c3\ub81b><\/pre>\n<p>\uc774\ub807\uac8c \ud558\uba74 \ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c \ub0b4\ube44\uac8c\uc774\uc158\uc774 \uc791\ub3d9\ud569\ub2c8\ub2e4.<\/p>\n<h2>\uacb0\ub860<\/h2>\n<p>\ubc29\uae08 \uc81c\uac00 OCEAN \uc2a4\ud0dd\uacfc CEAN \uc2a4\ud0dd\uc5d0 \ub300\ud574 \ubc1c\ud45c\ud588\ub358 \uc790\ub8cc\ub97c \ubcf4\uc168\uc744 \uac81\ub2c8\ub2e4. <a href=\"https:\/\/www.meetup.com\/AngularJS-OC\/events\/240799354\/\" target=\"_blank\" rel=\"noopener noreferrer\">\uc575\uade4\ub7ec \uc624\ub80c\uc9c0 \uce74\uc6b4\ud2f0<\/a> \uadf8\ub8f9\uacfc <a href=\"https:\/\/www.meetup.com\/Couchbase-Los-Angeles\/events\/241028595\/\" target=\"_blank\" rel=\"noopener noreferrer\">\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ub85c\uc2a4\uc564\uc824\ub808\uc2a4<\/a> \uadf8\ub8f9.<\/p>\n<p>MongoDB \uac1c\ubc1c\uc790\uc774\uace0 Couchbase\ub97c \ucc98\uc74c \uc0b4\ud3b4\ubcf4\uace0 \uacc4\uc2e0\ub2e4\uba74 <a href=\"https:\/\/labs.couchbase.com\/mongodb-to-couchbase-cookbook\/\" target=\"_blank\" rel=\"noopener noreferrer\">\uc694\ub9ac\ucc45<\/a> MongoDB\uc5d0\uc11c \uc774\ub3d9\ud558\ub294 \ubc29\ubc95\uc744 \uc124\uba85\ud558\uba74\uc11c Ottoman.js\uc640 N1QL\uc5d0 \ub300\ud574 \uc790\uc138\ud788 \uc124\uba85\ud558\ub294 \uae00\uc744 \uc37c\ub358 \uc801\uc774 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>Couchbase \ubc0f Node.js\uc5d0 \ub300\ud55c \uc790\uc138\ud55c \ub0b4\uc6a9\uc740 \ub2e4\uc74c\uc744 \ud655\uc778\ud558\uc138\uc694. <a href=\"https:\/\/www.couchbase.com\/blog\/ko\/developers\/\" target=\"_blank\" rel=\"noopener noreferrer\">\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \uac1c\ubc1c\uc790 \ud3ec\ud138<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>I was recently at two different Meetup groups in Southern California presenting on what I&#8217;m calling, the OCEAN stack, which is composed of Ottoman.js, Couchbase Server, Express Framework, Angular, and Node.js. We had a great turnout of developers hungry to [&hellip;]<\/p>","protected":false},"author":63,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,1816,1822,1812],"tags":[1719,1349,1725],"ppma_author":[9032],"class_list":["post-3841","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-couchbase-server","category-node-js","category-n1ql-query","tag-cean","tag-development","tag-nosql-database"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Couchbase Meetup Project on the OCEAN Stack Available<\/title>\n<meta name=\"description\" content=\"See how to build an API using Ottoman.js and then with N1QL instead of Ottoman.js. Both APIs will be consumed by a front-end developed in Angular.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/ko\/couchbase-meetup-project-ocean-stack-available\/\" \/>\n<meta property=\"og:locale\" content=\"ko_KR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Couchbase Meetup Project on the OCEAN Stack Available\" \/>\n<meta property=\"og:description\" content=\"See how to build an API using Ottoman.js and then with N1QL instead of Ottoman.js. Both APIs will be consumed by a front-end developed in Angular.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/ko\/couchbase-meetup-project-ocean-stack-available\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/thepolyglotdeveloper\" \/>\n<meta property=\"article:published_time\" content=\"2017-07-20T14:00:11+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T01:46:03+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/07\/oc-angular-meetup.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"549\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@nraboy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9\ubd84\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/\"},\"author\":{\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\"},\"headline\":\"Couchbase Meetup Project on the OCEAN Stack Available\",\"datePublished\":\"2017-07-20T14:00:11+00:00\",\"dateModified\":\"2025-06-14T01:46:03+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/\"},\"wordCount\":2004,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"CEAN\",\"Development\",\"NoSQL Database\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Server\",\"Node.js\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/\",\"name\":\"Couchbase Meetup Project on the OCEAN Stack Available\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2017-07-20T14:00:11+00:00\",\"dateModified\":\"2025-06-14T01:46:03+00:00\",\"description\":\"See how to build an API using Ottoman.js and then with N1QL instead of Ottoman.js. Both APIs will be consumed by a front-end developed in Angular.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#breadcrumb\"},\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Couchbase Meetup Project on the OCEAN Stack Available\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ko-KR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\",\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"caption\":\"Nic Raboy, Developer Advocate, Couchbase\"},\"description\":\"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.\",\"sameAs\":[\"https:\/\/www.thepolyglotdeveloper.com\",\"https:\/\/www.facebook.com\/thepolyglotdeveloper\",\"https:\/\/x.com\/nraboy\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/ko\/author\/nic-raboy-2\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ubc0b\uc5c5 \ud504\ub85c\uc81d\ud2b8\uac00 OCEAN \uc2a4\ud0dd\uc5d0\uc11c \uc9c4\ud589\ub429\ub2c8\ub2e4.","description":"Ottoman.js\ub97c \uc0ac\uc6a9\ud558\uc5ec API\ub97c \ube4c\ub4dc\ud55c \ub2e4\uc74c Ottoman.js \ub300\uc2e0 N1QL\uc744 \uc0ac\uc6a9\ud558\uc5ec API\ub97c \ube4c\ub4dc\ud558\ub294 \ubc29\ubc95\uc744 \ucc38\uc870\ud558\uc138\uc694. \ub450 API \ubaa8\ub450 Angular\ub85c \uac1c\ubc1c\ub41c \ud504\ub7f0\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \uc0ac\uc6a9\ud558\uac8c \ub429\ub2c8\ub2e4.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/ko\/couchbase-meetup-project-ocean-stack-available\/","og_locale":"ko_KR","og_type":"article","og_title":"Couchbase Meetup Project on the OCEAN Stack Available","og_description":"See how to build an API using Ottoman.js and then with N1QL instead of Ottoman.js. Both APIs will be consumed by a front-end developed in Angular.","og_url":"https:\/\/www.couchbase.com\/blog\/ko\/couchbase-meetup-project-ocean-stack-available\/","og_site_name":"The Couchbase Blog","article_author":"https:\/\/www.facebook.com\/thepolyglotdeveloper","article_published_time":"2017-07-20T14:00:11+00:00","article_modified_time":"2025-06-14T01:46:03+00:00","og_image":[{"width":1200,"height":549,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/07\/oc-angular-meetup.jpg","type":"image\/jpeg"}],"author":"Nic Raboy, Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_creator":"@nraboy","twitter_misc":{"Written by":"Nic Raboy, Developer Advocate, Couchbase","Est. reading time":"9\ubd84"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/"},"author":{"name":"Nic Raboy, Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1"},"headline":"Couchbase Meetup Project on the OCEAN Stack Available","datePublished":"2017-07-20T14:00:11+00:00","dateModified":"2025-06-14T01:46:03+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/"},"wordCount":2004,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["CEAN","Development","NoSQL Database"],"articleSection":["Best Practices and Tutorials","Couchbase Server","Node.js","SQL++ \/ N1QL Query"],"inLanguage":"ko-KR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/","url":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/","name":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ubc0b\uc5c5 \ud504\ub85c\uc81d\ud2b8\uac00 OCEAN \uc2a4\ud0dd\uc5d0\uc11c \uc9c4\ud589\ub429\ub2c8\ub2e4.","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2017-07-20T14:00:11+00:00","dateModified":"2025-06-14T01:46:03+00:00","description":"Ottoman.js\ub97c \uc0ac\uc6a9\ud558\uc5ec API\ub97c \ube4c\ub4dc\ud55c \ub2e4\uc74c Ottoman.js \ub300\uc2e0 N1QL\uc744 \uc0ac\uc6a9\ud558\uc5ec API\ub97c \ube4c\ub4dc\ud558\ub294 \ubc29\ubc95\uc744 \ucc38\uc870\ud558\uc138\uc694. \ub450 API \ubaa8\ub450 Angular\ub85c \uac1c\ubc1c\ub41c \ud504\ub7f0\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \uc0ac\uc6a9\ud558\uac8c \ub429\ub2c8\ub2e4.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#breadcrumb"},"inLanguage":"ko-KR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/"]}]},{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-meetup-project-ocean-stack-available\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Couchbase Meetup Project on the OCEAN Stack Available"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ube14\ub85c\uadf8","description":"NoSQL \ub370\uc774\ud130\ubca0\uc774\uc2a4, Couchbase","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ko-KR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ube14\ub85c\uadf8","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1","name":"Nic Raboy, \uac1c\ubc1c\uc790 \uc639\ud638\uc790, Couchbase","image":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354","url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","caption":"Nic Raboy, Developer Advocate, Couchbase"},"description":"\ub2c9 \ub77c\ubcf4\uc774\ub294 \ucd5c\uc2e0 \uc6f9 \ubc0f \ubaa8\ubc14\uc77c \uac1c\ubc1c \uae30\uc220\uc744 \uc639\ud638\ud558\ub294 \uc0ac\ub78c\uc785\ub2c8\ub2e4. \uadf8\ub294 Java, JavaScript, Golang \ubc0f Angular, NativeScript, Apache Cordova\uc640 \uac19\uc740 \ub2e4\uc591\ud55c \ud504\ub808\uc784\uc6cc\ud06c\uc5d0 \ub300\ud55c \uacbd\ud5d8\uc774 \uc788\uc2b5\ub2c8\ub2e4. Nic\uc740 \uc6f9 \ubc0f \ubaa8\ubc14\uc77c \uac1c\ubc1c\uc744 \ubcf4\ub2e4 \uc27d\uac8c \uc774\ud574\ud560 \uc218 \uc788\ub3c4\ub85d \uc790\uc2e0\uc758 \uac1c\ubc1c \uacbd\ud5d8\uc5d0 \ub300\ud574 \uae00\uc744 \uc4f0\uace0 \uc788\uc2b5\ub2c8\ub2e4.","sameAs":["https:\/\/www.thepolyglotdeveloper.com","https:\/\/www.facebook.com\/thepolyglotdeveloper","https:\/\/x.com\/nraboy"],"url":"https:\/\/www.couchbase.com\/blog\/ko\/author\/nic-raboy-2\/"}]}},"authors":[{"term_id":9032,"user_id":63,"is_guest":0,"slug":"nic-raboy-2","display_name":"Nic Raboy, Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","author_category":"","last_name":"Raboy","first_name":"Nic","job_title":"","user_url":"https:\/\/www.thepolyglotdeveloper.com","description":"\ub2c9 \ub77c\ubcf4\uc774\ub294 \ucd5c\uc2e0 \uc6f9 \ubc0f \ubaa8\ubc14\uc77c \uac1c\ubc1c \uae30\uc220\uc744 \uc639\ud638\ud558\ub294 \uc0ac\ub78c\uc785\ub2c8\ub2e4. \uadf8\ub294 Java, JavaScript, Golang \ubc0f Angular, NativeScript, Apache Cordova\uc640 \uac19\uc740 \ub2e4\uc591\ud55c \ud504\ub808\uc784\uc6cc\ud06c\uc5d0 \ub300\ud55c \uacbd\ud5d8\uc774 \uc788\uc2b5\ub2c8\ub2e4. Nic\uc740 \uc6f9 \ubc0f \ubaa8\ubc14\uc77c \uac1c\ubc1c\uc744 \ubcf4\ub2e4 \uc27d\uac8c \uc774\ud574\ud560 \uc218 \uc788\ub3c4\ub85d \uc790\uc2e0\uc758 \uac1c\ubc1c \uacbd\ud5d8\uc5d0 \ub300\ud574 \uae00\uc744 \uc4f0\uace0 \uc788\uc2b5\ub2c8\ub2e4."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/3841","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/users\/63"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/comments?post=3841"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/3841\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media?parent=3841"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/categories?post=3841"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/tags?post=3841"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/ppma_author?post=3841"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}