MongoDB/MongoDB Atlas CRUD 다루기

MongoDB Atlas 클러스터(데이터베이스) access하기&CRUD하기 - 6. update_one()

Fletcher 2024. 7. 28. 18:10

※ 참고자료 ※

PyMongo 4.8.0 Documentation Reference Link

https://pymongo.readthedocs.io/en/stable/index.html

 

 

 

반갑습니다!

저번 포스트까지 데이터 조회에 관련된 함수들을 살펴봤습니다

그 중에 변경 사항을 모니터링하는 부분에 대해서는,

이번 포스트에서 진행하는 update의 내용 이후에 살펴보기로 잠시 미뤄뒀었습니다

 

이제, 이번 포스트에서는 도큐먼트의 내용을 수정하는 방법에 대해서 알아보겠습니다

 

 

 

먼저는 update_one() 함수의 샘플 코드입니다

#MongoDB Update - update_one() 테스트
class MongoDBUpdateOneResource(Resource):
    def put(self):
        # 클러스터 접근을 위한 클라이언트 객체 생성
        client = pymongo.MongoClient(Config.MONGO_DB_URI)

        # 컬렉션 정보 저장
        database = client["project-server"]
        collection = database["MongoDB_TEST"]

        # 단일 항목 갱신
        result = collection.update_one( {"name":"Brandon Led"}, {"$set" : {"age":67}} )

        # 리소스 종료
        client.close()

        return {"acknowledged":result.acknowledged,
                "matched_count":result.matched_count,
                "modified_count":result.modified_count,
                "upserted_id":result.upserted_id}, 200

 

update_one() 함수의 파라미터에는 여러가지가 들어가는데요

positional하게 넣어주시려면,

첫 번째 자리는 filter 즉 해당 도큐먼트를 찾기 위한 조건입니다

그리고 두 번째 자리는 값을 변경하고자 하는 key-value를 기재해주시면 되겠습니다

 

위 샘플 코드를 풀어서 설명하면,

"

"project-server" 데이터베이스에 있는 "MongoDB_TEST" 컬렉션의 도큐먼트들 중에서

"name" 키의 값이 "Brandon Led"인 도큐먼트의 필드 중

"age" 키의 값을 66으로 바꿔라

"

라는 뜻이 되겠습니다

 

 

그리고 update_one() 함수를 시행하면 일정한 데이터를 리턴하는데요

 

acknowledged : 작업이 성공적으로 수행되었는지 여부 의미

matched_count : 필터 조건에 맞는 문서의 수 의미

modified_count : 수정된 문서의 수 의미

upserted_id : upsert 작업에서 생성된 새로운 문서의 _id 의미

 

 

현재 제 해당 컬렉션에는

"name":"Brandon Led" 조건을 만족하는 도큐먼트가 두 개가 있는데요

update_one() 함수를 사용하여 해당 조건과 데이터 갱신을 적용하면,

조건을 만족하는 모든 도큐먼트 중에서 최상단 1개의 도큐먼트에만

수정 내용이 반영됩니다 ^^

 

 

 

※ 참고 ※

update_one() 함수의 파라미터 종류

① filter

특정 문서를 찾기 위한 조건 → 해당 조건에 맞는 첫 번째 문서가 갱신됨

 

② update

갱신 데이터 지정 → $set, $inc 등이 사용됨

 

③ upsert

True로 설정하면, 해당 조건에 맞는 문서가 없을 경우 새로운 문서를 삽입함

(기본값: False)

 

④ array_filters

배열 필터를 적용하는 조건을 지정 → 배열 내 특정 요소를 갱신할 때 사용함

 

⑤ bypass_document_validation

True로 설정하면, 문서 유효성 검사를 무시함

(기본값: False)

 

⑥ collation

문자열 비교를 제어하기 위한 옵션

 

⑦ hint

인덱스 사용을 위한 힌트

 

⑧ session

특정 세션을 지정

 

 

 

 

 

 

 

 

그럼 포스트맨을 이용해서 한 번 시험동작하고 리턴 값을 확인 해보겠습니다

 

API 호출을 위해서 샘플 코드 중에서

json 요청 데이터를 받기 위해 data = request.get_json() 부분을 추가하고,

"$set"의 value로 data['age'] 부분만 추가로 수정한 다음 API 호출한 결과입니다

 

결과를 보니,

해당 Update 작업이 성공했고,

필터 조건에 맞는 도큐먼트는 1개였으며,

수정된 문서의 수는 1개였습니다!

 

 

여기서 upserted_id의 값은 null인데요

 update_one() 함수의 파라미터로 upsert= True | False로 설정할 수 있습니다

default는 upsert = False이며,

True로 설정할 경우 해당 필터 조건에 만족하는 도큐먼트가 없을시 새로운 문서를 삽입하는 작업을 수행합니다

그 때 새로 생성된 도큐먼트의 아이디 값을 update의 리턴으로서 "upsert_id"로 반환합니다 

 

 

 

 

그럼 이번엔 update_one() 함수의 파라미터 중 upsert를 True로 설정하여

해당 조건의 도큐먼트가 있으면 기존의 도큐먼트를 수정하고,

해당 조건의 도큐먼트가 없으면 새 도큐먼트를 삽입하는 작업을 해보겠습니다

#MongoDB Update - update_one() 테스트
class MongoDBUpdateOneResource(Resource):
    def put(self):

        data = request.get_json()

        # 클러스터 접근을 위한 클라이언트 객체 생성
        client = pymongo.MongoClient(Config.MONGO_DB_URI)

        # 컬렉션 정보 저장
        database = client["project-server"]
        collection = database["MongoDB_TEST"]

        # 단일 항목 갱신
        result = collection.update_one( {"name":"Brandon Led"}, {"$set" : {"height":data['height']}}, upsert=True )

        # 리소스 종료
        client.close()

        return {"acknowledged":result.acknowledged,
                "matched_count":result.matched_count,
                "modified_count":result.modified_count,
                "upserted_id":result.upserted_id}, 200

 

아까의 샘플 코드를 조금만 변형해서 적용해보겠습니다

이 코드를 풀어서 설명하면,

"

"name" 키의 값이 "Brandon Led"인 도큐먼트를 찾아서,

"height" 필드의 값을 JSON 요청 데이터 중 height키의 값으로 갱신해라

"

가 되겠습니다

 

 

 

아까와 마찬가지로 성공적으로 처리가 되었습니다

filter 조건으로 지정한 것이, "name":"Brandon Led"였고,

해당 조건을 만족하는 기존의 도큐먼트가 존재했기 때문에

해당 도큐먼트의 필드로 "height":189라는 한 페어가

해당 도큐먼트의 새로운 필드로 추가되었을겁니다

한 번 확인을 해볼까요?

 

 

 

해당 도큐먼트에 "height"라는 필드가 존재하지 않았기 때문에

데이터가 추가되어 갱신된 것을 확인할 수 있겠습니다

 

여기서 잠깐,

MySQL 등과 같은 RDBMS와 다른 점이 바로 이 부분이죠

NoSQL은 스키마 구조에 대한 정형성이 없기 때문에

이렇게 새로운 필드가 추가 되는 것이 오류로 처리 되지 않고, 또 번거롭지도 않습니다

 

다시 본론으로 돌아와서,

그럼 이번에는 조건을 만족하는 도큐먼트가 없을 경우에

새로운 문서가 삽입되는 것도 확인해보겠습니다

 

 

 

현재 아래 코드의 조건을 만족하는 도큐먼트는 컬렉션에 존재하지 않습니다

#MongoDB Update - update_one() 테스트
class MongoDBUpdateOneResource(Resource):
    def put(self):

        data = request.get_json()

        # 클러스터 접근을 위한 클라이언트 객체 생성
        client = pymongo.MongoClient(Config.MONGO_DB_URI)

        # 컬렉션 정보 저장
        database = client["project-server"]
        collection = database["MongoDB_TEST"]

        # 단일 항목 갱신
        result = collection.update_one( {"popularity":"legend"}, {"$set" : {"social status":data['social_status']}}, upsert=True )

        # 리소스 종료
        client.close()

        return {"acknowledged":result.acknowledged,
                "matched_count":result.matched_count,
                "modified_count":result.modified_count,
                "upserted_id":str(result.upserted_id)}, 200

 

어떤 형식으로 새로운 도큐먼트가 추가 되는지 한 번 확인해볼까요?

 

 

 

 

filter 조건으로 설정한 것과 수정 데이터의 값이 필드로 있는

새로운 도큐먼트가 추가된 것을 확인할 수가 있겠습니다 ^^

당연히 도큐먼트 고유의 id 값도 자동으로 지정이 되어있네요

 

 

 

 

마지막으로 한 가지 내용을 더 설명하고 마무리 짓도록 하겠습니다

filter를 적용할 때 배열 필터를 조건으로 적용할 수 있는데요

아래와 같은 예시 데이터를 준비했습니다

 

해당 도큐먼트의 필드는 "name"과 "grades" 두 개입니다

그리고 "grades"는 값으로 array를 갖는데

해당 어레이의 요소는 각각 {"subject":"math", "score":66}, {"subject":"korean", "score":98}입니다

 

 

 

아래 샘플과 같이 배열 필터를 이용해서 해당 조건을 조회한 다음 수정해보도록 하겠습니다

#MongoDB Update - update_one() 테스트
class MongoDBUpdateOneResource(Resource):
    def put(self):

        data = request.get_json()

        # 클러스터 접근을 위한 클라이언트 객체 생성
        client = pymongo.MongoClient(Config.MONGO_DB_URI)

        # 컬렉션 정보 저장
        database = client["project-server"]
        collection = database["MongoDB_TEST"]

        # 단일 항목 갱신
        result = collection.update_one(
            {"name":"Tae-hwan"},
            {"$set":{"grades.$[elem].score":data['new_score']}},
            array_filters=[{"elem.subject":"math"}],
            upsert=True
            )

        # 리소스 종료
        client.close()

        return {"acknowledged":result.acknowledged,
                "matched_count":result.matched_count,
                "modified_count":result.modified_count,
                "upserted_id":str(result.upserted_id)}, 200

 

 

포스트맨으로 api를 호출한 결과 위와 같은 리스폰스를 받는 것을 볼 수가 있겠습니다

해당 조건을 만족하는 도큐먼트가 1개 있었고(matched_count),

해당 수정 내용이 반영된 도큐먼트가 총 1개가 되겠습니다(modified_count)

그리고 조건을 만족하는 도큐먼트가 기존에 존재했기 때문에

별도의 신규 도큐먼트가 생성되지 않았으므로 upserted_id는 당연히 None이 되겠습니다!

 

 

 

 

 

MongoDB Atlas의 클러스터를 확인해보니 상기 이미지와 같이

데이터 수정이 성공적으로 반영된 것을 확인할 수가 있겠습니다 ^^!

수정 전에는 66점이었는데 수정 후에는 88점이 되었습니다

 

 

 

이번 포스트에서는 update_one() 함수에 대해서

파라미터와 리턴 값들에 대해 알아보았습니다

여기서 줄이고 다음 포스트에서 이어서 찾아뵙겠습니다 ^^