$and: 여러 조건을 모두 만족 (기본적으로 콤마(,)로 구분된 여러 조건은 AND로 동작)
$or: 여러 조건 중 하나라도 만족
$not: 주어진 쿼리 표현식의 결과를 반전
$nor: 여러 조건을 모두 만족하지 않음
# 예시: 나이가 25세 미만이거나 (OR) 직업이 '독립운동가'인 사용자 조회query_or_condition = { "$or": [ {"age": {"$lt": 25}}, {"occupation": "독립운동가"} # (상)편 예제 데이터 기준: ' 대한민국 독립유공자' ]}print("\n25세 미만이거나 독립운동가인 사용자:")for user in users_collection.find(query_or_condition, {"name": 1, "age": 1, "occupation":1, "_id":0}): print(user) # 예시: 'email' 필드가 존재하면서 (AND) 'status' 필드가 'martyr'가 아닌 사용자 # $and는 명시적으로 사용할 수도 있지만, 기본적으로 딕셔너리 내 여러 키는 AND로 처리됩니다.query_and_not_condition = { "email": {"$exists": True}, # email 필드가 존재하고 "status": {"$ne": "martyr"} # status가 'martyr'가 아닌}print("\n이메일이 있고 순교자가 아닌 사용자:")for user in users_collection.find(query_and_not_condition, {"name": 1, "email":1, "status":1, "_id":0}): print(user)
$type: 필드의 BSON 데이터 타입을 확인합니다. (예: "string", "int", "array", "objectId", "date" 등 문자열 또는 BSON 타입 번호 사용)
# 예시: 'lastModified' 필드가 Date 타입인 문서 조회query_type_date = {"lastModified": {"$type": "date"}}print("\nlastModified가 Date 타입인 사용자:")for user in users_collection.find(query_type_date, {"name": 1, "lastModified":1, "_id":0}): print(user)
# 예시: 'tags' 필드에 "patriot"와 "activist"를 모두 포함하는 사용자 조회query_tags_all = {"tags": {"$all": ["patriot", "activist"]}}print("\n'patriot'와 'activist' 태그를 모두 가진 사용자:")for user in users_collection.find(query_tags_all, {"name": 1, "tags":1, "_id":0}): print(user) # 예시: 'scores' 배열 필드에 80점 이상, 90점 미만인 점수가 하나라도 있는 학생 조회 # (scores 필드가 있다고 가정하고 임시 데이터 삽입 후 테스트) # users_collection.update_one({"name": "유관순"}, {"$set": {"scores":}}) # users_collection.update_one({"name": "안중근"}, {"$set": {"scores":}})query_scores_elemMatch = { "scores": {"$elemMatch": {"$gte": 80, "$lt": 90}}}print("\n80점대 점수를 가진 학생:")for student in users_collection.find(query_scores_elemMatch, {"name":1, "scores":1, "_id":0}): print(student)
문자열 필드에서 패턴 매칭을 수행합니다. Python의 re 모듈을 사용하거나, 직접 MongoDB의 $regex 연산자를 사용할 수 있습니다.
import re # 예시: 이름(name)이 '김'으로 시작하는 사용자 조회 (Python re 모듈 사용)regex_kim_start = re.compile(r"^김")query_name_regex_re = {"name": regex_kim_start}print("\n이름이 '김'으로 시작하는 사용자 (re 모듈):")for user in users_collection.find(query_name_regex_re, {"name":1, "_id":0}): print(user) # 예시: 이메일(email) 주소에 'example.com'을 포함하는 사용자 조회 ($regex 사용)query_email_regex_operator = {"email": {"$regex": "example\\.com", "$options": "i"}} # i: 대소문자 무시print("\n'example.com' 이메일을 사용하는 사용자 ($regex):")for user in users_collection.find(query_email_regex_operator, {"name":1, "email":1, "_id":0}): print(user)
create_index(keys, **kwargs): 단일 또는 복합 인덱스를 생성합니다.
keys
인덱스 키
단일 필드는 [("필드명", 방향)] 또는 "필드명"
복합 필드는 [("필드1", 방향), ("필드2", 방향)]
방향은 pymongo.ASCENDING (1) 또는 pymongo.DESCENDING (-1).
name
인덱스 이름 지정 (선택 사항).
unique=True
고유 인덱스 생성.
background=True
백그라운드에서 인덱스 생성 (MongoDB 구버전 옵션, 최신 버전은 대부분 기본적으로 백그라운드 동작).
sparse=True
해당 필드가 없는 문서는 인덱싱에서 제외 (주로 고유 인덱스와 함께 사용).
create_indexes([IndexModel, ...]): 여러 인덱스를 한 번에 생성합니다. IndexModel 객체를 사용합니다.
from pymongo import IndexModel, ASCENDING, DESCENDINGtry: # 단일 필드 인덱스 생성 (email 오름차순) users_collection.create_index([("email", ASCENDING)], name="email_index", unique=True) print("\n'email_index' (unique) 생성 성공.") # 복합 인덱스 생성 (occupation 오름차순, age 내림차순) occupation_age_index = IndexModel([("occupation", ASCENDING), ("age", DESCENDING)], name="occupation_age_idx") users_collection.create_indexes([occupation_age_index]) print("'occupation_age_idx' 생성 성공.")except pymongo.errors.OperationFailure as e: print(f"인덱스 생성 중 오류: {e}") # 이미 존재하거나, 고유 제약 위반 등
# 예시: 이름은 'fullName'으로, 나이만 포함, _id는 제외pipeline_project = [ {"$match": {"occupation": "대한민국 독립유공자"}}, # 이전 결과에 이어서 {"$project": { "_id": 0, "fullName": "$name", # $name은 name 필드의 값을 의미 "currentAge": "$age" }}]print("\n집계 $project: 이름 변경 및 필드 선택")for doc in users_collection.aggregate(pipeline_project): print(doc)
_id 필드에 그룹화 기준을 지정하고, 다양한 집계 연산자($sum, $avg, $min, $max, $push, $addToSet 등)를 사용합니다.
# 예시: 직업(occupation)별 평균 나이와 인원 수 계산pipeline_group = [ {"$group": { "_id": "$occupation", # 직업별로 그룹화 "averageAge": {"$avg": "$age"}, # 평균 나이 계산 "count": {"$sum": 1} # 그룹 내 문서 개수(인원 수) 계산 }}]print("\n집계 $group: 직업별 평균 나이 및 인원 수")for group_data in users_collection.aggregate(pipeline_group): print(group_data)
오늘은 MongoDB 올인 외전 시리즈의 두 번째 시간으로, Python과 PyMongo를 사용하여 MongoDB의 고급 기능을 활용하는 방법을 배웠습니다.
다양한 쿼리 연산자를 통해 원하는 데이터를 더욱 정교하게 찾아내는 방법, 코드 레벨에서 인덱스를 직접 관리하여 성능을 최적화하는 방법, 그리고 집계 프레임워크의 기초를 통해 데이터를 그룹화하고 분석하는 방법을 익혔습니다.
이러한 고급 기능들을 잘 활용하면, Python 애플리케이션에서 MongoDB를 단순한 데이터 저장소를 넘어, 강력한 데이터 처리 및 분석 엔진으로 사용할 수 있게 됩니다.