(MongoDB) mongoengine

Kepler·2020년 4월 6일
1

MongoDB

목록 보기
2/2

connect to MongoDB

  • 환경변수를 .zshrc에 추가한다. (source ~/.zshrc를 잊지말것)
export MONGO_URI="mongodb://<ID입력>:<PW입력>@<ip>:<port>/<db이름>?authSource=admin"
  • os.getenv()를 이용하여 환경번수를 불러오고, connect를 사용하여 연결한다.
url = os.getenv('MONGO_URI')

connect(
    db= "test", 		# db이름
    host = url)			# 환경변수

모델링

mongodb를 python과 함께 사용하기 위해 제공되는 third-party framework중 대표적인것은 mongoengine, pymodm등이 있다. 이번 프로젝트에서는 이미 mongoengine 베이스로 짜여져 있어서 mongoengine을 사용하게 되었다.

mongoengine은 Nosql인 mongodb를 마치 RDBMS처럼 사용할 수 있게 해준다. RDBMS의 쿼리나 모델링등에 익숙한 사람에게는 좀더 이해하기가 쉽고 쿼리작성도 원만하게 해주는 장점이 있다. 내가 생각하는 mongoengine의 가장 큰 장점은 원래 mongodb가 binary 형태로 저장하는 ObjectId(primary key같은 id로 새 document가 생성될때 저절로 부여됨)를 .id를 사용하여 코드에 바로 사용할 수 있는 string 형태로 가져올 수 있게 해준다는 점이다.

하지만 단점으로는 modeling이라는 것이 존재하기 때문에, Nosql의 장점인 flexible한 데이터 저장을 어렵게 한다는 점이다. 모델링이라는 작업이 생김으로 인해, 각각의 필드의 data type을 지정해줘야 하는데, Person이라는 class의 job 필드의 value의 형태가 {"job":["teatcher", "programmer", "mom"]} 과 같은 dictionary안에 list가 저장되는 형식이면 모델링도 jobs = DictField(ListField(StringField))) 같은 형식으로 해 주어야 한다는 점이다. value의 형태가 복잡해질수록 데이터 타입을 정의하는게 꽤 귀찮아 지기도 한다..

flexible한 class 만들기

꼭 flexible한 형태로 데이터를 저장해야 할때는 모델의 필드에meta = {'strict':False}를 사용하면 된다. 이를 사용하면 앞서 정의되지않는 parents와 같은 필드를 city document에 저장할 수 있다.
(**를 사용하면 mongodb에 저장되는 BSON형태 그대로 데이터를 저장할 수 있다)

쿼리

장고의 ORM과 비슷하여, 장고를 사용한적이 있다면 사용이 편리할 것이다.

# 1. <collection이름>.objects() : 해당 콜렉션의 documents 불러오기 
Cities.objects()
Cities.objects.all_field()
> <Cities Objects>
> <Cities Objects>

# 2. <collection>.objects.get(<field이름> = "<검색할값>")
a = Cities.objects.get(name="Atlanta")
a.name
> Atlanta

# 3. delete(): 삭제
Places.objects(city=city_id).delete()

# 4. <class이름>(필드이름=값): 새 document 생성하기

# name이라는 field가 Places class에 정의되어 있는 경우
place = Places(name="Houston")	
place.save()	# 저장

# 필드가 정의되지 않은 경우는, **를 사용하여 저장하고 싶은 형태 그대로를 저장할 수 있다. 
new_city = Cities(**{"parent": {"country":{"parent":{"continent" : {"name" : country.continent.name, "reference" : continent_id}}, "name":country.name, "reference":country_id}}}, created_at=datetime.datetime.utcnow())
new_city.save()

# 5. 이미 있는 다큐먼트 업데이트하기
# update를 사용해도 되나, full_result=True 설정을 하지 않으면 update된 document의 갯수를 리턴한다.
# returns the number of updated documents (unless full_result is True)
city = Cities.objects(id=city_id).modify(
                                                bbox            = converted_bbox,
                                                geolocation     = coordinates_values,
                                                name            = updated_data['name'],
                                                name_suffix     = updated_data['name_suffix'],
                                                roman_name      = updated_data['roman_name'],
                                                native_name     = updated_data['native_name'],
                                                description     = updated_data['description']
                                            )     
                                            

좀 더 다양한 쿼리의 예는 mongoengine 공식문서에서 확인 가능하다.

ReferenceField 쿼리

Referencefield 로 설정한 경우, RDBMS의 lookup처럼 Referencefield로 설정된 collections의 key들에 접근 할 수 있다.

예제

Places class 는 city 라는 ReferenceField를 가지고 있다.


Place 객체를 하나 불러와서 저장한 place_datacity의 정보를 역참조하여 해당 필드의 name에 접근할 수 있다.

cityname인 Hong Kong이 출력된 것을 확인할 수 있다.

profile
🔰

0개의 댓글