AI 에이전트의 경우: 문서 인덱스는 https://www.mongodb.com/ko-kr/docs/llms.txt에서 사용할 수 있으며, 모든 페이지의 마크다운 버전은 어떤 URL 경로에 .md를 추가하여 사용할 수 있습니다.
Docs Menu

복합 작업

이 가이드 에서는 스칼라 운전자 로 복합 작업을 수행하는 방법을 학습 수 있습니다.

복합 작업은 읽기 작업과 하나의 원자 조작 으로 수행되는 쓰기 (write) 작업으로 구성됩니다. 원자 조작 완전히 완료되거나 전혀 완료되지 않는 작업입니다.

원자 조작은 코드에서 경쟁 조건을 방지하는 데 도움이 될 수 있습니다. 경쟁 조건은 코드의 동작이 제어할 수 없는 이벤트의 순서에 따라 달라질 때 발생합니다.

MongoDB는 다음과 같은 복합 연산을 지원합니다.

  • 하나의 문서 찾기 및 업데이트

  • 하나의 문서 찾기 및 바꾸기

  • 문서 한 개 찾기 및 삭제

원자성 연산 및 원자성에 대한 자세한 내용은 MongoDB Server 매뉴얼의 원자성 및 트랜잭션을 참조하세요.

트랜잭션

둘 이상의 문서 읽기 및 쓰기와 같이 더 복잡한 작업을 원자적으로 수행해야 하는 경우 트랜잭션을 사용합니다. 트랜잭션을 사용하면 데이터베이스 명령 시퀀스를 원자 조작 으로 실행할 수 있습니다. 트랜잭션에 대한 자세한 내용은 MongoDB Server 매뉴얼의 트랜잭션을 참조하세요.

이 섹션에서는 스칼라 운전자 사용하여 복합 작업을 수행하는 방법을 설명합니다.

다음 예제에서는 두 개의 샘플 문서가 포함된 컬렉션 사용합니다.

{"_id": {"$oid": "1"}, "food": "donut", "color": "green"}
{"_id": {"$oid": "2"}, "food": "pear", "color": "yellow"}

이 예제에서는 다음 collection 참조를 사용하여 각 문서 Document 클래스의 인스턴스 에 매핑합니다.

val database: MongoDatabase = mongoClient.getDatabase("compound_operations")
val collection: MongoCollection[Document] = database.getCollection("example")
val hotelCollection: MongoCollection[Document] = database.getCollection("rooms")

각 복합 연산은 일치하는 문서 내보내거나 쿼리 필터하다 와 일치하는 문서가 없는 경우 값을 내보내지 않고 완료되는 SingleObservable[Document] 을 반환합니다. 쿼리 필터하다 여러 문서와 일치하는 경우 메서드는 첫 번째 일치 항목에 대해 작동하며, 여기서 first 은 해당 옵션 객체 에서 정렬 순서를 지정하지 않는 한 디스크의 기본 순서 나타냅니다.

참고

쓰기 작업 후 문서 반환

기본값 으로 복합 연산은 일치하는 문서 반환한 다음 해당 문서에 대해 쓰기 (write) 연산을 수행합니다. 옵션 객체 를 해당 메서드에 전달하여 복합 연산이 쓰기 (write) 연산을 먼저 수행하도록 지시할 수 있습니다.찾기 및 바꾸기 예시 이 구성을 보여줍니다.

하나의 문서 찾아 업데이트 하려면 MongoCollection 클래스의 findOneAndUpdate() 메서드를 사용합니다.

다음 예시 findOneAndUpdate() 메서드를 사용하여 color 필드 값이 "green"인 문서 찾습니다. 그런 다음 해당 문서 의 food 필드 "pizza"로 업데이트합니다.

또한 FindOneAndUpdateOptions 인스턴스를 사용하여 다음 옵션을 지정합니다.

  • 쿼리와 일치하는 문서가 없는 경우 쿼리 필터에 지정된 문서를 삽입하는 업서트를 지정합니다.

  • MongoDB 인스턴스 에서 이 작업의 최대 실행 시간을 5 초로 설정합니다. 작업에 시간이 더 오래 걸리면 findOneAndUpdate() 메서드는 관찰자의 onError() 콜백 통해 MongoExecutionTimeoutException를 방출합니다.

val filter = equal("color", "green")
val update = set("food", "pizza")
val options = new FindOneAndUpdateOptions()
.upsert(true)
.maxTime(5, TimeUnit.SECONDS)
val observable: SingleObservable[Document] =
collection.findOneAndUpdate(filter, update, options)
observable.subscribe(new Observer[Document] {
override def onNext(doc: Document): Unit = println(doc.toJson())
override def onError(e: Throwable): Unit = println(s"Failed: ${e.getMessage}")
override def onComplete(): Unit = println("Completed")
})
{"_id": {"$oid": "1"}, "color": "green", "food": "pizza"}
Completed

이 섹션에서 사용되는 메서드 및 클래스에 대한 자세한 내용은 다음 API 설명서를 참조하세요.

하나의 문서 찾아 바꾸려면 MongoCollection 클래스의 findOneAndReplace() 메서드를 사용합니다.

다음 예시 findOneAndReplace() 메서드를 사용하여 color 필드 값이 "green"인 문서 찾습니다. 일치하는 문서 다음으로 대체합니다.

{"music": "classical", "color": "green"}

또한 이 예시 FindOneAndReplaceOptions 인스턴스 사용하여 반환된 문서 바꾸기 작업 후의 상태 여야 함을 지정합니다.

val replaceFilter = equal("color", "green")
val replacement = Document(
"music" -> "classical",
"color" -> "green"
)
val replaceOptions = new FindOneAndReplaceOptions()
.returnDocument(ReturnDocument.AFTER)
val replaceObservable: SingleObservable[Document] =
collection.findOneAndReplace(replaceFilter, replacement, replaceOptions)
replaceObservable.subscribe(new Observer[Document] {
override def onNext(doc: Document): Unit = println(doc.toJson())
override def onError(e: Throwable): Unit = println(s"Failed: ${e.getMessage}")
override def onComplete(): Unit = println("Completed")
})
{"_id": {"$oid": "1"}, "music": "classical", "color": "green"}
Completed

이 섹션에서 사용되는 메서드 및 클래스에 대한 자세한 내용은 다음 API 설명서를 참조하세요.

하나의 문서 찾아 삭제 하려면 MongoCollection 클래스의 findOneAndDelete() 메서드를 사용합니다.

다음 예시 findOneAndDelete() 메서드를 사용하여 _id 필드 에서 가장 큰 값을 가진 문서 찾아 삭제 .

이 예제에서는 FindOneAndDeleteOptions 인스턴스를 사용하여 _id 필드에 내림차순 정렬을 지정합니다.

val deleteOptions = new FindOneAndDeleteOptions()
.sort(descending("_id"))
val deleteObservable: SingleObservable[Document] =
collection.findOneAndDelete(empty(), deleteOptions)
deleteObservable.subscribe(new Observer[Document] {
override def onNext(doc: Document): Unit = println(doc.toJson())
override def onError(e: Throwable): Unit = println(s"Failed: ${e.getMessage}")
override def onComplete(): Unit = println("Completed")
})
{"_id": {"$oid": "2"}, "food": "pear", "color": "yellow"}
Completed

이 섹션에서 사용되는 메서드 및 클래스에 대한 자세한 내용은 다음 API 설명서를 참조하세요.

여러 작업을 원자 단위로 수행하면 복합 작업을 통해 경쟁 조건을 방지할 수 있습니다.

이 섹션의 예에서는 방이 하나 있는 호텔을 실행 가정해 보겠습니다. 작은 스칼라 프로그램을 사용하여 게스트를 객실에 체크인합니다.

다음 문서 호텔 객실을 나타냅니다.

{"_id": {"$oid": "1"}, "guest": null, "room": "Blue Room", "reserved": false}

다음 예시 bookARoomUnsafe() 함수를 사용하여 게스트를 객실에 체크인합니다. 이 함수는 찾기 작업과 업데이트 작업을 별도로 수행합니다.

def bookARoomUnsafe(guestName: String): Unit = {
val availableFilter = equal("reserved", false)
val findResults = Await.result(
hotelCollection.find(availableFilter).first().toFuture(),
Duration(10, TimeUnit.SECONDS)
)
if (Option(findResults).isEmpty) {
println(s"Sorry, we are booked, $guestName")
return
}
val room = findResults
val roomName = room.getString("room")
println(s"You got the $roomName, $guestName")
val reserveUpdate = combine(
set("reserved", true),
set("guest", guestName)
)
val roomFilter = equal("_id", room.get("_id").get)
Await.result(
hotelCollection.updateOne(roomFilter, reserveUpdate).toFuture(),
Duration(10, TimeUnit.SECONDS)
)
}

얀과 패트라는 두 게스트가 동시에 같은 객실을 예약하려고 한다고 가정해 보겠습니다.

잔은 다음 출력을 확인합니다.

You got the Blue Room, Jan

패트릭은 다음 출력을 확인합니다.

You got the Blue Room, Pat

데이터베이스 살펴보면 다음과 같은 문서 있습니다.

{"_id": {"$oid": "1"}, "guest": "Jan", "room": "Blue Room", "reserved": true}

애플리케이션 패트와 얀 모두에게 방을 예약했다고 말했지만 데이터베이스 1월 예약만 표시됩니다. 다음은 MongoDB 수행한 작업 순서입니다.

  1. 1월의 빈 방 찾기 및 반환

  2. 패트를 위한 빈 방 찾기 및 반환

  3. 패트의 예약으로 방 업데이트하기

  4. 얀의 예약으로 방 업데이트

패트가 잠시 방을 예약했지만, 잔의 업데이트 작업이 마지막에 실행되었기 때문에 패트의 예약을 덮어썼습니다.

다음 예시 bookARoomSafe() 함수를 사용하여 게스트를 객실에 체크인합니다. 이 함수는 findOneAndUpdate()를 사용하여 찾기 및 업데이트 작업을 단일 원자 조작 으로 수행합니다.

def bookARoomSafe(guestName: String): Unit = {
val reserveUpdate = combine(
set("reserved", true),
set("guest", guestName)
)
val availableFilter = equal("reserved", false)
val room: Document = Await.result(
hotelCollection.findOneAndUpdate(availableFilter, reserveUpdate).toFuture(),
Duration(10, TimeUnit.SECONDS)
)
if (Option(room).isEmpty) {
println(s"Sorry, we are booked, $guestName")
return
}
val roomName = room.getString("room")
println(s"You got the $roomName, $guestName")
}

얀과 패트라는 두 게스트가 동시에 같은 객실을 예약하려고 한다고 가정해 보겠습니다.

잔은 다음 출력을 확인합니다.

You got the Blue Room, Jan

패트릭은 다음 출력을 확인합니다.

Sorry, we are booked, Pat

데이터베이스 살펴보면 다음과 같은 문서 있습니다.

{"_id": {"$oid": "1"}, "guest": "Jan", "room": "Blue Room", "reserved": true}

잔은 방을 예약했고, 패트는 사용 가능한 방이 없다는 올바른 메시지를 받았습니다. 다음은 MongoDB 수행한 작업 순서입니다.

  1. 1월의 빈 방을 찾아 예약하기

  2. 패트를 위한 빈 방을 찾아 예약해 보세요.

  3. 빈 방을 찾지 않고 값을 내보내지 않고 완료

findOneAndUpdate()는 찾기 및 업데이트 원자적으로 수행하기 때문에, 월의 예약이 완료된 후에는 패트의 작업을 사용 가능한 방으로 읽을 수 없습니다.

중요

쓰기 락

MongoDB 인스턴스 는 복합 작업 기간 동안 수정하려는 문서 에 쓰기 락 (write lock) 설정합니다.

이 섹션에서 사용되는 메서드 및 클래스에 대한 자세한 내용은 다음 API 설명서를 참조하세요.