전 파트에서 하던 것을 완성하도록 하겠다.
export const see = async (req, res) => {
const { id } = req.params;
const user = await User.findById(id);
if (!user) {
return res.status(404).render("404", { pageTitle: "User not found." });
}
const videos = await Video.find({ owner: user._id });
여기에서 하고 있는건 owner
가 user._id
인 모든 영상들을 찾는 거다.
url
에 있는 user
의 id
를 가지고 찾고 있다.
사실 이 코드만으로도 충분하다.
하지만 여기에 나온 방식을 사용해서 더 멋있게 코드를 만들어 보도록 한다.
어떤 유저가 업로드한 모든 영상들을 찾기 위해 populate
를 쓸 수 있다.
const videos = await Video.find({ owner: user._id });
현재 이 코드를 삭제를 한다.
return res.render("users/profile", {
pageTitle: user.name,
user,
videos,
});
videos
도 지워 준다.
return res.render("users/profile", {
pageTitle: user.name,
user,
});
그러면 profile.pug
의 videos
가 작동하지 않는다.
block content
each video in videos
+video(video)
else
li Sorry nothing found.
이 부분이다.
그리고 DB
를 초기화 했었기 때문에 로그인 상태가 아니다. 그러면 user
없이 프로필 창에 들어 갈 수 없게 된다.
그래서 videos
를 profile
로 보내지 않았기 때문에 작동하지 않게 된다.
그래도 한 번 더 좋게 고쳐 보도록 한다.
models
폴더를 보면 video
는 1개의 owner
를 가지고 있다.
이전에도 살펴 봤듯이 video
는 하나의 owner
를 가지고 owner
는 여러 videos
를 가질 수 있다.
video
는 하나의 user
를 가지지만 user
는 여러 videos
를 가질 수 있다.
이 논리를 기반으로 user model
안에 videos
라는 array
를 만들어 준다.
const userSchema = new mongoose.Schema({
email: { type: String, required: true, unique: true },
avatarUrl: String,
socialOnly: { type: Boolean, default: false },
username: { type: String, required: true, unique: true },
password: { type: String },
name: { type: String, required: true },
location: String,
});
여기에 추가 해 준다.
const userSchema = new mongoose.Schema({
email: { type: String, required: true, unique: true },
avatarUrl: String,
socialOnly: { type: Boolean, default: false },
username: { type: String, required: true, unique: true },
password: { type: String },
name: { type: String, required: true },
location: String,
videos: [{ type: mongoose.Schema.Types.ObjectId, ref: "Video" }],
});
object
가 아닌 array
로 만들어 준다. 여러 개의 videos
를 가지기 때문이다.
1개의 영상은 소유주가 1명이지만, 소유주는 여러 영상을 소유 할 수 있다.
그래서 array
로 만들었다. 그리고 이 array
에 무엇으로 채워 주냐면 object
이다.
그렇게 해서 objectId
를 사용해 주었다.
owner: { type: mongoose.Schema.Types.ObjectId, required: true, ref: "User" },
이 부분이다.
해당 코드를 그대로 사용하게 된다. 수정 할 부분을 수정해 준다.
이제 ObjectId
를 가지는 array
가 되는 거다.
required
는 필요가 없다. ref
는 User
가 아니라 Video
이다.
videos
는 Video model
에 연결된 ObjectId
로 구성된 array
이다.
이건 array
이니까 많은 video
를 담을 수 있다.
이제
videoController
를 수정해 줄 차례이다.
그 이유는 영상을 업로드 할때 추가적으로 해야 할 것이 있기 때문이다.
const { title, description, hashtags } = req.body;
try {
await Video.create({
title,
description,
fileUrl,
owner: _id,
hashtags: Video.formatHashtags(hashtags),
});
여기서 Video owner
에 사용자 _id
를 저장하고 있다.
하지만 이제는 업로드 될 영상의 id
를 user model
에도 저장해 줘야 한다.
User
에 videos
라는 array
가 있다는걸 기억하고 있어야 한다.
그래서 새로 업로드 하는 영상의 id
를 user model
에 저장해줄 거다.
현재 유저의 id
를 Video
의 owner
에 추가 하고 있다.
이제 다른 방식으로 해보도록 한다.
다행히 create()
가 새로 만드는 video
를 return
해준다.
await Video.create({
title,
description,
fileUrl,
owner: _id,
hashtags: Video.formatHashtags(hashtags),
});
const newVideo = await Video.create({
이렇게 해준다. 이말은 현재 가지고 있는 id
로 사용자를 검색 할수 있고
newVideo
의 id
를 User
의 videos array
에 추가해 준다.
그리고 user
를 찾아 보도록 한다.
const newVideo = await Video.create({
title,
description,
fileUrl,
owner: _id,
hashtags: Video.formatHashtags(hashtags),
});
const user = await User.findById(_id);
user.videos.push();
그리고 user.videos
를 쓸거다. user
에 videos array
가 있다는 걸 알기에 그렇다.
array
에 요소를 추가 할때는 push
를 사용하면 된다.
해당 작업 페이지로 가서 inspect > console
에서 에시를 보도록 한다.
const hello = []
undefined
hello.push(1)
1
hello
[1]
위와 같은 원리로 user.videos.push(비디오 id)
를 써보도록 한다.
user.videos.push(newVideo._id);
이렇게 user.videos.push()
를 쓰고 newVideo
의 id
를 써준다.
그리고 user.save()
를 써준다.
user.videos.push(newVideo._id);
user.save();
그리고 다시 로그인을 해본다. 영상도 모두 삭제 되었으니 새로 올려 준다.
DB
에서 모든 사용자를 검색해 보도록 한다.
db.users.find()
db.videos.find()
user
에 videos array
가 추가 되어 있다. 그리고 모든 영상들도 검색해 본다.
전 단계에서 본 것 처럼 user
에는 videos array
가 있고,
video
에는 owner id
가 있다. 이렇게 해서 둘이 연결이 되었다.
이제 업로드 된 영상 소유자의 프로필 창을 들어가 본다.
videos
가 정의되지 않아서 열리지 않고 있다고 한다.
userController
를 수정해서 해결해 보도록 한다.
export const see = async (req, res) => {
const { id } = req.params;
const user = await User.findById(id);
먼저 see controller
에 console log(user)
를 해서
export const see = async (req, res) => {
const { id } = req.params;
const user = await User.findById(id);
console.log(user);
그 결과 값을 확인 해보도록 한다. 에러가 나오지만 중요한건 user
이다.
보다시피 이 안에는 videos array
가 존재 한다.
이제 이 videos array
로 videos
정보를 다 가져올 수 있게 된다.
const user = await User.findById(id);
const user = await User.findById(id).populate("videos");
populate()
를 써준다. 그리고 videos
를 populate
해본다.
이제 Mongoose
가 id
를 가져다가 모든 영상들을 프로필 창에 보여줄거다.
새로고침을 해도 계속 에러가 나와있지만 console
을 확인해 보면 videos
정보가 로드 된걸 볼수 있다.
다시 한번 확인해 보면 videos
라는 array
를 만들었고 그 안에 ObjectId
를 저장하고 있다.
그런데 videos
를 가져왔다. 이전처럼 id
만 가진 array
가 아니고
Mongoose
의 도움으로 video object
로 구성된 array
가 되었다.
이제
profile.pug
만 수정해주면 된다.
block content
each video in videos
+video(video)
else
li Sorry nothing found.
이제 each video in videos
대신에 each video in user.videos
를 써준다.
block content
each video in user.videos
+video(video)
else
li Sorry nothing found.
user
를 variable
로 users/profile
로 보내고 있기 때문이다.
그리고 DB
에서 찾은 user
는 videos
를 가지고 있으니까 잘 작동하게 된다.
이 모든게 populate
한 줄로 정리가 되었다.
물론 populate
를 하지 않으면 이전처럼 될거다.
이전에는 video id
만 있었다. 그런데 object
자체가 필요 하다.
그래서 그렇게 만들었다. 이렇게 populate
를 쓰면 된다.
지금까지
relataionship
에 대해서 배웠다.
이제 여러 개의 video
와 어떻게 relationship
을 구축하면 되는지 알게 되었다.
user
는 여러 개의 video
를 업로드 할수 있다는걸 반드시 기억해야 한다.
그리고 video
는 owner
가 하나 뿐이다. 이렇게 relationship
을 만들어 봤다.
video
를 하나 더 만들어 보도록 한다.
그렇게 하면 프로필 창에 들어가면 두 영상을 모두 볼 수 있다.
바로 현재 유저가 영상의 소유자 이기 때문이다.
다음 파트에서는 여기에 몇 가지 condition
들을 추가 해 보겠다.
Edit Video →
Delete Video →
왜냐하면 해당 버튼들을 안보이게만 만들었기 때문이다.
owner
가 아닌 사람들이 수정할 수 있는 페이지를 볼 수 없게 만들어 본다.
현재는 누구나 수정 할수 있는 상태 이다. 이제 영상에는 owner
가 있으니
owner
만 수정 사능하도록 만들어 볼거다.
그리고 getEdit
도 수정해서 영상 소유주만 form
을 보고 제출 할수 있게 만들거다.
이런 것들을 보완해야 하고 video
를 삭제하는 것도 owner
만 가능하도록 만들거다.
userSchema.pre("save", async function () {
this.password = await bcrypt.hash(this.password, 5);
});
현재 이 부분이 버그가 있는데 이 버그는 user
를 save
를 할 때 마다
비밀번호를 반복적으로 hashing
하고 있다. 좋지 않은 방법이다.
왜냐하면 videoController
에서 영상을 업로드 할때 user.save()
를 실행 하는데
그렇게 되면 비밀번호가 다시 한번 hash
가 된다.
사용자가 다시 로그인 할수 없기 때문에 이 부분을 수정 해줘야 한다.
특정 조건에서만 비밀번호가 hash
되도록 만들어 줄거다.
항상 되는 것이 아니라 현재는 save()
가 실행 될 때마다 hash
가 일어나고 있다.
그로 인해 이 사용자는 비밀번호를 사용 할수 없게 된다. 더 이상 로그인을 할수 없는 거다.
다음 파트에서는 버그를 수정하고 보안을 신경 써보도록 한다.
보안은 영상 owner
가 아닌 사람들이 영상을 수정/삭제 하지 못하게 만드는 것이고
위에 언급했던 버그도 수정하도록 하겠다.
그리고 다시 DB
를 초기화 한 다음에 버그가 존재 한다는 것을 살펴 보도록 하겠다.