MongoDB의 $addToSet 연산자는 배열에 새로운 값을 추가할 때 사용됩니다. 단, 추가하려는 값이 이미 배열에 존재한다면 중복 없이 그대로 유지되며 아무런 변경도 일어나지 않습니다. 이러한 특성 덕분에 집합(set)처럼 중복을 허용하지 않는 배열을 관리할 때 매우 유용합니다.
예제 컬렉션 생성하기
먼저 문서를 포함하는 컬렉션을 생성해 보겠습니다.
> db.demo380.insertOne({
... "details" : [
... {
... "Name" : "Chris",
... "details1" : [ ]
... },
... {
... "Name" : "David",
... "details1" : [ ]
... }
... ]
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e5b56e32ae06a1609a00b11")
}find() 메서드로 문서 조회하기
find() 메서드를 사용하면 컬렉션의 모든 문서를 확인할 수 있습니다.
> db.demo380.find().pretty();
위 쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
{
"_id" : ObjectId("5e5b56e32ae06a1609a00b11"),
"details" : [
{
"Name" : "Chris",
"details1" : [ ]
},
{
"Name" : "David",
"details1" : [ ]
}
]
}$addToSet으로 깊게 중첩된 배열에 객체 추가하기
이제 위치 연산자($)와 함께 $addToSet을 사용하여 내부에 중첩된 details1 배열에 객체를 추가해 보겠습니다. 먼저 details.Name 필드로 대상 문서를 찾은 뒤, details.$.details1 경로를 지정하면 조건에 일치하는 배열 요소 안의 하위 배열에 값이 삽입됩니다.
> db.demo380.update({
... "details.Name": "David"
... }, {
... $addToSet: {
... "details.$.details1": {
... 'SubjectName': "MongoDB",
... 'TeacherName':"Bob"
... }
... }
... }, false, true);
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })업데이트가 성공적으로 완료되었습니다. 다시 find() 메서드로 전체 문서를 확인해 보겠습니다.
> db.demo380.find().pretty();
실행 결과는 다음과 같습니다.
{
"_id" : ObjectId("5e5b56e32ae06a1609a00b11"),
"details" : [
{
"Name" : "Chris",
"details1" : [ ]
},
{
"Name" : "David",
"details1" : [
{
"SubjectName" : "MongoDB",
"TeacherName" : "Bob"
}
]
}
]
}정리
이 예제에서 핵심은 위치 연산자($)입니다. 쿼리 조건(details.Name: "David")에 일치하는 배열 요소의 인덱스를 가리키며, 이를 통해 깊게 중첩된 배열에도 정확하게 값을 추가할 수 있습니다. 또한 $addToSet 덕분에 동일한 {SubjectName: "MongoDB", TeacherName: "Bob"} 객체를 여러 번 추가하더라도 중복 저장이 되지 않으므로 데이터 무결성을 자연스럽게 유지할 수 있습니다.