배열 연산자
배열을 다루는데 갱신 연산자를 사용할 수 있다.
배열은 일반적이고 강력한 데이터 구조다. 연산자는 리스트에 대한 인덱스를 지정할 수 있을 뿐 아니라 Set처럼 이중으로 쓸 수 있다.
요소 삽입 연산자
$push 연산자
$push는 배열이 이미 존재하면 배열 끝에 요소를 추가하고, 존재하지 않으면 새로운 배열을 생성한다.
> db.cars.findOne()
{
"_id" : ObjectId("628f46057a32d396cf84a7ef"),
"name" : "avante",
"brand" : "hyundai"
}
> db.cars.updateOne(
{ _id: ObjectId("628f46057a32d396cf84a7ef") },
{ $push: { options: { HUD: true, AuthStop: true } } }
)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.cars.findOne()
{
"_id" : ObjectId("628f46057a32d396cf84a7ef"),
"name" : "avante",
"brand" : "hyundai",
"options" : [
{
"HUD" : true,
"AuthStop" : true
}
]
}
$each 연산자
$each를 사용하면 작업 한 번으로 값을 여러 개 추가할 수 있다.
> db.cars.findOne({ _id: ObjectId("628f46057a32d396cf84a7f0") })
{
"_id" : ObjectId("628f46057a32d396cf84a7f0"),
"name" : "k5",
"brand" : "kia"
}
> db.cars.updateOne(
{ _id: ObjectId("628f46057a32d396cf84a7f0") },
{ $push: { models: { $each: [2018, 2019, 2020, 2021] } } }
)
> db.cars.findOne({ _id: ObjectId("628f46057a32d396cf84a7f0") })
{
"_id" : ObjectId("628f46057a32d396cf84a7f0"),
"name" : "k5",
"brand" : "kia",
"models" : [
2018,
2019,
2020,
2021
]
}
$slice 연산자
$slice는 $push와 함께 사용되며, 배열의 특정 크기 이상으로 늘어나지 않게 하고 효과적으로 topN 목록을 만들 수 있다.
> db.domesticCars.updateOne(
{ ranking: "sales" },
{ $push: { top10: { $each: [
{ name: "그랜저", brand: "현대", salesCount: 9483 },
{ name: "포터", brand: "현대", salesCount: 9208 },
{ name: "카니발", brand: "현대", salesCount: 6689 }],
$slice: -10,
$sort: { salesCount: -1 }}}})
> db.domesticCars.find().pretty()
{
"_id" : ObjectId("6299924566ff75edaba9a6d4"),
"ranking" : "sales",
"top10" : [
{
"name" : "그랜저",
"brand" : "현대",
"salesCount" : 9483
},
{
"name" : "포터",
"brand" : "현대",
"salesCount" : 9208
},
{
"name" : "카니발",
"brand" : "현대",
"salesCount" : 6689
}
]
}
예제는 배열에 추가할 수 있는 요소의 개수를 10개로 제한한다.
추가 후에 배열 요소의 개수가 10보다 작으면 모든 요소가 유지되고, 10보다 크면 마지막 10개 요소만 유지된다.
따라서 $slice는 도큐먼트 내에 큐를 생성하는 데 사용할 수 있다.
트리밍 하기 전에 $sort 연산자를 $push에 적용할 수 있다.
$slice나 $sort를 배열상에서 $push와 함께 쓰려면 반드시 $each도 사용해야 한다.
$ne 연산자
$ne는 특정 값이 배열에 존재하지 않을 때 해당 값을 추가하면서, 배열을 집합(Set)처럼 처리할 수 있다.
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"현대",
"기아",
"쌍용"
]
}
> db.domesticCars.updateOne({
_id: ObjectId("629993b466ff75edaba9a6d5"),
brands: { $ne: "삼성" }},
{ $push: { brands: "삼성" }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"현대",
"기아",
"쌍용",
"삼성"
]
}
> db.domesticCars.updateOne({
_id: ObjectId("629993b466ff75edaba9a6d5"),
brands: { $ne: "삼성" }},
{ $push: { brands: "삼성" }})
{ "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0 }
$addToSet 연산자
$ne 대신 $addToSet를 사용할 수도 있다. 사용법은 더 간단하지만 $ne와 기능은 같다.
> db.domesticCars.updateOne({
_id: ObjectId("629993b466ff75edaba9a6d5") },
{ $addToSet: { brands: "삼성" }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
$addToSet은 배열 내에서 중복을 피할 수 있다.
고유한 값을 여러 개 추가하려면 $addToSet과 $each를 결합해 사용한다.
이는 $ne와 $push 조합으로는 할 수 없는 작업이다.
> db.domesticCars.updateOne(
{ _id: ObjectId("629993b466ff75edaba9a6d5") },
{ $addToSet: { brands: { $each: ["삼성", "에디슨모터스"] }}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"현대",
"기아",
"쌍용",
"삼성",
"에디슨모터스"
]
}
인덱스 기반 요소 갱신 연산자
값이 여러 개인 배열에서 일부를 변경하는 조작은 꽤 어렵다. 배열 내 여러 값을 다루는 방법은 두 가지가 있다.
위치(인덱스)를 이용하거나 위치 연산자($)를 사용한다.
배열 인덱스는 기준이 0이며, 배열 요소는 인덱스를 도큐먼트의 키처럼 사용한다.
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"기아",
"현대",
"쌍용"
]
}
> db.domesticCars.updateOne(
{ _id: ObjectId("629993b466ff75edaba9a6d5") },
{ $set: { "brands.0": "KIA" }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"KIA",
"현대",
"쌍용"
]
}
하지만 보통 도큐먼트를 쿼리해서 검사해보지 않고는 배열의 몇 번째 요소를 변경할지 알 수 없다.
이 문제를 해결하기 위해 몽고DB에서는 쿼리 도큐먼트와 일치하는 배열 요소 및 요소의 위치를 알아내서 갱신하는 위치 연산자($)를 제공한다.
위치 연산자는 첫 번째로 일치하는 요소만 갱신한다.
> db.domesticCars.updateOne(
{ _id: ObjectId("629993b466ff75edaba9a6d5"), brands: "현대" },
{ $set: { "brands.$": "HYUNDAI" }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"KIA",
"HYUNDAI",
"쌍용"
]
}
필터를 이용한 요소 갱신 연산자
몽고DB 3.6에서는 개별 배열 요소를 갱신하는 배열 필터인 arrayFilters를 도입해 특정 조건에 맞는 배열 요소를 갱신할 수 있다.
> db.cars.findOne()
{
"_id" : ObjectId("6299a4c266ff75edaba9a6d7"),
"kinds" : [
{
"name" : "아반테",
"brand" : "현대",
"price" : 10000
},
{
"name" : "카니발",
"brand" : "기아",
"price" : 10000
},
{
"name" : "소나타",
"brand" : "현대",
"price" : 10000
}
]
}
> db.cars.updateOne(
{ _id: ObjectId("6299a4c266ff75edaba9a6d7") },
{ $set: { "kinds.$[elem].price": 20000 }},
{ arrayFilters: [{ "elem.brand": "현대" }]})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.cars.findOne()
{
"_id" : ObjectId("6299a4c266ff75edaba9a6d7"),
"kinds" : [
{
"name" : "아반테",
"brand" : "현대",
"price" : 20000
},
{
"name" : "카니발",
"brand" : "기아",
"price" : 10000
},
{
"name" : "소나타",
"brand" : "현대",
"price" : 20000
}
]
}
요소 제거 연산자
$pop 연산자
배열의 큐나 스택처럼 사용하려면 배열의 양쪽 끝에서 요소를 제거하는 $pop을 사용한다.
{ $pop: { key: 1 }}은 배열의 마지막 요소를 제거하고, { $pop: { key: -1 }}은 배열의 처음 요소를 제거한다.
> db.domesticCars.updateOne(
{ _id: ObjectId("629993b466ff75edaba9a6d5") },
{ $pop: { brands: -1 }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"기아",
"쌍용",
"삼성",
"에디슨모터스"
]
}
> db.domesticCars.updateOne(
{ _id: ObjectId("629993b466ff75edaba9a6d5") },
{ $pop: { brands: 1 }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"기아",
"쌍용",
"삼성"
]
}
$pull 연산자
$pull은 도큐먼트에서 조건과 일치하는 요소를 모두 제거한다.
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"기아",
"쌍용",
"현대"
]
}
> db.domesticCars.updateOne(
{ _id: ObjectId("629993b466ff75edaba9a6d5") },
{ $pull: { brands: "쌍용" }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.domesticCars.findOne({ _id: ObjectId("629993b466ff75edaba9a6d5") })
{
"_id" : ObjectId("629993b466ff75edaba9a6d5"),
"brands" : [
"기아",
"현대"
]
}
'MongoDB' 카테고리의 다른 글
몽고DB 도큐먼트 갱신, 치환하기 (0) | 2022.06.03 |
---|---|
몽고DB 도큐먼트 삽입, 삭제하기 (0) | 2022.05.26 |
몽고DB 셸 사용해보기 (0) | 2022.05.26 |
몽고DB의 데이터형 (0) | 2022.05.25 |
몽고DB 셸 소개 (0) | 2022.05.25 |