이머시브코스 TIL 8주차 모음
Model
View
controller
var Sequelize = require('sequelize');
var db = new Sequelize('chatter', 'root', 'root');
var User = db.define('User', {
username: Sequelize.STRING
});
var Message = db.define('Message', {
userid: Sequelize.INTEGER,
text: Sequelize.STRING,
roomname: Sequelize.STRING
});
User.sync()
.then(function(){
return User.create({username: 'Jean Valjean'});
})
.then(function(){
return User.findAll({where: {username: 'Jean Valjean'} });
})
.then(function(users){
users.forEach(function(user){
console.log(user.username + ' exists');
});
db.close();
})
.catch(function(err){
console.error(err);
db.close();
});
1. 데이터의 구조가 거의 또는 전혀 없는 대용량의 데이터를 저장하는 경우
2. 클라우드 컴퓨팅 및 저장공간을 최대한 활용하는 경우
3. 빠르게 서비스를 구축하고 데이터 구조를 자주 업데이트하는 경우
필드(Field) : 데이터포인트를 위한 고유한 식별자
값(value) : 주어진 식별자와 관계된 데이터
도큐먼트(Document) : 필드 - 값 쌍으로 저장된 데이터
컬렉션(Collection) : MongoDB의 도큐먼트로 구성된 저장소
BSON(Binary JSON) : JSON보다 메모리 사용에 효율적이며, 빠르고 가볍우며 유연
⇒ MongoDB는 JSON형식으로 작성된 것은 무엇이든 데이터베이스에 추가할 수 있고, 조회할 수 있지만, 속도, 효율성, 유연성의 장점이 있기 때문에 내부적으로 BSON 형식으로 데이터를 저장하고 사용
mongoimport : 데이터베이스를 아틀라스 클러스터로 가져올 수 있도록 함
mongoexport : JSON 형식의 데이터를 아틀라스 클러스터에서 내보낼 때 사용
mongorestore : mongodump가 생성한 BSON 형식의 데이터를 가져옴
mongodump : BSON 형식의 데이터를 내보낼 때 사용
레플리카 세트 : 동일한 데이터를 저장하는 소수의 연결된 머신들은 머신 중 하나에 문제가 발생하더라도 데이터가 그대로 유지되도록 함인스턴스 : 특정 소프트웨어를 실행하는 로컬 또는 클라우드의 단일 머신이고, 이 경우 인스턴스는 클라우드에서 실행되는 MongoDB 데이터베이스클러스터 : 데이터를 저장하는 서버 그룹// 몽고디비 연결(myFirstDatabase가 디비이름)
~ mongo "mongodb+srv://cluster0.bp3j7.mongodb.net/myFirstDatabase" --username root
> show dbs
> use 디비이름
> show collections
// inspections 컬렉션에 추가
> db.inspection.insert({"_id":"1","test":"1"})
// 다수의 도큐먼트 삽입
> db.inspection.insert([{"test":"1"},{"test":"2"},{"test":"3"}])
// 두번째 파라미터에 ordered 옵션 추가
// 순서에 상관없이 고유한 _id를 가진 도큐먼트는 모두 컬렉션에 삽입
> db.inspections.insert([{"_id" : "1", "test": "1"}, {"_id" : "1", "test": "2"}, {"_id" : "3", "test": "3"}],
{"ordered":false})
// zips 컬렉션에 데이터 읽기
> db.zips.find()
// 좀 더 보기 편하게 출력해줌
> db.zips.find().pretty()
// 데이터의 수 조회
> db.zips.find().count()
// state가 NY인 데이터 찾기(+조건문 한개이상)
> db.zips.find({"state":"NY"})
> db.zips.find({"state":"NY","city":"ALBANY"})
// find 명령어는 실제 데이터 중에서 랜덤하게 선택된 20개 결과물만 출력함
// findOne() 무작위의 데이터 1개만 가져오기
> db.zips.findOne()
// 특정한 데이터 1개 가져오기
> db.zips.findOne({"_id":ObjectId("5c8eccc1caa187d17ca6eec1")})
// updateOne() 주어진 기준에 맞는 다수의 도큐먼트 중 첫번째 도큐먼트 하나만 업데이트
// updateMany() 쿼리문과 일치하는 모든 도큐먼트 업데이트
// city가 ALPINE인 데이터를 pop 필드를 10만큼 증가
> db.zips.updateMany({"city":"ALPINE"}, {"$inc":{"pop":10}})
// zip이 12534인 데이터를 pop 필드가 6235로 업데이트
> db.zips.updateOne({"zip":"12534"}, {"$set":{"pop":6235}})
// 만약 존재하지 않는 필드인 population이라고 실수로 적으면 오류가 나지않고 필드가 추가됨
> db.zips.updateOne({"zip":"12534"}, {"$set":{"population":6235}})
// grades 컬렉션에서 student_id가 250이고 class_id가 339인 데이터 하나를
// scores 필드의 값인 배열에 추가
> db.grades.updateOne({"student_id":250,"class_id":339},{"$push":{"scores":{"type":"extra credit","score":100}}})
$inc : 특정한 필드의 값을 원하는 만큼 증가시킬 수 있다
$set : 주어진 필드에 지정된 값을 업데이트
$push : 배열로 이루어진 필드의 값에서 요소(서브 도큐먼트)를 추가하기 위한 연산자
// deleteOne() 주어진 기준에 맞는 다수의 도큐먼트 중 첫번째 도큐먼트 하나를 삭제
// deleteMany() 쿼리문과 일치하는 모든 도큐먼트를 삭제
// _id 값으로 쿼리해 도큐먼트를 삭제하는 것이 좋은 접근법
// 만약 _id 값으로 쿼리하지 않는다면 검색 쿼리문에 다양한 도큐먼트가 적합할 수 있기 때문
> db.inspection.deleteOne({"_id":"1"})
// drop() 컬렉션 삭제
> db.collection_name.drop()
$eq = EQual to
$ne ≠ Not Equal to
$gt > Greater Than
$lt < Less Than
$gte ≥ Greater Than or Equal to
$lte ≤ Less Than or Equal to
> db.trips.find({"tripduration":{"$lte":70}, "usertype":{"$ne":"Subscriber"}}).pretty()
$and : 주어진 모든 쿼리절과 일치하는가(기본 연산자로 사용)
$or : 주어진 쿼리절 하나라도 일치하는가
$nor : 주어진 모든 쿼리절과 일치하지 않는가
$not : 주어진 쿼리와 일치하지 않는가
// result 필드 값이 "No Violation Issued"와 "Violation Issued"가 아닌 데이터
> db.inspections.find({$nor: [{result: "No Violation Issued"}, {result: "Violation Issued"}]}).pretty()
// class_id가 50보다 크고 100보다 작은 데이터($and 연산자 기본 적용)
> db.grades.find({class_id:{"$gt":50, "$lt":100}}).pretty()
// 동일한 연산자를 두 번 이상 포함해야 할 때는 $and 명시
{"$and":[{"$or":[{dis_airport:"ICN"},{src_airport:"ICN"}]},{"$or":[{airplane:"CR2"},{airplane:"A81"}]}]}
$expr : 변수와 조건문을 사용할 수도 있고, 같은 도큐먼트 내의 필드들을 서로 비교할 수 있음// start station id와 end station id가 같은 데이터
// $는 연산자를 나타낼 뿐만 아니라, 필드의 값을 참조할 때도 사용
> db.trips.find({"$expr":{"$eq":["$start station id","$end station id"]}})
// tripduration이 1200이상이고, end station과 start station이 같은 데이터
{"$expr":{"$and": [{"$gt":["$tripduration",1200]},{"$eq":["$end station id","$start station id"]}]}}
// SQL syntax
{field:{operator:value}}
// Aggregation syntax
{operator:{field, value}}
$push : 배열의 마지막 위치에 엘리먼트를 넣음(배열 이 아닌 필드에 사용했을 경우, 필드의 타입을 배열로 바꿈)
$all : 배열 요소의 순서와 상관없이 지정된 요소가 포함된 모든 도큐먼트를 찾을 수 있다
$size : 배열의 길이로 결과를 제한함
// producst 배열로 이루어진 필드에 InvestmentStock를 포함하는 데이터
{"products":"InvestmentStock"}
// producst 배열로 이루어진 필드에 InvestmentStock만 들어있는 데이터
{"products":["InvestmentStock"]}
{"tags":{"$all":["granddaughter","engineer","sundial","archer","patricia","cut","caterpillar","cheek","rainbow","self"]}}
{"amenities":{"$size":20, "$all":["Internet","Wifi"]}}
$elemMatch(projection) : 지정한 배열 필드가 도큐먼트에 존재하고 조건에 맞는 요소가 있는 경우에만 해당 필드를 결과에 포함시킴
$elemMatch(query) : find 명령의 쿼리부분에서도 사용 가능
> db.listingsAndReviews.find({"amenities":{"$size":20,"$all":["Internet","Wifi","Kitchen","Air conditioning","Pool","Shampoo"]}},
{"price":1,"address":1}).pretty()
// find() 명령에서 첫번째 인자인 쿼리에 해당하는 도큐먼트를 projection ->
// class_id가 431이고 scores 배열 필드에 score 필드 값이 85이상인 도큐먼트만 scores를 보여주고
// 85 이상이 아니면 scores 안보여줌
> db.grades.find({"class_id":431},{"scores":{"$elemMatch":{"score":{"$gt":85}}}}).pretty()
> db.grades.find({"scores":{"$elemMatch":{"type":"extra credit"}}}).pretty()
$regex : 일치시키려는 문자열 지정
// start station location 필드의 서브 도큐먼트 type 값이 Point인 데이터
> db.trips.findOne({"start station location.type":"Point"})
//
> db.companies.find({"relationships.0.person.last_name":"Zuckerberg"},{"name":1}).pretty()
// relationships 배열에서 이름이 Mark인 CEO(name으로 projection)
> db.companies.find({"relationships.0.person.first_name":"Mark","relationships.0.title":{"$regex":"CEO"}},{"name":1}).pretty()
$match : Query
$project : Projection
$group : 들어온 데이터 스트림을 여러개로 그룹화하는 연산자
{$group: {_id:, <field 1>:{<accumulator 1>:<expression 1>}, ...}}
> db.listingsAndReviews.aggregate([{$match:{"amenities":"Wifi"}},{$project:{"price":1,"address":1,"_id":0}}]).pretty()
> db.listingsAndReviews.aggregate([{$project:{"address":1,"_id":0}}, {$group:{_id:"$adress.country","count":{"$sum":1}}}])
Domain : 서버와 요청의 도메인이 일치하는 경우 쿠키 전송
Path : 서버와 요청의 세부경로가 일치하는 경우 쿠키 전송
MaxAge / Expires : 쿠키의 유효기간 설정
HttpOnly : 스크립트의 쿠키 접근 가능 여부 결정(XSS 공격)
Secure : Https 프로토콜에서만 쿠키 전송 여부 결정
sameSite : CORS 요청의 경우 옵션 및 메서드에 따라 쿠키 전송 여부 결정(CSRF 공격)
session : 서버가 Client에 유일하고 암호화된 ID를 부여(중요 데이터는 서버에서 관리)쿠키를 사용한 로그인, 예측할 수 있는요청/parameter를 가지고 있어야 함
CSRF 토큰 사용하기, Same-site cookie 사용하기
보안관련 읽을거..
https://starplatina.tistory.com/entry/비밀번호-해시에-소금치기-바르게-쓰기
https://d2.naver.com/helloworld/318732
1. Header
- 어떤 종류의 토큰인가?
- 어떤 알고리즘으로 암호화하는가?
2. Payload
- 유저의 정보
- 권한을 부여 받았는가?
- 기타 필요한 정보
3. Signature
- Header, Payload를 base64 인코딩한 값과 salt 값의 조합으로 암호화된 값
1. Statelessness & Scalability(무상태성&확장성)
- 서버는 클라이언트에 대한 정보를 저장할 필요X
- 토큰을 헤더에 추가함으로 인증절차 완료
2. 안정성
- 암호화한 토큰을 사용
- 암호화 키를 노출할 필요 X
3. 어디서나 생성 가능
- 토큰을 생성하는 서버가 꼭 토큰을 만들지 않아도 됨
4. 권한 부여에 용이
- 토큰의 payload(내용물)안에 어떤 정보에 접근 가능한지 정의
Resource Owner : 액세스 중인 리소스의 유저
Client : Resource owner를 대신하여 보호된 리소스에 액세스하는 응용프로그램
Resource server : client의 요청을 수락하고 응답할 수 있는 서버
Authorization server : Resource server가 액세스 토큰을 발급받는 서버
Authorization grant : 클라이언트가 액세스 토큰을 얻을 때 사용하는 자격 증명
Authorization code : access token을 발급받기 전에 필요한 code
Access token : 보호된 리소스에 액세스하는데 사용되는 credentials
Scope : 주어진 액세스 토큰을 사용하여 액세스할 수 있는 리소스의 범위