몽고DB는 RDB처럼 데이터끼리 관계로 연결시키기보다는,
연관된 데이터, 같이 이용될 확률이 높은 데이터를 한뭉텅이로 저장하는게 일반적이다
그 방식을 Embedding
시킨다고 한다. 아래는 embed 방식의 모델을 보여준다.
// video객체를 복수개 가지는 user 모델.
const Video = {
URI: String
}
const UserSchema = new mongoose.Schema({
name: String,
videos: [Video]
});
export const UserModelForSubdoc = mongoose.model('User', UserSchema);
위 모델에 한번의 query를 해서 아래의 값을 얻고 싶은데 어떻게 해야하는가.
for문으로 query를 복수개 날릴순 없지않나... for은 최후의 방식이다.
// 무식하게 for문으로 query를 두번날린다면 이렇게 된다.
for (let i of inputList) {
await Model.findByIdAndUpdate(
userID,
{ $push: { videos: { URI : i } } },
{new: true});
}
위 for문 방식을 하지 않고 아래의 원하는 결과값을 받으려면 어떻게 해야하는지 알아보자.
//원하는 결과값
{
"result": {
"_id": "dsfheiofjkdlsfmklsdfm",
"name": "브레드",
"videos": [
{
"_id": "5fca3a6e3a0a6f4360495ba7",
"URI": "https1"
},
{
"_id": "5fca3a6e3a0a6f4360495ba8",
"URI": "https2"
}
],
}
}
Embding된 모델에서 video(subdoc)를 복수개 생성하고 싶을 때는 어떻게 해야할까?
단순히 $push
?하면 되지않나? "아니다". 먼저 알야아할 게 있다. 바로 $each 연산자
!
몽고DB의 설명부터 보자.
$each
The $each modifier is available for use with the $addToSet operator and the $push operator.
Use with the $addToSet operator to add multiple values to an array<field>
if the values do not exist in the<field>
.
"Array field에 복수개의 값을 넣어줄때 $push 와 $addToSet과 같이 이용하면 된다."
복수개의 subdoc을 생성하기전에 한단계 쉬운 Array Field에 복수개의 데이터를 넣어보자.
const UserSchema = new mongoose.Schema({
name: String,
videos: [String]
});
export const UserModel1 = mongoose.model('User', UserSchema);
위 userModel1
의 videos field에 복수개의 데이터를 추가
하는 방법은 아주 간단하다.
MongoDB document
Use with the $push operator to append multiple values to an array field
{ $push: { field: { $each: [ value1, value2 ... ] } } }
추가하려는 값의 array에 $each
를 붙여주면 된다.
한개의 값을 추가할 때 이랬다면. { field: value1 }
복수개의 값을 추가할때는 이렇게 바뀐다. { field: { $each: [value1, value2] } }
다시 우리의 문제 상황으로 돌아오자.
우리가 하고자 하는 건: "아래의 모델에 복수개의 Subdoc을 한번의 query로 생성한다."
// video객체를 복수개 가지는 user 모델.
const Video = {
URI: String
}
const UserSchema = new mongoose.Schema({
name: String,
videos: [Video]
});
export const UserModelForSubdoc = mongoose.model('User', UserSchema);
//원하는 결과값
{
"result": {
"_id": "dsfheiofjkdlsfmklsdfm",
"name": "브레드",
"videos": [
{
"_id": "5fca3a6e3a0a6f4360495ba7",
"URI": "https1"
},
{
"_id": "5fca3a6e3a0a6f4360495ba8",
"URI": "https2"
}
],
}
}
// URIInputs = [ "http1", "http2", "http3" ];
let array = [];
for (let i = 0; i < URIInputs.length; i++) {
var obj = {};
obj['URI'] = URIInputs[i];
array.push(obj);
}
// array = [ {"URI" : "http1"}, {"URI": "http2"}, {"URI": "http3"} ]
let checkSubdoc = await this.userModel
.findOneAndUpdate(
{ _id: user._id },
{ $push: { videos: { $each: array } } },
{ new: true }
);
Subdoc는 단순 field가 아니기때문에 값만 떡하니 보낸다고 생성되지 않는다.
object로 값을 보내줘야한다. 그래서 key, value가 있는 object로 바꿔줬고 object들을 한 array에 모두 push했다.
그 뒤 단순 field를 push 업데이트하듯이 $each 연산자와 $push연산자를 같이 이용해서 subdoc를 복수개 생성하게 했다.