PyMongo 데이터 수정

PyMongo 데이터 수정

Pymongo
PyMongo 데이터 수정
Author

gabriel yang

Published

September 28, 2024


MongoDB는 유연한 비정형(NoSQL) 데이터베이스로, 문서를 자유롭게 추가하고 수정할 수 있습니다. PyMongo는 MongoDB와 Python 간의 연결을 지원하며, 이를 통해 쉽게 데이터를 업데이트할 수 있습니다. 이 글에서는 PyMongo에서 update_one()update_many() 메서드를 사용하여 문서를 수정하는 방법을 설명하겠습니다.

1. PyMongo 설치 및 기본 설정

먼저 PyMongo를 설치해야 합니다. 터미널에서 다음 명령어를 실행하세요:

pip install pymongo

설치가 완료되면, MongoDB 서버와 연결하기 위한 코드를 작성할 수 있습니다.

MongoDB localhost에 연결

from pymongo import MongoClient

# MongoDB 서버에 연결 (로컬호스트를 사용한 예)
client = MongoClient('mongodb://localhost:27017/')

위 코드에서 MongoClient를 사용하여 MongoDB 서버와 연결합니다. localhost는 로컬에서 실행 중인 MongoDB 서버를 의미하며, 기본 포트인 27017을 사용합니다. 만약 원격 서버에 연결하려면 해당 서버의 IP 주소와 포트를 사용하면 됩니다.

MongoDB Atlas에 연결

MongoDB Atlas는 클라우드 기반의 MongoDB 서비스로, 다음과 같이 연결 문자열을 설정하여 사용할 수 있습니다:

from pymongo import MongoClient

# MongoDB Atlas 연결
client = MongoClient("mongodb+srv://<username>:<password>@cluster0.mongodb.net/mydatabase?retryWrites=true&w=majority")
Note

주의: <username>, <password>, <dbname>은 사용자의 MongoDB Atlas 계정에 맞게 수정해야 합니다.

#| echo: false
from pymongo import MongoClient

# MongoDB Atlas 연결
client = MongoClient("mongodb+srv://gabrielwithhappy:lJR3LbMaRjkJpEJg@cluster0.gbyjc.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0")
from pymongo import MongoClient

# 데이터베이스 선택
db = client['testdb']

# 컬렉션 선택
users = db['users']

# # 새로 생성된 문서만 출력되도록 collection에 저장된 문서를 모두 삭제
users.delete_many({})

# 테스트용 문서 목록
userdata = [
    {"name": "Alice", "age": 30, "email": "alice@example.com"},
    {"name": "Bob", "age": 25, "email": "bob@example.com"},
    {"name": "Charlie", "age": 35, "email": "charlie@example.com"},
    {"name": "Daisy", "age": 28, "email": "daisy@example.com"},
    {"name": "Eve", "age": 40, "email": "eve@example.com"},
    {"name": "Frank", "age": 22},  # email 필드 없음
    {"name": "Grace", "age": 50, "email": "grace@example.com"},
    {"name": "Hank", "age": 20, "email": "hank@example.com"},
]

# 여러 문서 삽입
result = users.insert_many(userdata)

# 전체 문서 조회
updated_documents = users.find({})
for document in updated_documents:
    print(document)
{'_id': ObjectId('66f87b2c4efbafb3dc09140a'), 'name': 'Alice', 'age': 30, 'email': 'alice@example.com'}
{'_id': ObjectId('66f87b2c4efbafb3dc09140b'), 'name': 'Bob', 'age': 25, 'email': 'bob@example.com'}
{'_id': ObjectId('66f87b2c4efbafb3dc09140c'), 'name': 'Charlie', 'age': 35, 'email': 'charlie@example.com'}
{'_id': ObjectId('66f87b2c4efbafb3dc09140d'), 'name': 'Daisy', 'age': 28, 'email': 'daisy@example.com'}
{'_id': ObjectId('66f87b2c4efbafb3dc09140e'), 'name': 'Eve', 'age': 40, 'email': 'eve@example.com'}
{'_id': ObjectId('66f87b2c4efbafb3dc09140f'), 'name': 'Frank', 'age': 22}
{'_id': ObjectId('66f87b2c4efbafb3dc091410'), 'name': 'Grace', 'age': 50, 'email': 'grace@example.com'}
{'_id': ObjectId('66f87b2c4efbafb3dc091411'), 'name': 'Hank', 'age': 20, 'email': 'hank@example.com'}

위 코드를 통해 MongoDB 서버에 연결하고, testdb 데이터베이스와 users 컬렉션을 선택했습니다. 컬렉션이 존재하지 않는다면 MongoDB는 데이터를 삽입할 때 자동으로 컬렉션을 생성합니다.

2. update_one() 메서드로 한 개의 문서 수정

update_one() 메서드는 컬렉션에서 조건에 맞는 첫 번째 문서를 수정할 때 사용됩니다. update_one() 메서드는 두 개의 인자를 받습니다:

  1. 필터 조건: 어떤 문서를 수정할지 선택하는 조건입니다.
  2. 수정 명령: 어떤 값을 어떻게 수정할지를 지정하는 명령입니다.

다음은 name이 “Alice”인 사용자의 나이를 35로 업데이트하는 예시입니다.

# 필터 조건 및 수정 명령
filter_query = {"name": "Alice"}
update_command = {"$set": {"age": 35}}

# 한 개의 문서 수정
result = users.update_one(filter_query, update_command)

# 결과 출력
updated_documents = users.find(filter_query)
for document in updated_documents:
    print(document)
print(f"Matched {result.matched_count} document(s) and modified {result.modified_count} document(s).")

코드 설명:

  • filter_query: 수정할 문서를 찾기 위한 조건입니다. 여기서는 name이 “Alice”인 문서를 선택합니다.
  • update_command: 수정할 내용을 나타냅니다. $set 연산자를 사용하여 age 필드를 35로 수정합니다.
  • result.matched_count: 필터 조건과 일치하는 문서의 개수입니다.
  • result.modified_count: 실제로 수정된 문서의 개수입니다.

출력 예시:

{'_id': ObjectId('66f87b2c4efbafb3dc09140a'), 'name': 'Alice', 'age': 35, 'email': 'alice@example.com'}
Matched 1 document(s) and modified 1 document(s).

3. update_many() 메서드로 여러 문서 수정

update_many() 메서드는 조건에 맞는 여러 문서를 한 번에 수정할 때 사용됩니다. 사용법은 update_one()과 동일하지만, 여러 문서를 수정한다는 점에서 차이가 있습니다.

다음은 age가 30 이상인 모든 사용자의 status 필드를 “active”로 업데이트하는 예시입니다.

# 필터 조건 및 수정 명령
filter_query = {"age": {"$gte": 30}}
update_command = {"$set": {"status": "active"}}

# 여러 문서 수정
result = users.update_many(filter_query, update_command)

# 결과 출력
updated_documents = users.find(filter_query)
for document in updated_documents:
    print(document)
print(f"Matched {result.matched_count} document(s) and modified {result.modified_count} document(s).")

코드 설명:

  • filter_query: 여기서는 age 필드가 30 이상인 모든 문서를 선택합니다.
  • update_command: status 필드를 “active”로 설정하는 업데이트 명령입니다.

출력 예시:

{'_id': ObjectId('66f87b874efbafb3dc091413'), 'name': 'Alice', 'age': 35, 'email': 'alice@example.com', 'status': 'active'}
{'_id': ObjectId('66f87b874efbafb3dc091415'), 'name': 'Charlie', 'age': 35, 'email': 'charlie@example.com', 'status': 'active'}
{'_id': ObjectId('66f87b874efbafb3dc091417'), 'name': 'Eve', 'age': 40, 'email': 'eve@example.com', 'status': 'active'}
{'_id': ObjectId('66f87b874efbafb3dc091419'), 'name': 'Grace', 'age': 50, 'email': 'grace@example.com', 'status': 'active'}
Matched 4 document(s) and modified 4 document(s).

4. 업데이트 후 문서 확인

업데이트가 성공했는지 확인하기 위해 업데이트된 문서를 조회할 수 있습니다.

# 업데이트된 문서 확인
updated_user = users.find_one({"name": "Alice"})
print(updated_user)
{'_id': ObjectId('66f87e2d9d1075b1d0c38c51'), 'name': 'Alice', 'age': 35, 'email': 'alice@example.com', 'status': 'active'}

이 코드는 name이 “Alice”인 문서를 찾아 출력합니다.

5. 다양한 업데이트 연산자

MongoDB는 여러 업데이트 연산자를 지원하며, PyMongo에서도 이를 동일하게 사용할 수 있습니다. 자주 사용되는 연산자는 다음과 같습니다.

5.1 $set: 필드 값을 지정된 값으로 설정

이미 본 것처럼 $set 연산자는 기존 필드를 업데이트하거나 새 필드를 추가하는 데 사용됩니다.

# name이 'Bob'인 문서의 email 필드를 업데이트
result = users.update_one({"name": "Bob"}, {"$set": {"email": "newbob@example.com"}})

print(result)
updated_documents = users.find({"name": "Bob"})
for document in updated_documents:
    print(document)

출력 예시

UpdateResult({'n': 1, 'electionId': ObjectId('7fffffff000000000000003a'), 'opTime': {'ts': Timestamp(1727563035, 22), 't': 58}, 'nModified': 1, 'ok': 1.0, '$clusterTime': {'clusterTime': Timestamp(1727563035, 22), 'signature': {'hash': b'T\x10\x13o\xe8k\xd0\xaci\xf544\xfa\xd5\xea\xc3\x94\x95\xe4\xd4', 'keyId': 7377426399050596418}}, 'operationTime': Timestamp(1727563035, 22), 'updatedExisting': True}, acknowledged=True)
{'_id': ObjectId('66f87d109d1075b1d0c38c37'), 'name': 'Bob', 'age': 25, 'email': 'newbob@example.com'}

5.2 $inc: 필드 값을 증가 또는 감소

$inc 연산자는 숫자 필드를 지정된 값만큼 증가(양수) 또는 감소(음수)시킵니다.

# age 필드를 1만큼 증가
users.update_one({"name": "Charlie"}, {"$inc": {"age": 1}})

print(result)
updated_documents = users.find({"name": "Charlie"})
for document in updated_documents:
    print(document)

출력 예시

UpdateResult({'n': 1, 'electionId': ObjectId('7fffffff000000000000003a'), 'opTime': {'ts': Timestamp(1727563298, 27), 't': 58}, 'nModified': 1, 'ok': 1.0, '$clusterTime': {'clusterTime': Timestamp(1727563298, 27), 'signature': {'hash': b'C+\x07\x86\xe7\n\xf6\x9bg\xe1\xaa\x14%\xbf\xfb\xb3h\xde\xf2\x12', 'keyId': 7377426399050596418}}, 'operationTime': Timestamp(1727563298, 27), 'updatedExisting': True}, acknowledged=True)
{'_id': ObjectId('66f87e2d9d1075b1d0c38c53'), 'name': 'Charlie', 'age': 36, 'email': 'charlie@example.com', 'status': 'active'}

5.3 $unset: 필드를 제거

$unset 연산자는 지정된 필드를 문서에서 제거합니다.

# email 필드를 제거
users.update_one({"name": "Daisy"}, {"$unset": {"email": ""}})

print(result)
updated_documents = users.find({"name": "Daisy"})
for document in updated_documents:
    print(document)

출력 예시

UpdateResult({'n': 1, 'electionId': ObjectId('7fffffff000000000000003a'), 'opTime': {'ts': Timestamp(1727563298, 27), 't': 58}, 'nModified': 1, 'ok': 1.0, '$clusterTime': {'clusterTime': Timestamp(1727563298, 27), 'signature': {'hash': b'C+\x07\x86\xe7\n\xf6\x9bg\xe1\xaa\x14%\xbf\xfb\xb3h\xde\xf2\x12', 'keyId': 7377426399050596418}}, 'operationTime': Timestamp(1727563298, 27), 'updatedExisting': True}, acknowledged=True)
{'_id': ObjectId('66f87e2d9d1075b1d0c38c54'), 'name': 'Daisy', 'age': 28}

5.4 $rename: 필드 이름 변경

$rename 연산자는 필드의 이름을 변경합니다.

# 필드 이름 변경: 'age'를 'years_old'로 변경
users.update_one({"name": "Eve"}, {"$rename": {"age": "years_old"}})

print(result)
updated_documents = users.find({"name": "Eve"})
for document in updated_documents:
    print(document)

출력 예시

UpdateResult({'n': 1, 'electionId': ObjectId('7fffffff000000000000003a'), 'opTime': {'ts': Timestamp(1727563298, 27), 't': 58}, 'nModified': 1, 'ok': 1.0, '$clusterTime': {'clusterTime': Timestamp(1727563298, 27), 'signature': {'hash': b'C+\x07\x86\xe7\n\xf6\x9bg\xe1\xaa\x14%\xbf\xfb\xb3h\xde\xf2\x12', 'keyId': 7377426399050596418}}, 'operationTime': Timestamp(1727563298, 27), 'updatedExisting': True}, acknowledged=True)
{'_id': ObjectId('66f87e2d9d1075b1d0c38c55'), 'name': 'Eve', 'email': 'eve@example.com', 'status': 'active', 'years_old': 40}

5.5 $push: 배열에 값 추가

$push 연산자는 배열 필드에 새 값을 추가합니다.

# scores 배열에 새 값 추가
users.update_one({"name": "Frank"}, {"$push": {"scores": 85}})

print(result)
updated_documents = users.find({"name": "Frank"})
for document in updated_documents:
    print(document)

** 코드 설명** - {“name”: “Frank”}: 이 필터 조건에 맞는 문서를 찾습니다. 즉, name 필드가 “Frank”인 문서를 찾습니다. - {“$push”: {“scores”: 85}}: $push 연산자를 사용하여 scores라는 배열 필드에 값을 추가합니다. 이 경우, 85가 scores 배열에 추가됩니다. - 결과: 만약 Frank의 문서에 scores 필드가 이미 있다면, 배열에 85가 추가됩니다. 만약 scores 필드가 없다면, 배열을 생성한 후 85를 넣습니다.

출력 예시

UpdateResult({'n': 1, 'electionId': ObjectId('7fffffff000000000000003a'), 'opTime': {'ts': Timestamp(1727563298, 27), 't': 58}, 'nModified': 1, 'ok': 1.0, '$clusterTime': {'clusterTime': Timestamp(1727563298, 27), 'signature': {'hash': b'C+\x07\x86\xe7\n\xf6\x9bg\xe1\xaa\x14%\xbf\xfb\xb3h\xde\xf2\x12', 'keyId': 7377426399050596418}}, 'operationTime': Timestamp(1727563298, 27), 'updatedExisting': True}, acknowledged=True)
{'_id': ObjectId('66f87e2d9d1075b1d0c38c56'), 'name': 'Frank', 'age': 22, 'scores': [85]}