Mongodb and Python-1

Download as pdf or txt
Download as pdf or txt
You are on page 1of 66

Patterns and Processesfor the Popular

Document-Oriented Database

'TV- V . .

MB*
'

,LM.
=
7« ''7 7
‘sPM
m
u

*§lv , s.’
m
:mm

MongoDB
& Python
O’REILLY Niall O’Higgins
MongoDB and Python
Learn how to leverage MongoDD with your Python applications, using
the hands-on recipes in this book. You get complete code samples
for tasks such as making fast geo queries for location-based apps,
efficiently indexing your user documents for social-graph lookups, and
many other scenarios.

This guide explains the basics of the document-oriented database and


shows you how to set up a Python environment with it. Learn how to
read and write to MongoDB, apply idiomatic MongoDB and Python
patterns, and use the database with several popular Python web frame¬
works. You’ll discover how to model your data, write effective queries,
and avoid concurrency problems such as race conditions and deadlocks.

The recipes will help you:


Read, write, count, and sort documents in a MongoDB collection
Learn how to use the rich MongoDB query language
Maintain data integrity in replicated/distributed MongoDB
environments
Use embedding to efficiently model your data without joins
Code defensively to avoid KeyErrors and other bugs
Apply atomic operations to update game scores, billing systems,
and more with the fast accounting pattern
Use MongoDB with the Pylons 1 .x, Django, and Pyramid web
frameworks

Strata
Strata is the emerging ecosystem of people,
tools, and technologies that turn big data
into smart decisions. Find information and
Making Data Work resources at oreilly.com/data.

Twitter: @oreillymedia
facebook.com/orei I ly
US$19.99 CAN $20.99
ISBN: 978-1-449-31037-0
®

I 5 19 9 9 O’REILLY
oreilly.com
9 781449 310370

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
MongoDB and Python

1LDOO2¦+LJJLQV

O REILLY
Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
MongoDB and Python
E\1LDOO2¦+LJJLQV

&RS\ULJKW‹1LDOO2¦+LJJLQV$OOULJKWVUHVHUYHG
3ULQWHGLQWKH8QLWHG6WDWHVRI$PHULFD

3XEOLVKHGE\2¦5HLOO\0HGLD,QF*UDYHQVWHLQ+LJKZD\1RUWK6HEDVWRSRO&$

2¦5HLOO\ERRNVPD\EHSXUFKDVHGIRUHGXFDWLRQDOEXVLQHVVRUVDOHVSURPRWLRQDOXVH2QOLQHHGLWLRQV
DUHDOVRDYDLODEOHIRUPRVWWLWOHV KWWSP\VDIDULERRNVRQOLQHFRP )RUPRUHLQIRUPDWLRQFRQWDFWRXU
FRUSRUDWHLQVWLWXWLRQDOVDOHVGHSDUWPHQW  RUFRUSRUDWH#RUHLOO\FRP

Editors: 0LNH/RXNLGHVDQG6KDZQ:DOODFH Cover Designer: .DUHQ0RQWJRPHU\


Production Editor: -DVPLQH3HUH] Interior Designer: 'DYLG)XWDWR
Proofreader: 2¦5HLOO\3URGXFWLRQ6HUYLFHV Illustrator: 5REHUW5RPDQR

1XWVKHOO+DQGERRNWKH1XWVKHOO+DQGERRNORJRDQGWKH2¦5HLOO\ORJRDUHUHJLVWHUHGWUDGHPDUNVRI
2¦5HLOO\0HGLD,QF0RQJR'%DQG3\WKRQWKHLPDJHRIDGZDUIPRQJRRVHDQGUHODWHGWUDGHGUHVVDUH
WUDGHPDUNVRI2¦5HLOO\0HGLD,QF
0DQ\RIWKHGHVLJQDWLRQVXVHGE\PDQXIDFWXUHUVDQGVHOOHUVWRGLVWLQJXLVKWKHLUSURGXFWVDUHFODLPHGDV
WUDGHPDUNV:KHUHWKRVHGHVLJQDWLRQVDSSHDULQWKLVERRNDQG2¦5HLOO\0HGLD,QFZDVDZDUHRID
WUDGHPDUNFODLPWKHGHVLJQDWLRQVKDYHEHHQSULQWHGLQFDSVRULQLWLDOFDSV

:KLOHHYHU\SUHFDXWLRQKDVEHHQWDNHQLQWKHSUHSDUDWLRQRIWKLVERRNWKHSXEOLVKHUDQGDXWKRUDVVXPH
QRUHVSRQVLELOLW\IRUHUURUVRURPLVVLRQVRUIRUGDPDJHVUHVXOWLQJIURPWKHXVHRIWKHLQIRUPDWLRQFRQ
WDLQHGKHUHLQ

,6%1

>/6,@



|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
Table of Contents

Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v

1. Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
,QWURGXFWLRQ 
)LQGLQJ5HIHUHQFH'RFXPHQWDWLRQ 
,QVWDOOLQJ0RQJR'% 
5XQQLQJ0RQJR'% 
6HWWLQJXSD3\WKRQ(QYLURQPHQWZLWK0RQJR'% 

2. Reading and Writing to MongoDB with Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9


&RQQHFWLQJWR0RQJR'%ZLWK3\WKRQ 
*HWWLQJD'DWDEDVH+DQGOH 
,QVHUWLQJD'RFXPHQWLQWRD&ROOHFWLRQ 
:ULWHWRD&ROOHFWLRQ6DIHO\DQG6\QFKURQRXVO\ 
*XDUDQWHHLQJ:ULWHVWR0XOWLSOH'DWDEDVH1RGHV 
,QWURGXFWLRQWR0RQJR'%4XHU\/DQJXDJH 
5HDGLQJ&RXQWLQJDQG6RUWLQJ'RFXPHQWVLQD&ROOHFWLRQ 
8SGDWLQJ'RFXPHQWVLQD&ROOHFWLRQ 
'HOHWLQJ'RFXPHQWVIURPD&ROOHFWLRQ 
0RQJR'%4XHU\2SHUDWRUV 
0RQJR'%8SGDWH0RGLILHUV 

3. Common MongoDB and Python Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23


$8QLTXHO\'RFXPHQW2ULHQWHG3DWWHUQ(PEHGGLQJ 
)DVW/RRNXSV8VLQJ,QGH[HVZLWK0RQJR'% 
/RFDWLRQEDVHG$SSVZLWK0RQJR'%*HR6SDWLDO,QGH[LQJ 
&RGH'HIHQVLYHO\WR$YRLG.H\(UURUVDQG2WKHU%XJV 
8SGDWHRU,QVHUW8SVHUWVLQ0RQJR'% 
$WRPLF5HDG:ULWH0RGLI\0RQJR'%¦VILQG$QG0RGLI\ 
)DVW$FFRXQWLQJ3DWWHUQ 

iii

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
4. MongoDB with Web Frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3\ORQV[DQG0RQJR'% 
3\UDPLGDQG0RQJR'% 
'MDQJRDQG0RQJR'% 
*RLQJ)XUWKHU 

iv | Table of Contents

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
Preface

,¦YH EHHQ EXLOGLQJ SURGXFWLRQ GDWDEDVHGULYHQ DSSOLFDWLRQV IRU DERXW  \HDUV ,¦YH
ZRUNHG ZLWK PRVW RI WKH XVXDO UHODWLRQDO GDWDEDVHV 0664/ 6HUYHU 0\64/
3RVWJUH64/ DQGZLWKVRPHYHU\LQWHUHVWLQJQRQUHODWLRQDOGDWDEDVHV )UHHEDVHFRP¦V
*UDSKG04/%HUNHOH\'%0RQJR'% 0RQJR'%LVDWWKLVSRLQWWKHV\VWHP,HQMR\
ZRUNLQJZLWKWKHPRVWDQGFKRRVHIRUPRVWSURMHFWV,WVLWVVRPHZKHUHDWDFURVVURDGV
EHWZHHQWKHSHUIRUPDQFHDQGSUDJPDWLVPRIDUHODWLRQDOV\VWHPDQGWKHIOH[LELOLW\DQG
H[SUHVVLYHQHVVRIDVHPDQWLFZHEGDWDEDVH,WKDVEHHQFHQWUDOWRP\VXFFHVVLQEXLOGLQJ
VRPHTXLWHFRPSOLFDWHGV\VWHPVLQDVKRUWSHULRGRIWLPH
,KRSHWKDWDIWHUUHDGLQJWKLVERRN\RXZLOOILQG0RQJR'%WREHDSOHDVDQWGDWDEDVH
WRZRUNZLWKDQGRQHZKLFKGRHVQ¦WJHWLQWKHZD\EHWZHHQ\RXDQGWKHDSSOLFDWLRQ
\RXZLVKWREXLOG

Conventions Used in This Book


7KHIROORZLQJW\SRJUDSKLFDOFRQYHQWLRQVDUHXVHGLQWKLVERRN
,WDOLF
,QGLFDWHVQHZWHUPV85/VHPDLODGGUHVVHVILOHQDPHVDQGILOHH[WHQVLRQV
Constant width
8VHGIRUSURJUDPOLVWLQJVDVZHOODVZLWKLQSDUDJUDSKVWRUHIHUWRSURJUDPHOHPHQWV
VXFKDVYDULDEOHRUIXQFWLRQQDPHVGDWDEDVHVGDWDW\SHVHQYLURQPHQWYDULDEOHV
VWDWHPHQWVDQGNH\ZRUGV
Constant width bold
6KRZVFRPPDQGVRURWKHUWH[WWKDWVKRXOGEHW\SHGOLWHUDOO\E\WKHXVHU
Constant width italic
6KRZVWH[WWKDWVKRXOGEHUHSODFHGZLWKXVHUVXSSOLHGYDOXHVRUE\YDOXHVGHWHU
PLQHGE\FRQWH[W

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
7KLVLFRQVLJQLILHVDWLSVXJJHVWLRQRUJHQHUDOQRWH
if,
|JA

7KLVLFRQLQGLFDWHVDZDUQLQJRUFDXWLRQ

Using Code Examples


7KLVERRNLVKHUHWRKHOS\RXJHW\RXUMREGRQH,QJHQHUDO\RXPD\XVHWKHFRGHLQ
WKLVERRNLQ\RXUSURJUDPVDQGGRFXPHQWDWLRQ<RXGRQRWQHHGWRFRQWDFWXVIRU
SHUPLVVLRQXQOHVV\RX¦UHUHSURGXFLQJDVLJQLILFDQWSRUWLRQRIWKHFRGH)RUH[DPSOH
ZULWLQJDSURJUDPWKDWXVHVVHYHUDOFKXQNVRIFRGHIURPWKLVERRNGRHVQRWUHTXLUH
SHUPLVVLRQ6HOOLQJRUGLVWULEXWLQJD&'520RIH[DPSOHVIURP2¦5HLOO\ERRNVGRHV
UHTXLUHSHUPLVVLRQ $QVZHULQJ D TXHVWLRQ E\FLWLQJWKLVERRNDQGTXRWLQJH[DPSOH
FRGHGRHVQRWUHTXLUHSHUPLVVLRQ,QFRUSRUDWLQJDVLJQLILFDQWDPRXQWRIH[DPSOHFRGH
IURPWKLVERRNLQWR\RXUSURGXFW¦VGRFXPHQWDWLRQGRHVUHTXLUHSHUPLVVLRQ
:HDSSUHFLDWHEXWGRQRWUHTXLUHDWWULEXWLRQ$QDWWULEXWLRQXVXDOO\LQFOXGHVWKHWLWOH
DXWKRUSXEOLVKHUDQG,6%1)RUH[DPSOH£0RQJR'%DQG3\WKRQE\1LDOO2¦+LJJLQV
&RS\ULJKW2¦5HLOO\0HGLD,QF¤
,I\RXIHHO\RXUXVHRIFRGHH[DPSOHVIDOOVRXWVLGHIDLUXVHRUWKHSHUPLVVLRQJLYHQDERYH
IHHOIUHHWRFRQWDFWXVDWSHUPLVVLRQV#RUHLOO\FRP

Safari® Books Online


6DIDUL%RRNV2QOLQHLVDQRQGHPDQGGLJLWDOOLEUDU\WKDWOHWV\RXHDVLO\
Safari
Books Online VHDUFKRYHUWHFKQRORJ\DQGFUHDWLYHUHIHUHQFHERRNVDQGYLGHRVWR
ILQGWKHDQVZHUV\RXQHHGTXLFNO\
:LWKDVXEVFULSWLRQ\RXFDQUHDGDQ\SDJHDQGZDWFKDQ\YLGHRIURPRXUOLEUDU\RQOLQH
5HDGERRNVRQ\RXUFHOOSKRQHDQGPRELOHGHYLFHV$FFHVVQHZWLWOHVEHIRUHWKH\DUH
DYDLODEOHIRUSULQWDQGJHWH[FOXVLYHDFFHVVWRPDQXVFULSWVLQGHYHORSPHQWDQGSRVW
IHHGEDFNIRUWKHDXWKRUV&RS\DQGSDVWHFRGHVDPSOHVRUJDQL]H\RXUIDYRULWHVGRZQ
ORDGFKDSWHUVERRNPDUNNH\VHFWLRQVFUHDWHQRWHVSULQWRXWSDJHVDQGEHQHILWIURP
WRQVRIRWKHUWLPHVDYLQJIHDWXUHV
2¦5HLOO\0HGLDKDVXSORDGHGWKLVERRNWRWKH6DIDUL%RRNV2QOLQHVHUYLFH7RKDYHIXOO
GLJLWDODFFHVVWRWKLVERRNDQGRWKHUVRQVLPLODUWRSLFVIURP2¦5HLOO\DQGRWKHUSXE
OLVKHUVVLJQXSIRUIUHHDWKWWSP\VDIDULERRNVRQOLQHFRP

vi | Preface

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
How to Contact Us
3OHDVHDGGUHVVFRPPHQWVDQGTXHVWLRQVFRQFHUQLQJWKLVERRNWRWKHSXEOLVKHU
2¦5HLOO\0HGLD,QF
*UDYHQVWHLQ+LJKZD\1RUWK
6HEDVWRSRO&$
 LQWKH8QLWHG6WDWHVRU&DQDGD
 LQWHUQDWLRQDORUORFDO
 ID[
:HKDYHDZHESDJHIRUWKLVERRNZKHUHZHOLVWHUUDWDH[DPSOHVDQGDQ\DGGLWLRQDO
LQIRUPDWLRQ<RXFDQDFFHVVWKLVSDJHDW
KWWSZZZRUHLOO\FRPFDWDORJ
7RFRPPHQWRUDVNWHFKQLFDOTXHVWLRQVDERXWWKLVERRNVHQGHPDLOWR
ERRNTXHVWLRQV#RUHLOO\FRP
)RUPRUHLQIRUPDWLRQDERXWRXUERRNVFRXUVHVFRQIHUHQFHVDQGQHZVVHHRXUZHEVLWH
DWKWWSZZZRUHLOO\FRP
)LQGXVRQ)DFHERRNKWWSIDFHERRNFRPRUHLOO\
)ROORZXVRQ7ZLWWHUKWWSWZLWWHUFRPRUHLOO\PHGLD
:DWFKXVRQ<RX7XEHKWWSZZZ\RXWXEHFRPRUHLOO\PHGLD

Acknowledgments
,ZRXOGOLNHWRWKDQN$ULHO%DFNHQURWK$VHHP0RKDQW\DQG(XJHQH&LXUDQDIRUJLYLQJ
GHWDLOHGIHHGEDFNRQWKHILUVWGUDIWRIWKLVERRN,ZRXOGDOVROLNHWRWKDQNWKH2¦5HLOO\
WHDPIRUPDNLQJLWDJUHDWSOHDVXUHWRZULWHWKHERRN2IFRXUVHWKDQNVWRDOOWKHSHRSOH
DWJHQZLWKRXWZKRP0RQJR'%ZRXOGQRWH[LVWDQGWKLVERRNZRXOGQRWKDYHEHHQ
SRVVLEOH

Preface | vii

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
CHAPTER 1
Getting Started

Introduction
)LUVWUHOHDVHGLQ0RQJR'%LVUHODWLYHO\QHZRQWKHGDWDEDVHVFHQHFRPSDUHGWR
FRQWHPSRUDU\ JLDQWV OLNH 2UDFOH ZKLFK WUDFH WKHLU ILUVW UHOHDVHV WR WKH ¦V $V D
GRFXPHQWRULHQWHGGDWDEDVHJHQHUDOO\JURXSHGLQWRWKH1R64/FDWHJRU\LWVWDQGVRXW
DPRQJGLVWULEXWHGNH\YDOXHVWRUHV$PD]RQ'\QDPRFORQHVDQG*RRJOH%LJ7DEOHUH
LPSOHPHQWDWLRQV:LWKDIRFXVRQULFKRSHUDWRUVXSSRUWDQGKLJKSHUIRUPDQFH2QOLQH
7UDQVDFWLRQ3URFHVVLQJ 2/73 0RQJR'%LVLQPDQ\ZD\VFORVHUWR0\64/WKDQWR
EDWFKRULHQWHGGDWDEDVHVOLNH+%DVH
7KH NH\ GLIIHUHQFHV EHWZHHQ 0RQJR'%¦V GRFXPHQWRULHQWHG DSSURDFK DQG D WUDGL
WLRQDOUHODWLRQDOGDWDEDVHDUH
 0RQJR'%GRHVQRWVXSSRUWMRLQV
 0RQJR'%GRHVQRWVXSSRUWWUDQVDFWLRQV,WGRHVKDYHVRPHVXSSRUWIRUDWRPLF
RSHUDWLRQVKRZHYHU
 0RQJR'%VFKHPDVDUHIOH[LEOH1RWDOOGRFXPHQWVLQDFROOHFWLRQPXVWDGKHUHWR
WKHVDPHVFKHPD
DQGDUHDGLUHFWUHVXOWRIWKHKXJHGLIILFXOWLHVLQPDNLQJWKHVHIHDWXUHVVFDOHDFURVV
DODUJHGLVWULEXWHGV\VWHPZKLOHPDLQWDLQLQJDFFHSWDEOHSHUIRUPDQFH7KH\DUHWUDGH
RIIVPDGHLQRUGHUWRDOORZIRUKRUL]RQWDOVFDODELOLW\$OWKRXJK0RQJR'%ODFNVMRLQV
LWGRHVLQWURGXFHVRPHDOWHUQDWLYHFDSDELOLWHVHJHPEHGGLQJZKLFKFDQEHXVHGWR
VROYHPDQ\RIWKHVDPHGDWDPRGHOLQJSUREOHPVDVMRLQV2IFRXUVHHYHQLIHPEHGGLQJ
GRHVQ¦WTXLWHZRUN\RXFDQDOZD\VSHUIRUP\RXUMRLQLQDSSOLFDWLRQFRGHE\PDNLQJ
PXOWLSOHTXHULHV
7KHODFNRIWUDQVDFWLRQVFDQEHSDLQIXODWWLPHVEXWIRUWXQDWHO\0RQJR'%VXSSRUWVD
IDLUO\GHFHQWVHWRIDWRPLFRSHUDWLRQV)URPWKHEDVLFDWRPLFLQFUHPHQWDQGGHFUHPHQW
RSHUDWRUVWRWKHULFKHU£ILQG$QG0RGLI\¤ZKLFKLVHVVHQWLDOO\DQDWRPLFUHDGPRGLI\
ZULWHRSHUDWRU

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
,WWXUQVRXWWKDWDIOH[LEOHVFKHPDFDQEHYHU\EHQHILFLDOHVSHFLDOO\ZKHQ\RXH[SHFW
WREHLWHUDWLQJTXLFNO\:KLOHXSIURQWVFKHPDGHVLJQ¢DVXVHGLQWKHUHODWLRQDOPRGHO
¢KDVLWVSODFHWKHUHLVRIWHQDKHDY\FRVWLQWHUPVRIPDLQWHQDQFH+DQGOLQJVFKHPD
XSGDWHVLQWKHUHODWLRQDOZRUOGLVRIFRXUVHGRDEOHEXWFRPHVZLWKDSULFH
,Q0RQJR'%\RXFDQDGGQHZSURSHUWLHVDWDQ\WLPHG\QDPLFDOO\ZLWKRXWKDYLQJWR
ZRUU\DERXW$/7(57$%/(VWDWHPHQWVWKDWFDQWDNHKRXUVWRUXQDQGFRPSOLFDWHG
GDWDPLJUDWLRQVFULSWV+RZHYHUWKLVDSSURDFKGRHVFRPHZLWKLWVRZQWUDGHRIIV)RU
H[DPSOHW\SHHQIRUFHPHQWPXVWEHFDUHIXOO\KDQGOHGE\WKHDSSOLFDWLRQFRGH&XVWRP
GRFXPHQWYHUVLRQLQJPLJKWEHGHVLUDEOHWRDYRLGODUJHFRQGLWLRQDOEORFNVWRKDQGOH
KHWHURJHQHRXVGRFXPHQWVLQWKHVDPHFROOHFWLRQ
7KHG\QDPLFQDWXUHRI0RQJR'%OHQGVLWVHOITXLWHQDWXUDOO\WRZRUNLQJZLWKDG\QDPLF
ODQJXDJHVXFKDV3\WKRQ7KHWUDGHRIIVEHWZHHQDG\QDPLFDOO\W\SHGODQJXDJHVXFKDV
3\WKRQDQGDVWDWLFDOO\W\SHGODQJXDJHVXFKDV-DYDLQPDQ\UHVSHFWVPLUURUWKHWUDGH
RIIVEHWZHHQWKHIOH[LEOHGRFXPHQWRULHQWHGPRGHORI0RQJR'%DQGWKHXSIURQWDQG
VWDWLFDOO\W\SHGVFKHPDGHILQLWLRQRI64/GDWDEDVHV
3\WKRQDOORZV\RXWRH[SUHVV0RQJR'%GRFXPHQWVDQGTXHULHVQDWLYHO\WKURXJKWKH
XVHRIH[LVWLQJODQJXDJHIHDWXUHVOLNHQHVWHGGLFWLRQDULHVDQGOLVWV,I\RXKDYHZRUNHG
ZLWK-621LQ3\WKRQ\RXZLOOLPPHGLDWHO\EHFRPIRUWDEOHZLWK0RQJR'%GRFXPHQWV
DQGTXHULHV
)RUWKHVHUHDVRQV0RQJR'%DQG3\WKRQPDNHDSRZHUIXOFRPELQDWLRQIRUUDSLGLWHU
DWLYHGHYHORSPHQWRIKRUL]RQWDOO\VFDODEOHEDFNHQGDSSOLFDWLRQV)RUWKHYDVWPDMRULW\
RIPRGHUQ:HEDQGPRELOHDSSOLFDWLRQVZHEHOLHYH0RQJR'%LVOLNHO\DEHWWHUILWWKDQ
5'%06WHFKQRORJ\

Finding Reference Documentation


0RQJR'%3\WKRQJHQ¦V3\0RQJRGULYHUDQGHDFKRIWKH:HEIUDPHZRUNVPHQ
WLRQHGLQWKLVERRNDOOKDYHJRRGUHIHUHQFHGRFXPHQWDWLRQRQOLQH
)RU0RQJR'%ZHZRXOGVWURQJO\VXJJHVWERRNPDUNLQJDQGDWOHDVWVNLPPLQJRYHU
WKHRIILFLDO0RQJR'%PDQXDOZKLFKLVDYDLODEOHLQDIHZGLIIHUHQWIRUPDWVDQGFRQ
VWDQWO\XSGDWHGDWKWWSZZZPRQJRGERUJGLVSOD\'2&60DQXDO:KLOHWKHPDQXDO
GHVFULEHVWKH-DYD6FULSWLQWHUIDFHYLDWKHmongoFRQVROHXWLOLW\DVRSSRVHGWRWKH3\WKRQ
LQWHUIDFHPRVWRIWKHFRGHVQLSSHWVVKRXOGEHHDVLO\XQGHUVWRRGE\D3\WKRQSURJUDP
PHUDQGPRUHRUOHVVSRUWDEOHWR3\0RQJRDOEHLWVRPHWLPHVZLWKDOLWWOHELWRIZRUN
)XUWKHUPRUHWKH0RQJR'%PDQXDOJRHVLQWRJUHDWHUGHSWKRQFHUWDLQDGYDQFHGDQG
WHFKQLFDOLPSOHPHQWDWLRQDQGGDWDEDVHDGPLQLVWUDWLRQWRSLFVWKDQLVSRVVLEOHLQWKLV
ERRN

2 | Chapter 1:ಗGetting Started

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
)RUWKH3\WKRQODQJXDJHDQGVWDQGDUGOLEUDU\\RXFDQXVHWKHhelp()IXQFWLRQLQWKH
LQWHUSUHWHURUWKH pydocWRRORQWKHFRPPDQGOLQHWRJHW$3,GRFXPHQWDWLRQIRUDQ\
PHWKRGVRUPRGXOHV)RUH[DPSOH
pydoc string

7KHODWHVW3\WKRQODQJXDJHDQG$3,GRFXPHQWDWLRQLVDOVRDYDLODEOHIRURQOLQHEURZVLQJ
DWKWWSGRFVS\WKRQRUJ
JHQ¦V3\0RQJRGULYHUKDV$3,GRFXPHQWDWLRQDYDLODEOHRQOLQHWRJRZLWKHDFKUH
OHDVH<RXFDQILQGWKLVDWKWWSDSLPRQJRGERUJS\WKRQ$GGLWLRQDOO\RQFH\RXKDYH
WKH3\0RQJRGULYHUSDFNDJHLQVWDOOHGRQ\RXUV\VWHPDVXPPDU\YHUVLRQRIWKH$3,
GRFXPHQWDWLRQ VKRXOG EH DYDLODEOH WR \RX LQ WKH 3\WKRQ LQWHUSUHWHU YLD WKH help()
IXQFWLRQ'XHWRDQLVVXHZLWKWKHvirtualenvWRROPHQWLRQHGLQWKHQH[WVHFWLRQ£S\
GRF¤GRHVQRWZRUNLQVLGHDYLUWXDOHQYLURQPHQW<RXPXVWLQVWHDGUXQpython -m pydoc
pymongo

Installing MongoDB
)RUWKHSXUSRVHVRIGHYHORSPHQWLWLVUHFRPPHQGHGWRUXQD0RQJR'%VHUYHURQ\RXU
ORFDOPDFKLQH7KLVZLOOSHUPLW\RXWRLWHUDWHTXLFNO\DQGWU\QHZWKLQJVZLWKRXWIHDU
RIGHVWUR\LQJDSURGXFWLRQGDWDEDVH$GGLWLRQDOO\\RXZLOOEHDEOHWRGHYHORSZLWK
0RQJR'%HYHQZLWKRXWDQ,QWHUQHWFRQQHFWLRQ
'HSHQGLQJRQ\RXURSHUDWLQJV\VWHP\RXPD\KDYHPXOWLSOHRSWLRQVIRUKRZWRLQVWDOO
0RQJR'%ORFDOO\
0RVWPRGHUQ81,;OLNHV\VWHPVZLOOKDYHDYHUVLRQRI0RQJR'%DYDLODEOHLQWKHLU
SDFNDJHPDQDJHPHQWV\VWHP7KLVLQFOXGHV)UHH%6''HELDQ8EXQWX)HGRUD&HQ
W26DQG$UFK/LQX[,QVWDOOLQJRQHRIWKHVHSDFNDJHVLVOLNHO\WKHPRVWFRQYHQLHQWDS
SURDFKDOWKRXJKWKHYHUVLRQRI0RQJR'%SURYLGHGE\\RXUSDFNDJLQJYHQGRUPD\ODJ
EHKLQGWKHODWHVWUHOHDVHIURPJHQ)RUORFDOGHYHORSPHQWDVORQJDV\RXKDYHWKH
ODWHVWPDMRUUHOHDVH\RXDUHSUREDEO\ILQH
JHQDOVRSURYLGHVWKHLURZQ0RQJR'%SDFNDJHVIRUPDQ\V\VWHPVZKLFKWKH\XSGDWH
YHU\TXLFNO\RQHDFKUHOHDVH7KHVHFDQEHDOLWWOHPRUHZRUNWRJHWLQVWDOOHGEXWHQVXUH
\RXDUHUXQQLQJWKHODWHVWDQGJUHDWHVW$IWHUWKHLQLWLDOVHWXSWKH\DUHW\SLFDOO\WULYLDO
WRNHHSXSWRGDWH)RUDSURGXFWLRQGHSOR\PHQWZKHUH\RXOLNHO\ZDQWWREHDEOHWR
XSGDWHWRWKHPRVWUHFHQWVWDEOH0RQJR'%YHUVLRQZLWKDPLQLPXPRIKDVVOHWKLV
RSWLRQSUREDEO\PDNHVWKHPRVWVHQVH
,QDGGLWLRQWRWKHV\VWHPSDFNDJHYHUVLRQVRI0RQJR'%JHQSURYLGHELQDU\]LSDQG
WDUDUFKLYHV7KHVHDUHLQGHSHQGHQWRI\RXUV\VWHPSDFNDJHPDQDJHUDQGDUHSURYLGHG
LQERWKELWDQGELWIODYRXUVIRU26;:LQGRZV/LQX[DQG6RODULVJHQDOVR
SURYLGHVWDWLFDOO\EXLOWELQDU\GLVWULEXWLRQVRIWKLVNLQGIRU/LQX[ZKLFKPD\EH\RXU
EHVWRSWLRQLI\RXDUHVWXFNRQDQROGHUOHJDF\/LQX[V\VWHPODFNLQJWKHPRGHUQOLEF

Installing MongoDB | 3

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
DQGRWKHUOLEUDU\YHUVLRQV$OVRLI\RXDUHRQ26;:LQGRZVRU6RODULVWKHVHDUH
SUREDEO\\RXUEHVWEHW
)LQDOO\\RXFDQDOZD\VEXLOG\RXURZQELQDULHVIURPWKHVRXUFHFRGH8QOHVV\RXQHHG
WRPDNHPRGLILFDWLRQVWR0RQJR'%LQWHUQDOV\RXUVHOIWKLVPHWKRGLVEHVWDYRLGHGGXH
WRWKHWLPHDQGFRPSOH[LW\LQYROYHG
,QWKHLQWHUHVWVRIVLPSOLFLW\ZHZLOOSURYLGHWKHFRPPDQGVUHTXLUHGWRLQVWDOODVWDEOH
YHUVLRQRI0RQJR'%XVLQJWKHV\VWHPSDFNDJHPDQDJHURIWKHPRVWFRPPRQ81,;
OLNHRSHUDWLQJV\VWHPV7KLVLVWKHHDVLHVWPHWKRGDVVXPLQJ\RXDUHRQRQHRIWKHVH
SODWIRUPV)RU0DF26;DQG:LQGRZVZHSURYLGHLQVWUXFWLRQVWRLQVWDOOWKHELQDU\
SDFNDJHVIURPJHQ
8EXQWX'HELDQ
sudo apt-get update; sudo apt-get install mongodb

)HGRUD
sudo yum install mongo-stable-server

)UHH%6'
sudo pkg_add -r mongodb

:LQGRZV
*RWRKWWSZZZPRQJRGERUJDQGGRZQORDGWKHODWHVWSURGXFWLRQUHOHDVH]LSILOHIRU
:LQGRZV¢FKRRVLQJELWRUELWGHSHQGLQJRQ\RXUV\VWHP([WUDFWWKHFRQWHQWV
RIWKH]LSILOHWRDORFDWLRQOLNHC:\mongodbDQGDGGWKHbinGLUHFWRU\WR\RXU3$7+
0DF26;
*RWRKWWSZZZPRQJRGERUJDQGGRZQORDGWKHODWHVWSURGXFWLRQUHOHDVHFRPSUHVVHG
WDUILOHIRU26;¢FKRRVLQJELWRUELWGHSHQGLQJRQ\RXUV\VWHP([WUDFWWKH
FRQWHQWVWRDORFDWLRQOLNH/usr/local/RU/optDQGDGGWKHbinGLUHFWRU\WR\RXU3$7+
)RUH[PDSOH
cd /tmp
wget http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-1.8.3-rc1.tgz
tar xfz mongodb-osx-x86_64-1.8.3-rc1.tgz
sudo mkdir /usr/local/mongodb
sudo cp -r mongodb-osx-x86_64-1.8.3-rc1/bin /usr/local/mongodb/
export PATH=$PATH:/usr/local/mongodb/bin

4 | Chapter 1:ಗGetting Started

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
Install MongoDB on OS X with Mac Ports
,I\RXZRXOGOLNHWRWU\DWKLUGSDUW\V\VWHPSDFNDJHPDQDJHPHQWV\VWHPRQ0DF26
;\RXPD\DOVRLQVWDOO0RQJR'% DQG3\WKRQLQIDFW WKURXJK0DF3RUWV0DF3RUWV
LVVLPLODUWR)UHH%6'SRUWVEXWIRU26;
$ZRUGRIZDUQLQJWKRXJK0DF3RUWVFRPSLOHVIURPVRXUFHDQGVRFDQWDNHFRQVLG
HUDEO\ORQJHUWRLQVWDOOVRIWZDUHFRPSDUHGZLWKVLPSO\JUDEELQJWKHELQDULHV)XWKHU
PRUH\RXZLOOQHHGWRKDYH$SSOH¦V;FRGH'HYHORSHU7RROVLQVWDOOHGDORQJZLWKWKH
;ZLQGRZLQJHQYLURQPHQW
7KHILUVWVWHSLVWRLQVWDOO0DF3RUWVIURPKWWSZZZPDFSRUWVRUJ:HUHFRPPHQG
GRZQORDGLQJDQGLQVWDOOLQJWKHLU'0*SDFNDJH
2QFH\RXKDYH0DF3RUWVLQVWDOOHG\RXFDQLQVWDOO0RQJR'%ZLWKWKHFRPPDQG
sudo port selfupdate; sudo port install mongodb

7RLQVWDOO3\WKRQIURP0DF3RUWVXVHWKHFRPPDQG
sudo port selfupdate; sudo port install python27

Running MongoDB
2QVRPHSODWIRUPV¢VXFKDV8EXQWX¢WKHSDFNDJHPDQDJHUZLOODXWRPDWLFDOO\VWDUW
WKHPRQJRGGDHPRQIRU\RXDQGHQVXUHLWVWDUWVRQERRWDOVR2QRWKHUVVXFKDV0DF
26;\RXPXVWZULWH\RXURZQVFULSWWRVWDUWLWDQGPDQXDOO\LQWHJUDWHZLWKODXQFKG
VRWKDWLWVWDUWVRQV\VWHPERRW
1RWHWKDWEHIRUH\RXFDQVWDUW0RQJR'%LWVGDWDDQGORJGLUHFWRULHVPXVWH[LVW
,I\RXZLVKWRKDYH0RQJR'%VWDUWDXWRPDWLFDOO\RQERRWRQ:LQGRZVJHQKDYHD
GRFXPHQW GHVFULELQJ KRZ WR VHW WKLV XS DW KWWSZZZPRQJRGERUJGLVSOD\'2&6
:LQGRZV6HUYLFH
7RKDYH0RQJR'%VWDUWDXWRPDWLFDOO\RQERRWXQGHU0DF26;ILUVW\RXZLOOQHHGD
SOLVWILOH6DYHWKHIROORZLQJ FKDQJLQJGEDQGORJSDWKVDSSURSULDWHO\ WR /Library/
LaunchDaemons/org.mongodb.mongod.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/
PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>RunAtLoad</key>
<true/>
<key>Label</key>
<string>org.mongo.mongod</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/mongodb/bin/mongod</string>
<string>--dbpath</string>

Running MongoDB | 5

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
<string>/usr/local/mongodb/data/</string>
<string>--logpath</string>
<string>/usr/local/mongodb/log/mongodb.log</string>
</array>
</dict>
</plist>

1H[WUXQWKHIROORZLQJFRPPDQGVWRDFWLYDWHWKHVWDUWXSVFULSWZLWKODXQFKG
sudo launchctl load /Library/LaunchDaemons/org.mongodb.mongod.plist
sudo launchctl start org.mongodb.mongod

$TXLFNZD\WRWHVWZKHWKHUWKHUHLVD0RQJR'%LQVWDQFHDOUHDG\UXQQLQJRQ\RXUORFDO
PDFKLQHLVWRW\SH mongoDWWKHFRPPDQGOLQH7KLVZLOOVWDUWWKH0RQJR'%DGPLQ
FRQVROHZKLFKDWWHPSWVWRFRQQHFWWRDGDWDEDVHVHUYHUUXQQLQJRQWKHGHIDXOWSRUW
 
,QDQ\FDVH\RXFDQDOZD\VVWDUW0RQJR'%PDQXDOO\IURPWKHFRPPDQGOLQH7KLVLV
DXVHIXOWKLQJWREHIDPLOLDUZLWKLQFDVH\RXHYHUZDQWWRWHVWIHDWXUHVVXFKDVUHSOLFD
VHWVRUVKDUGLQJE\UXQQLQJPXOWLSOHPRQJRGLQVWDQFHVRQ\RXUORFDOPDFKLQH
$VVXPLQJWKHPRQJRGELQDU\LVLQ\RXU3$7+UXQ
mongod --logpath <path/to/mongo.logfile> --port <port to listen on> --dbpath <path/to/
data directory>

Setting up a Python Environment with MongoDB


,QRUGHUWREHDEOHWRFRQQHFWWR0RQJR'%ZLWK3\WKRQ\RXQHHGWRLQVWDOOWKH3\
0RQJRGULYHUSDFNDJH,Q3\WKRQWKHEHVWSUDFWLFHLVWRFUHDWHZKDWLVNQRZQDVD
£YLUWXDO HQYLURQPHQW¤ LQ ZKLFK WR LQVWDOO \RXU SDFNDJHV 7KLV LVRODWHV WKHP FOHDQO\
IURP DQ\ £V\VWHP¤ SDFNDJHV \RX KDYH LQVWDOOHG DQG \LHOGV WKH DGGHG ERQXV RI QRW
UHTXLULQJ URRW SULYLOHJHV WR LQVWDOO DGGLWLRQDO 3\WKRQ SDFNDJHV 7KH WRRO WR FUHDWH D
£YLUWXDOHQYLURQPHQW¤LVFDOOHGYLUWXDOHQY
7KHUHDUHWZRDSSURDFKHVWRLQVWDOOLQJWKHYLUWXDOHQYWRRORQ\RXUV\VWHP¢PDQXDOO\
DQGYLD\RXUV\VWHPSDFNDJHPDQDJHPHQWWRRO0RVWPRGHUQ81,;OLNHV\VWHPVZLOO
KDYHWKHYLUWXDOHQYWRROLQWKHLUSDFNDJHUHSRVLWRULHV)RUH[DPSOHRQ0DF26;ZLWK
0DF3RUWV\RXFDQUXQ sudo port install py27-virtualenvWRLQVWDOOYLUWXDOHQYIRU
3\WKRQ2Q8EXQWX\RXFDQUXQsudo apt-get install python-virtualenv5HIHU
WRWKHGRFXPHQWDWLRQIRU\RXU26WROHDUQKRZWRLQVWDOOLWRQ\RXUVSHFLILFSODWIRUP
,QFDVH\RXDUHXQDEOHRUVLPSO\GRQ¦WZDQWWRXVH\RXUV\VWHP¦VSDFNDJHPDQDJHU\RX
FDQDOZD\VLQVWDOOLW\RXUVHOIE\KDQG,QRUGHUWRPDQXDOO\LQVWDOOLW\RXPXVWKDYH
WKH3\WKRQVHWXSWRROVSDFNDJH<RXPD\DOUHDG\KDYHVHWXSWRROVRQ\RXUV\VWHP<RX
FDQWHVWWKLVE\UXQQLQJpython -c import setuptoolsRQWKHFRPPDQGOLQH,IQRWKLQJ
LVSULQWHGDQG\RXDUHVLPSO\UHWXUQHGWRWKHSURPSW\RXGRQ¦WQHHGWRGRDQ\WKLQJ
,IDQ,PSRUW(UURULVUDLVHG\RXQHHGWRLQVWDOOVHWXSWRROV

6 | Chapter 1:ಗGetting Started

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
7RPDQXDOO\LQVWDOOVHWXSWRROVILUVWGRZQORDGWKHILOHKWWSSHDNWHOHFRPPXQLW\FRP
GLVWH]BVHWXSS\
7KHQUXQpython ez_setup.pyDVURRW
)RU:LQGRZVILUVWGRZQORDGDQGLQVWDOOWKHODWHVW3\WKRQ[SDFNDJHIURPKWWS
ZZZS\WKRQRUJ2QFH\RXKDYHLQVWDOOHG3\WKRQGRZQORDGDQGLQVWDOOWKH:LQGRZV
VHWXSWRROVLQVWDOOHUSDFNDJHIURPKWWSS\SLS\WKRQRUJS\SLVHWXSWRROV$IWHULQVWDO
OLQJ3\WKRQDQGVHWXSWRROV\RXZLOOKDYHWKHHDV\BLQVWDOOWRRODYDLODEOHRQ\RXU
PDFKLQHLQWKH3\WKRQVFULSWVGLUHFWRU\¢GHIDXOWLV&?3\WKRQ?6FULSWV?
2QFH\RXKDYHVHWXSWRROVLQVWDOOHGRQ\RXUV\VWHPUXQ easy_install virtualenvDV
URRW
1RZWKDW\RXKDYHWKH£YLUWXDOHQY¤WRRODYDLODEOHRQ\RXUPDFKLQH\RXFDQFUHDWH
\RXU ILUVW YLUWXDO 3\WKRQ HQYLURQPHQW <RX FDQ GR WKLV E\ H[HFXWLQJ WKH FRPPDQG
virtualenv --no-site-packages myenv<RXGRQRWQHHG¢DQGLQGHHGVKRXOGQRWZDQW
¢WRUXQWKLVFRPPDQGZLWKURRWSULYLOHJHV7KLVZLOOFUHDWHDYLUWXDOHQYLURQPHQWLQ
WKH GLUHFWRU\ £P\HQY¤ 7KH QRVLWHSDFNDJHV RSWLRQ WR WKH £YLUWXDOHQY¤ XWLOLW\ LQ
VWUXFWVLWWRFUHDWHDFOHDQ3\WKRQHQYLURQPHQWLVRODWHGIURPDQ\H[LVWLQJSDFNDJHV
LQVWDOOHGLQWKHV\VWHP
<RXDUHQRZUHDG\WRLQVWDOOWKH3\0RQJRGULYHU
:LWKWKH£P\HQY¤GLUHFWRU\DV\RXUZRUNLQJGLUHFWRU\ LHDIWHU£FGP\HQY¤ VLPSO\
H[HFXWHbin/easy_install pymongo7KLVZLOOLQVWDOOWKHODWHVWVWDEOHYHUVLRQRI3\0RQJR
LQWR\RXUYLUWXDO3\WKRQHQYLURQPHQW7RYHULI\WKDWWKLVZRUNHGVXFFHVVIXOO\H[HFXWH
WKHFRPPDQGbin/python -c import pymongoPDNLQJVXUHWKDWWKH£P\HQY¤GLUHFWRU\
LVVWLOO\RXUZRUNLQJGLUHFWRU\DVZLWKWKHSUHYLRXVFRPPDQG
$VVXPLQJ3\WKRQGLGQRWUDLVHDQ,PSRUW(UURU\RXQRZKDYHD3\WKRQYLUWXDOHQYZLWK
WKH3\0RQJRGULYHUFRUUHFWO\LQVWDOOHGDQGDUHUHDG\WRFRQQHFWWR0RQJR'%DQGVWDUW
LVVXLQJTXHULHV

Setting up a Python Environment with MongoDB | 7

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
CHAPTER 2
Reading and Writing
to MongoDB with Python

0RQJR'%LVDGRFXPHQWRULHQWHGGDWDEDVH7KLVLVGLIIHUHQWIURPDUHODWLRQDOGDWDEDVH
LQWZRVLJQLILFDQWZD\V)LUVWO\QRWDOOHQWULHVPXVWDGKHUHWRWKHVDPHVFKHPD6HF
RQGO\\RXFDQHPEHGHQWULHVLQVLGHRIRQHDQRWKHU'HVSLWHWKHVHPDMRUGLIIHUHQFHV
WKHUHDUHDQDORJVWR64/FRQFHSWVLQ0RQJR'%$ORJLFDOJURXSRIHQWULHVLQD64/
GDWDEDVHLVWHUPHGDWDEOH,Q0RQJR'%WKHDQDORJRXVWHUPLVDFROOHFWLRQ$VLQJOH
HQWU\LQD64/GDWDEVHLVWHUPHGDURZ,Q0RQJR'%WKHDQDORJLVDGRFXPHQW
7DEOH&RPSDULVRQRI64/5'%06DQG0RQJR'%&RQFHSWVDQG7HUPV
Concept SQL MongoDB
One User One Row One Document
All Users Users Table Users Collection
One Username Per User (1-to-1) Username Column Username Property
Many Emails Per User (1-to-many) SQL JOIN with Emails Table Embed relevant email doc in User
Document
Many Items Owned by Many Users (many-to- SQL JOIN with Items Table Programmatically Join with Items
many) Collection

+HQFHLQ0RQJR'%\RXDUHPRVWO\RSHUDWLQJRQGRFXPHQWVDQGFROOHFWLRQVRIGRFX
PHQWV,I\RXDUHIDPLOLDUZLWK-621D0RQJR'%GRFXPHQWLVHVVHQWLDOO\D-621
GRFXPHQWZLWKDIHZH[WUDIHDWXUHV)URPD3\WKRQSHUVSHFWLYHLWLVD3\WKRQGLFWLRQ
DU\
&RQVLGHUWKHIROORZLQJH[DPSOHRIDXVHUGRFXPHQWZLWKDXVHUQDPHILUVWQDPHVXU
QDPHGDWHRIELUWKHPDLODGGUHVVDQGVFRUH
from datetime import datetime
user_doc = {
"username" : "janedoe",
"firstname" : "Jane",

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
"surname" : "Doe",
"dateofbirth" : datetime(1974, 4, 12),
"email" : "[email protected]",
"score" : 0
}

$V\RXFDQVHHWKLVLVDQDWLYH3\WKRQREMHFW8QOLNH64/WKHUHLVQRVSHFLDOV\QWD[WR
GHDOZLWK7KH3\0RQJRGULYHUWUDQVSDUHQWO\VXSSRUWV3\WKRQGDWHWLPHREMHFWV7KLV
LVYHU\FRQYHQLHQWZKHQZRUNLQJZLWKGDWHWLPHLQVWDQFHV¢WKHGULYHUZLOOWUDQVSDUHQWO\
PDUVKDOOWKHYDOXHVIRU\RXLQERWKUHDGVDQGZULWHV<RXVKRXOGQHYHUKDYHWRZULWH
GDWHWLPHFRQYHUVLRQFRGH\RXUVHOI
,QVWHDGRIJURXSLQJWKLQJVLQVLGHRIWDEOHVDVLQ64/0RQJR'%JURXSVWKHPLQFRO
OHFWLRQV/LNH64/WDEOHV0RQJR'%FROOHFWLRQVFDQKDYHLQGH[HVRQSDUWLFXODUGRFX
PHQWSURSHUWLHVIRUIDVWHUORRNXSVDQG\RXFDQUHDGDQGZULWHWRWKHPXVLQJFRPSOH[
TXHU\SUHGLFDWHV8QOLNH64/WDEOHVGRFXPHQWVLQD0RQJR'%FROOHFWLRQGRQRWDOO
KDYHWRFRQIRUPWRWKHVDPHVFKHPD
5HWXUQLQJWRRXUXVHUH[DPSOHDERYHVXFKGRFXPHQWVZRXOGEHORJLFDOO\JURXSHGLQ
D£XVHUV¤FROOHFWLRQ

Connecting to MongoDB with Python


7KH3\0RQJRGULYHUPDNHVFRQQHFWLQJWRD0RQJR'%GDWDEDVHTXLWHVWUDLJKWIRUZDUG
)XUWKHUPRUHWKHGULYHUVXSSRUWVVRPHQLFHIHDWXUHVULJKWRXWRIWKHER[VXFKDVFRQ
QHFWLRQSRROLQJDQGDXWRPDWLFUHFRQQHFWRQIDLOXUH ZKHQZRUNLQJZLWKDUHSOLFDWHG
VHWXS ,I\RXDUHIDPLOLDUZLWKPRUHWUDGLWLRQDO5'%0664/V\VWHPV¢IRUH[DPSOH
0\64/¢\RXDUHOLNHO\XVHGWRKDYLQJWRGHSOR\DGGLWLRQDOVRIWZDUHRUSRVVLEO\HYHQ
ZULWH\RXURZQWRKDQGOHFRQQHFWLRQSRROLQJDQGDXWRPDWLFUHFRQQHFWJHQYHU\
WKRXJKWIXOO\UHOLHYHGXVRIWKHQHHGWRZRUU\DERXWWKHVHGHWDLOVZKHQZRUNLQJZLWK
0RQJR'%DQGWKH3\0RQJRGULYHU7KLVWDNHVDORWRIWKHKHDGDFKHRXWRIUXQQLQJD
SURGXFWLRQ0RQJR'%EDVHGV\VWHP
<RX LQVWDQWLDWH D &RQQHFWLRQ REMHFW ZLWK WKH QHFHVVDU\ SDUDPHWHUV %\ GHIDXOW WKH
&RQQHFWLRQREMHFWZLOOFRQQHFWWRD0RQJR'%VHUYHURQORFDOKRVWDWSRUW7R
EHH[SOLFLWZH¦OOSDVVWKRVHSDUDPHWHUVDORQJLQRXUH[DPSOH
""" An example of how to connect to MongoDB """
import sys

from pymongo import Connection


from pymongo.errors import ConnectionFailure

def main():
""" Connect to MongoDB """
try:
c = Connection(host="localhost", port=27017)
print "Connected successfully"
except ConnectionFailure, e:
sys.stderr.write("Could not connect to MongoDB: %s" % e)

10 | Chapter 2:ಗReading and Writing to MongoDB with Python

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
sys.exit(1)

if __name__ == "__main__":
main()

$V\RXFDQVHHD&RQQHFWLRQ)DLOXUHH[FHSWLRQFDQEHWKURZQE\&RQQHFWLRQLQVWDQ
WLDWLRQ,WLVXVXDOO\DJRRGLGHDWRKDQGOHWKLVH[FHSWLRQDQGRXWSXWVRPHWKLQJLQIRU
PDWLYHWR\RXUXVHUV

Getting a Database Handle


&RQQHFWLRQ REMHFWV WKHPVHOYHV DUH QRW DOO WKDW IUHTXHQWO\ XVHG ZKHQ ZRUNLQJ ZLWK
0RQJR'%LQ3\WKRQ7\SLFDOO\\RXFUHDWHRQHRQFHDQGWKHQIRUJHWDERXWLW7KLVLV
EHFDXVHPRVWRIWKHUHDOLQWHUDFWLRQKDSSHQVZLWK'DWDEDVHDQG&ROOHFWLRQREMHFWV
&RQQHFWLRQREMHFWVDUHMXVWDZD\WRJHWDKDQGOHRQ\RXUILUVW'DWDEVHREMHFW,QIDFW
HYHQLI\RXORVHUHIHUHQFHWRWKH&RQQHFWLRQREMHFW\RXFDQDOZD\VJHWLWEDFNEHFDXVH
'DWDEDVHREMHFWVKDYHDUHIHUHQFHWRWKH&RQQHFWLRQREMHFW
*HWWLQJD'DWDEDVHREMHFWLVHDV\RQFH\RXKDYHD&RQQHFWLRQLQVWDQFH<RXVLPSO\
QHHGWRNQRZWKHQDPHRIWKHGDWDEDVHDQGWKHXVHUQDPHDQGSDVVZRUGWRDFFHVVLWLI
\RXDUHXVLQJDXWKRUL]DWLRQRQLW
""" An example of how to get a Python handle to a MongoDB database """
import sys

from pymongo import Connection


from pymongo.errors import ConnectionFailure

def main():
""" Connect to MongoDB """
try:
c = Connection(host="localhost", port=27017)
except ConnectionFailure, e:
sys.stderr.write("Could not connect to MongoDB: %s" % e)
sys.exit(1)
# Get a Database handle to a database named "mydb"
dbh = c["mydb"]

# Demonstrate the db.connection property to retrieve a reference to the


# Connection object should it go out of scope. In most cases, keeping a
# reference to the Database object for the lifetime of your program should
# be sufficient.

assert dbh.connection == c
print "Successfully set up a database handle"

if __name__ == "__main__":
main()

Getting a Database Handle | 11

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
Inserting a Document into a Collection
2QFH\RXKDYHDKDQGOHWR\RXUGDWDEDVH\RXFDQEHJLQLQVHUWLQJGDWD/HWXVLPDJLQH
ZHKDYHDFROOHFWLRQFDOOHG£XVHUV¤FRQWDLQLQJDOOWKHXVHUVRIRXUJDPH(DFKXVHUKDV
DXVHUQDPHDILUVWQDPHVXUQDPHGDWHRIELUWKHPDLODGGUHVVDQGDVFRUH:HZDQW
WRDGGDQHZXVHU
""" An example of how to insert a document """
import sys

from datetime import datetime


from pymongo import Connection
from pymongo.errors import ConnectionFailure

def main():
try:
c = Connection(host="localhost", port=27017)
except ConnectionFailure, e:
sys.stderr.write("Could not connect to MongoDB: %s" % e)
sys.exit(1)
dbh = c["mydb"]
assert dbh.connection == c
user_doc = {
"username" : "janedoe",
"firstname" : "Jane",
"surname" : "Doe",
"dateofbirth" : datetime(1974, 4, 12),
"email" : "[email protected]",
"score" : 0
}

dbh.users.insert(user_doc, safe=True)
print "Successfully inserted document: %s" % user_doc

if __name__ == "__main__":
main()

1RWHWKDWZHGRQ¦WKDYHWRWHOO0RQJR'%WRFUHDWHRXUFROOHFWLRQ£XVHUV¤EHIRUHZH
LQVHUWWRLW&ROOHFWLRQVDUHFUHDWHGOD]LO\LQ0RQJR'%ZKHQHYHU\RXDFFHVVWKHP7KLV
KDVWKHDGYDQWDJHRIEHLQJYHU\OLJKWZHLJKWEXWFDQRFFDVLRQDOO\FDXVHSUREOHPVGXH
WRW\SRV7KHVHFDQEHKDUGWRWUDFNGRZQXQOHVV\RXKDYHJRRGWHVWFRYHUDJH)RU
H[DPSOHLPDJLQH\RXDFFLGHQWDOO\W\SHG
# dbh.usrs is a typo, we mean dbh.users! Unlike an RDBMS, MongoDB won't
# protect you from this class of mistake.
dbh.usrs.insert(user_doc)

7KHFRGHZRXOGH[HFXWHFRUUHFWO\DQGQRHUURUVZRXOGEHWKURZQ<RXPLJKWEHOHIW
VFUDWFKLQJ\RXUKHDGZRQGHULQJZK\\RXUXVHUGRFXPHQWLVQ¦WWKHUH:HUHFRPPHQG
EHLQJH[WUDYLJLODQWWRGRXEOHFKHFN\RXUVSHOOLQJZKHQDGGUHVVLQJFROOHFWLRQV*RRG
WHVWFRYHUDJHFDQDOVRKHOSILQGEXJVRIWKLVVRUW

12 | Chapter 2:ಗReading and Writing to MongoDB with Python

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
$QRWKHUIHDWXUHRI0RQJR'%LQVHUWVWREHDZDUHRILVSULPDU\NH\DXWRJHQHUDWLRQ,Q
0RQJR'%WKH_idSURSHUW\RQDGRFXPHQWLVWUHDWHGVSHFLDOO\,WLVFRQVLGHUHGWREH
WKHSULPDU\NH\IRUWKDWGRFXPHQWDQGLVH[SHFWHGWREHXQLTXHXQOHVVWKHFROOHFWLRQ
KDVEHHQH[SOFLWO\FUHDWHGZLWKRXWDQLQGH[RQ _id%\GHIDXOWLIQR _idSURSHUW\LV
SUHVHQWLQDGRFXPHQW\RXLQVHUW0RQJR'%ZLOOJHQHUDWHRQHLWVHOI:KHQ0RQJR'%
JHQHUDWHVDQ _idSURSHUW\LWVHOILWXVHVWKHW\SH2EMHFW,G$0RQJR'%2EMHFW,GLVD
ELWYDOXHZKLFKLVH[SHFWHGWRKDYHDYHU\KLJKSUREDELOLW\RIEHLQJXQLTXHZKHQ
FUHDWHG,WFDQEHFRQVLGHUHGVLPLODULQSXUSRVHWRD88,'REMHFWDVGHILQHGE\5)&
0RQJR'%2EMHFW,GVKDYHWKHQLFHSURSHUW\RIEHLQJDOPRVWFHUWDLQO\XQLTXH
XSRQJHQHUDWLRQKHQFHQRFHQWUDOFRRUGLQDWLRQLVUHTXLUHG
7KLVFRQWUDVWVVKDUSO\ZLWKWKHFRPPRQ5'%06LGLRPRIXVLQJDXWRLQFUHPHQWSUL
PDU\NH\V*XDUDQWHHLQJWKDWDQDXWRLQFUHPHQWNH\LVQRWDOUHDG\LQXVHXVXDOO\UH
TXLUHVFRQVXOWLQJVRPHFHQWUDOL]HGV\VWHP:KHQWKHLQWHQWLRQLVWRSURYLGHDKRUL
]RQWDOO\VFDODEOHGHFHQWUDOL]HGDQGIDXOWWROHUDQWGDWDEDVH¢DVLVWKHFDVHZLWK0RQ
JR'%¢DXWRLQFUHPHQWNH\VUHSUHVHQWDQXJO\ERWWOHQHFN
%\HPSOR\LQJ2EMHFW,GDV\RXU_id\RXOHDYHWKHGRRURSHQWRKRUL]RQWDOVFDOLQJYLD
0RQJR'%¦VVKDUGLQJFDSDELOLWLHV:KLOH\RXFDQLQIDFWVXSSO\\RXURZQYDOXHIRUWKH
_idSURSHUW\LI\RXZLVK¢VRORQJDVLWLVJOREDOO\XQLTXH¢WKLVLVEHVWDYRLGHGXQOHVV
WKHUHLVDVWURQJUHDVRQWRGRRWKHUZLVH([DPSOHVRIFDVHVZKHUH\RXPD\EHIRUFHG
WRSURYLGH\RXURZQ_idSURSHUW\YDOXHLQFOXGHPLJUDWLRQIURP5'%06V\VWHPVZKLFK
XWLOL]HGWKHSUHYLRXVO\PHQWLRQHGDXWRLQFUHPHQWSULPDU\NH\LGLRP
1RWHWKDWDQ2EMHFW,GFDQEHMXVWDVHDVLO\JHQHUDWHGRQWKHFOLHQWVLGHZLWK3\0RQJR
DV E\ WKH VHUYHU 7R JHQHUDWH DQ 2EMHFW,G ZLWK 3\0RQJR \RX VLPSO\ LQVWDQWLDWH
pymongo.objectid.ObjectId

Write to a Collection Safely and Synchronously


%\GHIDXOWWKH3\0RQJRGULYHUSHUIRUPVDV\QFKURQRXVZULWHV:ULWHRSHUDWLRQVLQ
FOXGHLQVHUWXSGDWHUHPRYHDQGILQG$QG0RGLI\
$V\QFKURQRXVZULWHVDUHXQVDIHLQWKHVHQVHWKDWWKH\DUHQRWFKHFNHGIRUHUURUVDQG
VRH[HFXWLRQRI\RXUSURJUDPFRXOGFRQWLQXHZLWKRXWDQ\JXDUDQWHHVRIWKHZULWHKDY
LQJFRPSOHWHGVXFFHVVIXOO\:KLOHDV\QFKURQRXVZULWHVLPSURYHSHUIRUPDQFHE\QRW
EORFNLQJH[HFXWLRQWKH\FDQHDVLO\OHDGWRQDVW\UDFHFRQGLWLRQVDQGRWKHUQHIDULRXV
GDWDLQWHJULW\EXJV)RUWKLVUHDVRQZHUHFRPPHQG\RXDOPRVWDOZD\VXVHVDIHV\Q
FKURQRXVEORFNLQJZULWHV,WVHHPVUDUHLQSUDFWLFHWRKDYHWUXO\£ILUHDQGIRUJHW¤ZULWHV
ZKHUHWKHUHDUHDERVOXWHO\QRFRQVHTXHQFHVIRUIDLOXUHV7KDWEHLQJVDLGRQHFRPPRQ
H[DPSOH ZKHUH DV\QFKURQRXV ZULWHV PD\ PDNH VHQVH LV ZKHQ \RX DUH ZULWLQJ QRQ
FULWLFDOORJVRUDQDO\WLFVGDWDWR0RQJR'%IURP\RXUDSSOLFDWLRQ

Write to a Collection Safely and Synchronously | 13

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
8QOHVV\RXDUHFHUWDLQ\RXGRQ¦WQHHGV\QFKURQRXVZULWHVZHUHFRP
PHQGWKDW\RXSDVVWKH£VDIH 7UXH¤NH\ZRUGDUJXPHQWWRLQVHUWVXS
GDWHVUHPRYHVDQGILQG$QG0RGLI\RSHUDWLRQV
# safe=True ensures that your write
# will succeed or an exception will be thrown
dbh.users.insert(user_doc, safe=True)

Guaranteeing Writes to Multiple Database Nodes


7KHWHUPQRGHUHIHUVWRDVLQJOHLQVWDQFHRIWKH0RQJR'%GDHPRQSURFHVV7\SLFDOO\
WKHUHLVDVLQJOH0RQJR'%QRGHSHUPDFKLQHEXWIRUWHVWLQJRUGHYHORSPHQWFDVHV\RX
FDQUXQPXOWLSOHQRGHVRQRQHPDFKLQH
5HSOLFD6HWLVWKH0RQJR'%WHUPIRUWKHGDWDEDVH¦VHQKDQFHGPDVWHUVODYHUHSOLFDWLRQ
FRQILJXUDWLRQ 7KLV LV VLPLODU WR WKH WUDGLWLRQDO PDVWHUVODYH UHSOLFDWLRQ \RX ILQG LQ
5'%06VXFKDV0\64/DQG3RVWJUH64/LQWKDWDVLQJOHQRGHKDQGOHVZULWHVDWDJLYHQ
WLPH,Q0RQJR'%PDVWHUVHOHFWLRQLVGHWHUPLQHGE\DQHOHFWLRQSURWRFRODQGGXULQJ
IDLORYHUDVODYHLVDXWRPDWLFDOO\SURPRWHGWRPDVWHUZLWKRXWUHTXLULQJRSHUDWRULQWHU
YHQWLRQ)XUWKHUPRUHWKH3\0RQJRGULYHULV5HSOLFD6HWDZDUHDQGSHUIRUPVDXWR
PDWLFUHFRQQHFWRQIDLOXUHWRWKHQHZPDVWHU0RQJR'%5HSOLFD6HWVWKHUHIRUHUHS
UHVHQWDPDVWHUVODYHUHSOLFDWLRQFRQILJXUDWLRQZLWKH[FHOOHQWIDLOXUHKDQGOLQJRXWRI
WKHER[)RUDQ\RQHZKRKDVKDGWRPDQXDOO\UHFRYHUIURPD0\64/PDVWHUIDLOXUHLQ
DSURGXFWLRQHQYLURQPHQWWKLVIHDWXUHLVDZHOFRPHUHOLHI
%\GHIDXOW0RQJR'% ZLOO UHWXUQ VXFFHVV IRU\RXUZULWHRSHUDWLRQRQFHLWKDVEHHQ
ZULWWHQWRDVLQJOHQRGHLQD5HSOLFD6HW
+RZHYHUIRUDGGHGVDIHW\LQFDVHRIIDLOXUH\RXPD\ZLVK\RXUZULWHWREHFRPPLWWHG
WRWZRRUPRUHUHSOLFDVEHIRUHUHWXUQLQJVXFFHVV7KLVFDQKHOSHQVXUHWKDWLQFDVHRI
FDWDVWURSKLFIDLOXUHDWOHDVWRQHRIWKHQRGHVLQWKH5HSOLFD6HWZLOOKDYH\RXUZULWH
3\0RQJRPDNHVLWHDV\WRVSHFLI\KRZPDQ\QRGHV\RXZRXOGOLNH\RXUZULWHWREH
UHSOLFDWHGWREHIRUHUHWXUQLQJVXFFHVV<RXVLPSO\VHWDSDUDPHWHUQDPHG£Z¤WRWKH
QXPEHURIVHUYHUVLQHDFKZULWHPHWKRGFDOO
)RUH[DPSOH
# w=2 means the write will not succeed until it has
# been written to at least 2 servers in a replica set.
dbh.users.insert(user_doc, w=2)

1RWHWKDWSDVVLQJDQ\YDOXHRI£Z¤WRDZULWHPHWKRGLQ3\0RQJRLP
SOLHVVHWWLQJ£VDIH 7UXH¤DOVR
4r<
t£.

14 | Chapter 2:ಗReading and Writing to MongoDB with Python

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
Introduction to MongoDB Query Language
0RQJR'%TXHULHVDUHUHSUHVHQWHGDVD-621OLNHVWUXFWXUHMXVWOLNHGRFXPHQWV7R
EXLOGDTXHU\\RXVSHFLI\DGRFXPHQWZLWKSURSHUWLHV\RXZLVKWKHUHVXOWVWRPDWFK
0RQJR'%WUHDWVHDFKSURSHUW\DVKDYLQJDQLPSOLFLWERROHDQ$1',WQDWLYHO\VXSSRUWV
ERROHDQ25TXHULHVEXW\RXPXVWXVHDVSHFLDORSHUDWRU RU WRDFKLHYHLW,QDGGLWLRQ
WRH[DFWPDWFKHV0RQJR'%KDVRSHUDWRUVIRUJUHDWHUWKDQOHVVWKDQHWF
6DPSOHTXHU\GRFXPHQWWRPDWFKDOOGRFXPHQWVLQWKHXVHUVFROOHFWLRQZLWKILUVWQDPH
£MDQH¤
q = {
"firstname" : "jane"
}

,IZHZDQWHGWRUHWULHYHDOOGRFXPHQWVZLWKILUVWQDPH£MDQH¤$1'VXUQDPH£GRH¤ZH
ZRXOGZULWH
q = {
"firstname" : "jane",
"surname" : "doe"
}

,IZHZDQWHGWRUHWULHYHDOOGRFXPHQWVZLWKDVFRUHYDOXHRIJUHDWHUWKDQZHZRXOG
ZULWH
q = {
"score" : { "$gt" : 0 }
}

1RWLFHWKHXVHRIWKHVSHFLDO£JW¤RSHUDWRU7KH0RQJR'%TXHU\ODQJXDJHSURYLGHV
DQXPEHURIVXFKRSHUDWRUVHQDEOLQJ\RXWREXLOGTXLWHFRPSOH[TXHULHV
6HHWKHVHFWLRQRQ0RQJR'%4XHU\2SHUDWRUVIRUGHWDLOV

Reading, Counting, and Sorting Documents in a Collection


,QPDQ\VLWXDWLRQV\RXRQO\ZDQWWRUHWULHYHDVLQJOHGRFXPHQWIURPDFROOHFWLRQ7KLV
LVHVSHFLDOO\WUXHZKHQGRFXPHQWVLQ\RXUFROOHFWLRQDUHXQLTXHRQVRPHSURSHUW\$
JRRGH[DPSOHRIWKLVLVDXVHUVFROOHFWLRQZKHUHHDFKXVHUQDPHLVJXDUDQWHHGXQLTXH
# Assuming we already have a database handle in scope named dbh
# find a single document with the username "janedoe".
user_doc = dbh.users.find_one({"username" : "janedoe"})
if not user_doc:
print "no document found for username janedoe"

1RWLFHWKDWfind_one()ZLOOUHWXUQNoneLIQRGRFXPHQWLVIRXQG
1RZ LPDJLQH \RX ZLVK WR ILQG DOO GRFXPHQWV LQ WKH XVHUV FROOHFWLRQ ZKLFK KDYH D
ILUVWQDPHSURSHUW\VHWWR£MDQH¤DQGSULQWRXWWKHLUHPDLODGGUHVVHV0RQJR'%ZLOO
UHWXUQD&XUVRUREMHFWIRUXVWRVWUHDPWKHUHVXOWV3\0RQJRKDQGOHVUHVXOWVWUHDPLQJ

Reading, Counting, and Sorting Documents in a Collection | 15

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
DV\RXLWHUDWHVRLI\RXKDYHDKXJHQXPEHURIUHVXOWVWKH\DUHQRWDOOVWRUHGLQPHPRU\
DWRQFH
# Assuming we already have a database handle in scope named dbh
# find all documents with the firstname "jane".
# Then iterate through them and print out the email address.
users = dbh.users.find({"firstname":"jane"})
for user in users:
print user.get("email")

1RWLFHLQWKHDERYHH[DPSOHWKDWZHXVHWKH3\WKRQdictFODVV¦getPHWKRG,IZHZHUH
FHUWDLQWKDWHYHU\VLQJOHUHVXOWGRFXPHQWFRQWDLQHGWKH£HPDLO¤SURSHUW\ZHFRXOG
KDYHXVHGGLFWLRQDU\DFFHVVLQVWHDG
for user in users:
print user["email"]

,I\RXRQO\ZLVKWRUHWULHYHDVXEVHWRIWKHSURSHUWLHVIURPHDFKGRFXPHQWLQDFROOHFWLRQ
GXULQJ D UHDG \RX FDQ SDVV WKRVH DV D GLFWLRQDU\ YLD DQ DGGLWLRQDO SDUDPHWHU )RU
H[DPSOHVXSSRVHWKDW\RXRQO\ZLVKWRUHWULHYHWKHHPDLODGGUHVVIRUHDFKXVHUZLWK
ILUVWQDPH£MDQH¤
# Only retrieve the "email" field from each matching document.
users = dbh.users.find({"firstname":"jane"}, {"email":1})
for user in users:
print user.get("email")

,I\RXDUHUHWULHYLQJDODUJHUHVXOWVHWUHTXHVWLQJRQO\WKHSURSHUWLHV\RXQHHGFDQUHGXFH
QHWZRUNDQGGHFRGLQJRYHUKHDGSRWHQWLDOO\LQFUHDVLQJSHUIRUPDQFH
6RPHWLPHV\RXDUHQRWVRLQWHUHVWHGLQWKHTXHU\UHVXOWVWKHPVHOYHVEXWDUHORRNLQJWR
ILQG WKH VL]H RI WKH UHVXOW VHW IRU D JLYHQ TXHU\ $ FRPPRQ H[DPSOH LV DQ DQDO\WLFV
VLWXDWLRQZKHUH\RXZDQWDFRXQWRIKRZPDQ\GRFXPHQWVDUHLQ\RXUXVHUV¦FROOHFWLRQV
0RQRJ'%VXSSRUWVHIILFLHQWVHUYHUVLGHFRXQWLQJRIUHVXOWVHWVZLWKWKHcount()PHWKRG
RQCursorREMHFWV
# Find out how many documents are in users collection, efficiently
userscount = dbh.users.find().count()
print "There are %d documents in users collection" % userscount

0RQJR'%FDQDOVRSHUIRUPUHVXOWVRUWLQJIRU\RXRQWKHVHUYHUVLGH(VSHFLDOO\LI\RX
DUHVRUWLQJUHVXOWVRQDSURSHUW\ZKLFKKDVDQLQGH[LWFDQVRUWWKHVHIDUPRUHHIILFLHQWO\
WKDQ\RXUFOLHQWSURJUDPFDQ3\0RQJR&XUVRUREMHFWVKDYHD sort()PHWKRGZKLFK
WDNHVD3\WKRQWXSOHFRPSULVLQJWKHSURSHUW\WRVRUWRQDQGWKHGLUHFWLRQ7KH3\
0RQJRsort()PHWKRGLVDQDORJRXVWRWKH64/25'(5%<VWDWHPHQW'LUHFWLRQFDQ
HLWKHUEHpymongo.ASCENDINGRUpymongo.DESCENDING)RUH[DPSOH
# Return all user with firstname "jane" sorted
# in descending order by birthdate (ie youngest first)
users = dbh.users.find(
{"firstname":"jane"}).sort(("dateofbirth", pymongo.DESCENDING))
for user in users:
print user.get("email")

16 | Chapter 2:ಗReading and Writing to MongoDB with Python

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
,QDGGLWLRQWRWKH sort()PHWKRGRQWKH3\0RQJR&XUVRUREMHFW\RXPD\DOVRSDVV
VRUWLQVWUXFWLRQVWRWKH find()DQG find_one()PHWKRGVRQWKH3\0RQJR&ROOHFWLRQ
REMHFW8VLQJWKLVIDFLOLW\WKHDERYHH[DPSOHPD\EHUHZULWWHQDV
# Return all user with firstname "jane" sorted
# in descending order by birthdate (ie youngest first)
users = dbh.users.find({"firstname":"jane"},
sort=[("dateofbirth", pymongo.DESCENDING)])
for user in users:
print user.get("email")

$QRWKHUVLWXDWLRQ\RXPD\HQFRXQWHU¢HVSHFLDOO\ZKHQ\RXKDYHODUJHUHVXOWVHWV¢LV
WKDW\RXZLVKWRRQO\IHWFKDOLPLWHGQXPEHURIUHVXOWV7KLVLVIUHTXHQWO\FRPELQHG
ZLWKVHUYHUVLGHVRUWLQJRIUHVXOWV)RUH[DPSOHLPDJLQH\RXDUHJHQHUDWLQJDKLJKVFRUH
WDEOHZKLFKGLVSOD\VRQO\WKHWRSWHQVFRUHV3\0RQJR&XUVRUREMHFWVKDYHDlimit()
PHWKRGZKLFKHQDEOHVWKLV7KHlimit()PHWKRGLVDQDORJRXVWRWKH64//,0,7VWDWH
PHQW
# Return at most 10 users sorted by score in descending order
# This may be used as a "top 10 users highscore table"
users = dbh.users.find().sort(("score", pymongo.DESCENDING)).limit(10)
for user in users:
print user.get("username"), user.get("score", 0)

,I\RXNQRZLQDGYDQFHWKDW\RXRQO\QHHGDOLPLWHGQXPEHURIUHVXOWVIURPDTXHU\
XVLQJlimit()FDQ\LHOGDSHUIRUPDQFHEHQHILW7KLVLVEHFDXVHLWPD\JUHDWO\UHGXFHWKH
VL]H RI WKH UHVXOWV GDWD ZKLFK PXVW EH VHQW E\ 0RQJR'% 1RWH WKDW D OLPLW RI  LV
HTXLYDOHQWWRQROLPLW
$GGLWLRQDOO\0RQJR'%FDQVXSSRUWVNLSSLQJWRDVSHFLILFRIIVHWLQDUHVXOWVHWWKURXJK
WKHCursor.skip()PHWKRGSURYLGHGE\3\0RQJR:KHQXVHGZLWKlimit()WKLVHQDEOHV
UHVXOWSDJLQDWLRQZKLFKLVIUHTXHQWO\XVHGE\FOLHQWVZKHQDOORZLQJHQGXVHUVWREURZVH
YHU\ODUJHUHVXOWVHWVskip()LVDQDORJRXVWRWKH64/2))6(7VWDWHPHQW)RUH[DPSOH
LPDJLQHD:HEDSSOLFDWLRQZKLFKGLVSOD\VXVHUVSHUSDJHVRUWHGDOSKDEHWLFDOO\E\
VXUQDPHDQGQHHGVWRIHWFKWKHGDWDWREXLOGWKHVHFRQGSDJHRIUHVXOWVIRUDXVHU7KH
TXHU\XVHGE\WKH:HEDSSOLFDWLRQPLJKWORRNOLNHWKLV
# Return at most 20 users sorted by name,
# skipping the first 20 results in the set
users = dbh.users.find().sort(
("surname", pymongo.ASCENDING)).limit(20).skip(20)

)LQDOO\ZKHQWUDYHUVLQJYHU\ODUJHUHVXOWVHWVZKHUHWKHXQGHUO\LQJGRFXPHQWVPD\EH
PRGLILHGE\RWKHUSURJUDPVDWWKHVDPHWLPH\RXPD\ZLVKWRXVH0RQJR'%¦V6QDS
VKRW0RGH,PDJLQHDEXV\VLWHZLWKKXQGUHGVRIWKRXVDQGVRIXVHUV<RXDUHGHYHO
RSLQJ DQ DQDO\WLFV SURJUDP WR FRXQW XVHUV DQG EXLOG YDULRXV VWDWLVWLFV DERXW XVDJH
SDWWHUQVDQGVRRQ+RZHYHUWKLVDQDO\WLFVSURJUDPLVLQWHQGHGWRUXQDJDLQVWWKHOLYH
SURGXFWLRQGDWDEDVH6LQFHWKLVLVVXFKDEXV\VLWHUHDOXVHUVDUHIUHTXHQWO\SHUIRUPLQJ
DFWLRQVRQWKHVLWHZKLFKPD\UHVXOWLQPRGLILFDWLRQVWRWKHLUFRUUHVSRQGLQJXVHUGRFX
PHQWV¢ZKLOH\RXUDQDO\WLFVSURJUDPLVUXQQLQJ'XHWRTXLUNVLQ0RQJR'%¦VFXU

Reading, Counting, and Sorting Documents in a Collection | 17

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
VRULQJPHFKDQLVPLQWKLVNLQGRIVLWXDWLRQ\RXUSURJUDPFRXOGHDVLO\VHHGXSOLFDWHV
LQ\RXUTXHU\UHVXOWVHW'XSOLFDWHGDWDFRXOGWKURZRIIWKHDFFXUDF\RI\RXUDQDO\VLV
SURJUDPDQGVRLWLVEHVWDYRLGHG7KLVLVZKHUH6QDSVKRW0RGHFRPHVLQ
0RQJR'%¦V6QDSVKRW0RGHJXDUDQWHHVWKDWGRFXPHQWVZKLFKDUHPRGLILHGGXULQJWKH
OLIHWLPHRIDTXHU\DUHUHWXUQHGRQO\RQFHLQDUHVXOWVHW,QRWKHUZRUGVGXSOLFDWHVDUH
HOLPLQDWHGDQG\RXVKRXOGQRWKDYHWRZRUU\DERXWWKHP

+RZHYHU6QDSVKRW0RGHGRHVKDYHVRPHOLPLWDWLRQV6QDSVKRW0RGH
FDQQRWEHXVHGZLWKVRUWLQJQRUFDQLWEHXVHGZLWKDQLQGH[RQDQ\
m
UP, SURSHUW\RWKHUWKDQ_id

7RXVH6QDSVKRW0RGHZLWK3\0RQJRVLPSO\SDVV£VQDSVKRW 7UXH¤DVDSDUDPHWHU
WRWKHfind()PHWKRG
# Traverse the entire users collection, employing Snapshot Mode
# to eliminate potential duplicate results.
for user in dbh.users.find(snapshot=True):
print user.get("username"), user.get("score", 0)

Updating Documents in a Collection


8SGDWHTXHULHVLQ0RQJR'%FRQVLVWRIWZRSDUWVDGRFXPHQWVSHFZKLFKLQIRUPVWKH
GDWDEDVHRIWKHVHWRIGRFXPHQWVWREHXSGDWHGDQGWKHXSGDWHGRFXPHQWLWVHOI
7KHILUVWSDUWWKHGRFXPHQWVSHFLVWKHVDPHDVWKHTXHU\GRFXPHQWZKLFK\RXXVH
ZLWKfind()RUfind_one()
7KHVHFRQGSDUWWKHXSGDWHGRFXPHQWFDQEHXVHGLQWZRZD\V7KHVLPSOHVWLVWR
VXSSO\WKHIXOOGRFXPHQWZKLFKZLOOUHSODFHWKHPDWFKHGGRFXPHQWLQWKHFROOHFWLRQ
)RUH[DPSOHVXSSRVH\RXKDGWKHIROORZLQJGRFXPHQWLQ\RXUXVHUVFROOHFWLRQ
user_doc = {
"username" : "janedoe",
"firstname" : "Jane",
"surname" : "Doe",
"dateofbirth" : datetime(1974, 4, 12),
"email" : "[email protected]",
"score" : 0
}

1RZOHW¦VVD\\RXZLVKWRXSGDWHWKHGRFXPHQWZLWKXVHUQDPH£MDQHGRH¤WRFKDQJH
WKHHPDLODGGUHVVWR£MDQHGRH#H[DPSOHFRP¤:HEXLOGDFRPSOHWHO\QHZGRFX
PHQWZKLFKLVLGHQWLFDOWRWKHRULJLQDOH[FHSWIRUWKHQHZHPDLODGGUHVV

18 | Chapter 2:ಗReading and Writing to MongoDB with Python

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
# first query to get a copy of the current document
import copy
old_user_doc = dbh.users.find_one({"username":"janedoe"})
new_user_doc = copy.deepcopy(old_user_doc)
# modify the copy to change the email address
new_user_doc["email"] = "[email protected]"
# run the update query
# replace the matched document with the contents of new_user_doc
dbh.users.update({"username":"janedoe"}, new_user_doc, safe=True)

%XLOGLQJWKHZKROHUHSODFHPHQWGRFXPHQWFDQEHFXPEHUVRPHDQGZRUVHFDQLQWUR
GXFHUDFHFRQGLWLRQV,PDJLQH\RXZDQWWRLQFUHPHQWWKHVFRUHSURSHUW\RIWKH£MDQH
GRH¤XVHU,QRUGHUWRDFKLHYHWKLVZLWKWKHUHSODFHPHQWDSSURDFK\RXZRXOGKDYHWR
ILUVWIHWFKWKHGRFXPHQWPRGLI\LWZLWKWKHLQFUHPHQWHGVFRUHWKHQZULWHLWEDFNWR
WKHGDWDEDVH:LWKWKDWDSSURDFK\RXFRXOGHDVLO\ORVHRWKHUVFRUHFKDQJHVLIVRPH
WKLQJHOVHZHUHWRXSGDWHWKHVFRUHLQEHWZHHQ\RXUHDGLQJDQGZULWLQJLW
,Q RUGHU WR VROYH WKLV SUREOHP WKH XSGDWH GRFXPHQW VXSSRUWV DQ DGGLWLRQDO VHW RI
0RQJR'%RSHUDWRUVFDOOHG£XSGDWHPRGLILHUV¤7KHVHXSGDWHPRGLILHUVLQFOXGHRSHU
DWRUVVXFKDVDWRPLFLQFUHPHQWGHFUHPHQWDWRPLFOLVWSXVKSRSDQGVRRQ,WLVYHU\
KHOSIXOWREHDZDUHRIZKLFKXSGDWHPRGLILHUVDUHDYDLODEOHDQGZKDWWKH\FDQGRZKHQ
GHVLJQLQJ \RXU DSSOLFDWLRQ 0DQ\ RI WKHVH ZLOO EH GHVFULEHG LQ WKHLU RZQ UHFLSHV
WKURXJKRXWWKLVERRN
7RLOOXVWUDWHXVDJHRI£XSGDWHPRGLILHUV¤OHW¦VUHWXUQWRRXURULJLQDOH[DPSOHRIFKDQJ
LQJRQO\WKHHPDLODGGUHVVRIWKHGRFXPHQWZLWKXVHUQDPH£MDQHGRH¤:HFDQXVHWKH
VHWXSGDWHPRGLILHULQRXUXSGDWHGRFXPHQWWRDYRLGKDYLQJWRTXHU\EHIRUHXSGDWLQJ
VHWFKDQJHVWKHYDOXHRIDQLQGLYLGXDOSURSHUW\RUDJURXSRISURSHUWLHVWRZKDWHYHU
\RXVSHFLI\
# run the update query, using the $set update modifier.
# we do not need to know the current contents of the document
# with this approach, and so avoid an initial query and
# potential race condition.
dbh.users.update({"username":"janedoe"},
{"$set":{"email":"[email protected]"}}, safe=True)

<RXFDQDOVRVHWPXOWLSOHSURSHUWLHVDWRQFHXVLQJWKHVHWXSGDWHPRGLILHU
# update the email address and the score at the same time
# using $set in a single write.
dbh.users.update({"username":"janedoe"},
{"$set":{"email":"[email protected]", "score":1}}, safe=True)

0
. . ..4ÿ4
$WWKHWLPHRIZULWLQJWKH3\0RQJRGULYHUHYHQLI\RXVSHFLI\DGRFX
PHQWVSHFWRWKHXSGDWHPHWKRGZKLFKPDWFKHVPXOWLSOHGRFXPHQWVLQ
a,:' DFROOHFWLRQRQO\DSSOLHVWKHXSGDWHWRWKHILUVWGRFXPHQWPDWFKHG

Updating Documents in a Collection | 19

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
,QRWKHUZRUGVHYHQLI\RXEHOLHYH\RXUXSGDWHGRFXPHQWVSHFPDWFKHVHYHU\VLQJOH
GRFXPHQWLQWKHFROOHFWLRQ\RXUXSGDWHZLOORQO\ZULWHWRRQHRIWKRVHGRFXPHQWV
)RUH[DPSOHOHWXVLPDJLQHZHZLVKWRVHWDIODJRQHYHU\GRFXPHQWLQRXUXVHUVFRO
OHFWLRQZKLFKKDVDVFRUHRI
# even if every document in your collection has a score of 0,
# only the first matched document will have its "flagged" property set to True.
dbh.users.update({"score":0},{"$set":{"flagged":True}}, safe=True)

,QRUGHUWRKDYH\RXUXSGDWHTXHU\ZULWHPXOWLSOHGRFXPHQWV\RXPXVW
SDVVWKH£PXOWL 7UXH¤SDUDPHWHUWRWKHXSGDWHPHWKRG
a,:'

# once we supply the "multi=True" parameter, all matched documents


# will be updated
dbh.users.update({"score":0},{"$set":{"flagged":True}}, multi=True, safe=True)

$OWKRXJKWKHGHIDXOWYDOXHIRUWKHPXOWLSDUDPHWHUWRWKHXSGDWHPHWKRG
LVFXUUHQWO\)DOVH¢PHDQLQJRQO\WKHILUVWPDWFKHGGRFXPHQWZLOOEH
XSGDWHG¢WKLV PD\ FKDQJH 7KH 3\0RQJR GRFXPHQWDWLRQ FXUUHQWO\
UHFRPPHQGVWKDW\RXH[SOLFLWO\VHWPXOWL )DOVHLI\RXDUHUHO\LQJRQWKLV
GHIDXOWWRDYRLGEUHDNDJHLQIXWXUH1RWHWKDWWKLVVKRXOGRQO\LPSDFW
\RXLI\RXDUHZRUNLQJZLWKDFROOHFWLRQZKHUH\RXUGRFXPHQWVDUHQRW
XQLTXHRQWKHSURSHUW\\RXDUHTXHU\LQJRQLQ\RXUGRFXPHQWVSHF

Deleting Documents from a Collection


,I\RXZLVKWRSHUPDQHQWO\GHOHWHGRFXPHQWVIURPDFROOHFWLRQLWLVTXLWHHDV\WRGR
VR7KH3\0RQJR&ROOHFWLRQREMHFWKDVDremove()PHWKRG$VZLWKUHDGVDQGXSGDWHV
\RXVSHFLI\ZKLFKGRFXPHQWV\RXZDQWWRUHPRYHE\ZD\RIDGRFXPHQWVSHF)RU
H[DPSOHWRGHOHWHDOOGRFXPHQWVIURPWKHXVHUVFROOHFWLRQZLWKDVFRUHRI\RXZRXOG
XVHWKHIROORZLQJFRGH
# Delete all documents in user collection with score 1
dbh.users.remove({"score":1}, safe=True)

1RWHWKDWWKH remove()PHWKRGWDNHVD safeSDUDPHWHU$VPHQWLRQHGLQWKHHDUOLHU


VHFWLRQ£:ULWHWRD&ROOHFWLRQ6DIHO\DQG6\QFKURQRXVO\¤LWLVUHFRPPHQGHGWRVHWWKH
safeSDUDPHWHUWRTrueRQZULWHPHWKRGVWRHQVXUHWKHRSHUDWLRQKDVFRPSOHWHG,WLV
DOVRZRUWKQRWLQJWKDWremove()ZLOOQRWUDLVHDQ\H[FHSWLRQRUHUURULIQRGRFXPHQWV
DUHPDWFKHG

20 | Chapter 2:ಗReading and Writing to MongoDB with Python

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
)LQDOO\LI\RXZLVKWRGHOHWHDOOGRFXPHQWVLQDFROOHFWLRQ\RXFDQSDVV1RQHDVD
SDUDPHWHUWRremove()
# Delete all documents in user collection
dbh.users.remove(None, safe=True)

&OHDULQJDFROOHFWLRQZLWK remove()GLIIHUVIURPGURSSLQJWKHFROOHFWLRQYLD drop_col


lection()LQWKDWWKHLQGH[HVZLOOUHPDLQLQWDFW

MongoDB Query Operators


$VPHQWLRQHGSUHYLRXVO\0RQJR'%KDVTXLWHDULFKVHWRITXHU\RSHUDWRUVDQGSUHG
LFDWHV,Q7DEOHZHSURYLGHDWDEOHZLWKWKHPHDQLQJRIHDFKRQHDORQJZLWKD
VDPSOHXVDJHDQGWKH64/HTXLYDOHQWZKHUHDSSOLFDEOH
7DEOH0RQJR'%TXHU\RSHUDWRUV
Operator Meaning Example SQL Equivalent
$gt Greater Than “score”:{"$gt”:0} >
$lt Less Than “score”:{"$lt”:0} <
$gte Greater Than or Equal “score”:{"$gte”:0} >=
$lte Less Than or Equal “score”:{"$lte”:0} ම
$all Array Must Contain All “skills”:{"$all”:["mongodb”,"python"]} N/A
$exists Property Must Exist “email”:{"$exists”:True} N/A
$mod Modulo X Equals Y “seconds”:{"$mod”:[60,0]} MOD()
$ne Not Equals “seconds”:{"$ne”:60} !=
$in In “skills”:{"$in”:["c”,"c++"]} IN
$nin Not In “skills”:{"$nin”:["php”,"ruby”,"perl"]} NOT IN
$nor Nor “$nor”:[{"language”:"english"},{"coun- N/A
try”:"usa"}]
$or Or “$or”:[{"language”:"english"},{"coun- OR
try”:"usa"}]
$size Array Must Be Of Size “skills”:{"$size”:3} N/A

,I \RX GR QRW IXOO\ XQGHUVWDQG WKH PHDQLQJ RU SXUSRVH RI VRPH RI WKHVH RSHUDWRUV
LPPHGLDWHO\ GR QRW ZRUU\ :H VKDOO GLVFXVV WKH SUDFWLFDO XVH RI VRPH RI WKH PRUH
DGYDQFHGRSHUDWRUVLQGHWDLOLQ&KDSWHU

MongoDB Query Operators | 21

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
MongoDB Update Modifiers
$VPHQWLRQHGLQWKHVHFWLRQ£8SGDWLQJ'RFXPHQWVLQD&ROOHFWLRQ¤0RQJR'%FRPHV
ZLWKDVHWRIRSHUDWRUVIRUSHUIRUPLQJDWRPLFPRGLILFDWLRQVRQGRFXPHQWV
7DEOH0RQJR'%XSGDWHPRGLILHUV
Modifier Meaning Example
$inc Atomic Increment “$inc”:{"score”:1}
$set Set Property Value “$set”:{"username”:"niall"}
$unset Unset (delete) Property “$unset”:{"username”:1}
$push Atomic Array Append (atom) “$push”:{"emails”:"[email protected]"}
$pushAll Atomic Array Append (list) “$pushall”:{"emails”:["[email protected]”,"foo2@ex-
ample.com"]}
$addToSet Atomic Append-If-Not-Present “$addToSet”:{"emails”:"[email protected]"}
$pop Atomic Array Tail Remove “$pop”:{"emails”:1}
$pull Atomic Conditional Array Item “$pull”:{"emails”:"[email protected]"}
Removal
$pullAll Atomic Array Multi Item Re- “$pullAll”:{"emails”:["[email protected]”, “foo2@ex-
moval ample.com"]}
$rename Atomic Property Rename “$rename”:{"emails”:"old_emails"}

$VZLWKWKH0RQJR'%TXHU\RSHUDWRUVOLVWHGHDUOLHULQWKLVFKDSWHUWKLVWDEOHLVPRVWO\
IRU\RXUUHIHUHQFH7KHVHRSHUDWRUVZLOOEHLQWURGXFHGLQJUHDWHUGHWDLOLQ&KDSWHU

22 | Chapter 2:ಗReading and Writing to MongoDB with Python

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
CHAPTER 3
Common MongoDB and
Python Patterns

$IWHUVRPHWLPHZRUNLQJZLWK0RQJR'%DQG3\WKRQWRVROYHGLIIHUHQWSUREOHPVYDU
LRXVSDWWHUQVDQGEHVWSUDFWLFHVEHJLQWRHPHUJH-XVWDVZLWKDQ\SURJUDPPLQJODQ
JXDJHDQGGDWDEDVHV\VWHPWKHUHDUHHVWDEOLVKHGDSSURDFKHVIRUPRGHOLQJGDWDDORQJ
ZLWKNQRZQPHWKRGVIRUDQVZHULQJTXHULHVDVTXLFNO\DQGHIILFLHQWO\DVSRVVLEOH
:KLOHWKHUHDUHP\ULDGVRXUFHVRIVXFKNQRZOHGJHIRUWUDGLWLRQDO5'%0V\VWHPVOLNH
0\64/WKHUHDUHIDUIHZHUUHVRXUFHVDYDLODEOHIRU0RQJR'%7KLVFKDSWHULVDQDW
WHPSWWRDGGUHVVWKLV

A Uniquely Document-Oriented Pattern: Embedding


:KLOHWKHDELOLW\RI0RQJR'%GRFXPHQWVWRFRQWDLQVXEGRFXPHQWVKDVEHHQPHQ
WLRQHGSUHYLRXVO\LQWKLVERRNLWKDVQRWEHHQH[SORUHGLQGHWDLO,QIDFWHPEHGGLQJLV
DQH[WUHPHO\LPSRUWDQWPRGHOLQJWHFKQLTXHZKHQZRUNLQJZLWK0RQJR'%DQGFDQ
KDYHLPSRUWDQWSHUIRUPDQFHDQGVFDODELOLW\LPSOLFDWLRQV,QSDUWLFXODUHPEHGGLQJFDQ
EHXVHGWRVROYHPDQ\GDWDPRGHOLQJSUREOHPVXVXDOO\VROYHGE\DMRLQLQWUDGLWLRQDO
5'%06)XUWKHUPRUHHPEHGGLQJLVSHUKDSVPRUHLQWXLWLYHDQGHDVLHUWRXQGHUVWDQG
WKDQDMRLQ
:KDWH[DFWO\LVPHDQWE\HPEHGGLQJ",Q3\WKRQWHUPVZKHQWKHYDOXHRIDNH\LQD
GLFWLRQDU\LV\HWDQRWKHUGLFWLRQDU\ZHVD\WKDW\RXDUHHPEHGGLQJWKHODWWHULQWKH
IRUPHU)RUH[DPSOH
my_document = {
"name":"foo document",
"data":{"name":"bar document"}
}

+HUH£GDWD¤LVDVXEGRFXPHQWHPEHGGHGLQWKHWRSOHYHOGRFXPHQW£P\BGRFXPHQW¤

23

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
(PEHGGLQJ VXEGRFXPHQWV FDQ EH D XVHIXO QDWXUDO WHFKQLTXH WR UHGXFH FOXWWHU RU
QDPHVSDFHFROOLVLRQV)RUH[DPSOHFRQVLGHUWKHFDVHZKHUHD£XVHU¤GRFXPHQWVKRXOG
UHIHUHQFH)DFHERRN7ZLWWHUDQG,5&DFFRXQWXVHUQDPHVSDVVZRUGVDQGDVVRFLDWHG
GHWDLOV¢LQDGGLWLRQWRVWRULQJD£XVHUQDPH¤SURSHUW\QDWLYHWR\RXUDSSOLFDWRQ
user_doc = {
"username":"foouser",
"twitter":{
"username":"footwitter",
"password":"secret",
"email":"[email protected]"
},
"facebook":{
"username":"foofacebook",
"password":"secret",
"email":"[email protected]"
},
"irc":{
"username":"fooirc",
"password":"secret",
}
}

1RWHWKDWLQ0RQJR'%GRFXPHQWV¢MXVWDVLQ3\WKRQGLFWLRQDULHV¢
SURSHUW\QDPHV DNDNH\V DUHXQLTXH,QRWKHUZRUGVDVLQJOHGRFX
a,:' PHQWFDQRQO\HYHUKDYHRQH£XVHUQDPH¤SURSHUW\7KLVUXOHDOVRDSSOLHV
WRSURSHUWLHVLQHPEHGGHGVXEGRFXPHQWV7KLVXQLTXHQHVVFRQVWUDLQW
FDQDFWXDOO\EHH[SORLWHGDQGHQDEOHVRPHXVHIXOSDWWHUQV6SHFLILFDOO\
VHHWKHVHFWLRQWLWOHG£)DVW$FFRXQWLQJ3DWWHUQ¤

2IFRXUVHHPEHGGHGVXEGRFXPHQWVFDQEHTXHULHGDJDLQVWMXVWOLNHWKHLUWRSOHYHO
FRXQWHUSDUWV)RUH[DPSOHLWZRXOGEHFRPSOHWHO\OHJDOWRDWWHPSWWRTXHU\IRUWKH
DERYHGRFXPHQWLQDFROOHFWLRQFDOOHG£XVHUV¤ZLWKWKHIROORZLQJVWDWHPHQW
user_doc = dbh.users.find_one({"facebook.username":"foofacebook"})

$V\RXFDQVHHWKHGRW £¤ LVXVHGWRGHQRWHNH\VLQDQHPEHGGHGVXEGRFXPHQW


7KLVVKRXOGEHIDPLOLDUWRDQ\ERG\ZKRKDVZRUNHGZLWKREMHFWVLQ-DYD6FULSWZKHUH
REMHFWVW\OHDFFHVVYLDWKHGRWQRWDWLRQFDQEHXVHGLQSDUDOOHOZLWKGLFWLRQDU\VW\OH
DFFHVVYLDVTXDUHEUDFNHWV$V0RQJR'%XVHV-DYD6FULSWKHDYLO\LQWHUQDOO\WKLVFKRLFH
RIQRWDWLRQLVXQVXUSULVLQJ-621LV-DYD6FULSW2EMHFW1RWDWLRQDIWHUDOO7KHGRWQR
WDWLRQFDQDOVREHXVHGLQXSGDWHVWDWHPHQWVZLWKXSGDWHPRGLILHUVVXFKDV$setWRVHW
WKHYDOXHRIDQLQGLYLGXDOVXESURSHUW\
# update modifiers such as $set also support the dot notation
dbh.users.update({"facebook.username":"foofacebook"},
{"$set":{"facebook.username":"bar"}}, safe=True)

7KLVXVHRIHPEHGGHGVXEGRFXPHQWVLVXVHIXOEXWSHUKDSVHYHQPRUHXVHIXOLVWR
HPEHGPXOWLSOHVXEGRFXPHQWVXQGHUDVLQJOHNH\,QRWKHUZRUGVDSURSHUW\ZKRVH

24 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
YDOXHLVDOLVWRUDUUD\RIVXEGRFXPHQWV,Q0RQJR'%WKLVLVDOHJDODQGYHU\XVHIXO
FRQVWUXFW7KLVLVDYHU\QDWXUDOZD\WRPRGHORQHWRPDQ\UHODWLRQVKLSVRUSDUHQW
FKLOGUHODWLRQVKLSV&RQVLGHUWKHH[DPSOHRID£XVHU¤GRFXPHQWZKLFKFDQUHIHUHQFH
PXOWLSOHHPDLODGGUHVVHVIRUWKDWXVHU,QWKHUHODWLRQDOPRGHOWKLVZRXOGW\SLFDOO\EH
DFKLHYHGZLWKWZRWDEOHV¢RQHIRUXVHUVDQGRQHIRUWKHHPDLODGGUHVVHVDVVRFLDWHG
ZLWKHDFKXVHU$MRLQTXHU\FRXOGWKHQEHXVHGWRUHWULHYHDXVHUDORQJZKLFKHDFKRI
LWVHPDLODGGUHVVHV
,Q0RQJR'%DQDWXUDODSSURDFKWRPRGHODRQHWRPDQ\UHODWLRQVKLSZRXOGEHWR
VLPSO\KDYHDSURSHUW\£HPDLOV¤RQWKHXVHUGRFXPHQWWKHYDOXHRIZKLFKLVDQDUUD\
FRQWDLQLQJVXEGRFXPHQWVHDFKUHSUHVHQWLQJDQDVVRFLDWHGHPDLODFFRXQW)RUH[DP
SOH
# A user document demonstrating one-to-many relationships using embedding
# Here we map multiple email addresses (along with whether or not the email
# is the user's primary email address) to a single user.
user_doc = {
"username":"foouser",
"emails":[
{
"email":"[email protected]",
"primary":True
},
{
"email":"[email protected]",
"primary":False
},
{
"email":"[email protected]",
"primary":False
}
]
}

1RWRQO\GRHVWKLVZRUNEXW0RQJR'%KDVVRPHVSHFLILFIHDWXUHVWRKHOSZRUNLQJ
ZLWKWKLVW\SHRIHPEHGGHGVWUXFWXUH-XVWDV\RXFDQTXHU\IRUGRFXPHQWVE\WKHYDOXH
RIVXEGRFXPHQWVGLUHFWO\HPEHGGHGLQWKHWRSOHYHOGRFXPHQWGRFXPHQWVFDQDOVR
EHORFDWHGE\WKHYDOXHRIVXEGRFXPHQWVHPEHGGHGLQDUUD\V7RGRWKLVVLPSO\XVH
WKHVDPHGRW £¤ QRWDWLRQDVGHVFULEHGHDUOLHULQWKLVVHFWLRQ0RQJR'%WUDQVSDUHQWO\
VHDUFKHVWKURXJKDUUD\VIRUVXEGRFXPHQWV
5HWXUQLQJWRRXUHDUOLHUH[DPSOHRIDVLQJOHXVHUZLWKPXOWLSOHHPDLODGGUHVVHVFRQVLGHU
WKHIROORZLQJFRGH
# A user document demonstrating one-to-many relationships using embedding
user_doc = {
"username":"foouser",
"emails":[
{
"email":"[email protected]",
"primary":True
},

A Uniquely Document-Oriented Pattern: Embedding | 25

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
{
"email":"[email protected]",
"primary":False
},
{
"email":"[email protected]",
"primary":False
}
]
}
# Insert the user document
dbh.users.insert(user_doc, safe=True)
# Retrieve the just-inserted document via one of its many email addresses
user_doc_result = dbh.users.find_one({"emails.email":"[email protected]"})
# Assert that the original user document and the query result are the same
assert user_doc == user_doc_result

,QDGGLWLRQWR0RQJR'%XQGHUVWDQGLQJOLVWVRIVXEGRFXPHQWVWRHQDEOHTXHU\LQJIRU
HPEHGGHGYDOXHVYLDWKHGRWQRWDWLRQWKHUHDUHDOVRXVHIXOXSGDWHPRGLILHUV $pull
$pushDQGWKHLUYDULDQWVDUHWKHPRVWKHOSIXOHQDEOLQJDWRPLFDSSHQGDQGUHPRYDORI
VXEGRFXPHQWVWRDQGIURPHPEHGGHGOLVWV&RQVLGHUWKHFDVHZKHUHDXVHUQRORQJHU
ZLVKHVDSDUWLFXODUHPDLODGGUHVVWREHOLQNHGWRKLVRUKHUDFFRXQW7KHQDLYHZD\WR
UHPRYHWKDWHPDLODGGUHVVIURPWKHLUXVHUGRFXPHQWZRXOGEHWRILUVWTXHU\IRUWKHLU
XVHUGRFXPHQWPRGLI\LWLQ\RXUDSSOLFDWLRQFRGHVRLWQRORQJHUFRQWDLQVWKHUHPRYHG
HPDLODGGUHVVDQGWKHQVHQGDQXSGDWHTXHU\WRWKHGDWDEDVH1RWRQO\LVWKLVFXP
EHUVRPHLWDOVRLQWURGXFHVDUDFHFRQGLWLRQDVWKHXQGHUO\LQJXVHUGRFXPHQWPD\KDYH
EHHQPRGLILHGE\DQRWKHUSURFHVVLQEHWZHHQ\RXUUHDGDQGZULWH
# Naive method to remove an email address from a user document
# Cumbersome and has a race condition
user_doc = {
"username":"foouser",
"emails":[
{
"email":"[email protected]",
"primary":True
},
{
"email":"[email protected]",
"primary":False
},
{
"email":"[email protected]",
"primary":False
}
]
}
# Insert the user document
dbh.users.insert(user_doc, safe=True)
# Retrieve the just-inserted document via username
user_doc_result = dbh.users.find_one({"username":"foouser"})
# Remove the "[email protected]" email address sub-document from the embedded list
del user_doc_result["emails"][1]

26 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
# Now write the new emails property to the database
# May cause data to be lost due to the race between read and write
dbh.users.update({"username":"foouser"},{"$set":{"emails":user_doc_result}},
safe=True)

7KHWKUHHPRVWFRPPRQRSHUDWLRQVRQVXEGRFXPHQWVHPEHGGHGLQDOLVWSURSHUW\
DUH'HOHWLRQLQVHUWLRQDQGPRGLILFDWLRQ(DFKRIWKHVHFDQEHSHUIRUPHGDWRPLFDOO\
ZLWKWKHSURYLGHGXSGDWHPRGLILHUV)LUVWOHW¦VGHPRQVWUDWHWKHXVHRI$pullWRUHPRYH
WKHVXEGRFXPHQWPDWFKLQJ£IRRXVHU#H[DPSOHFRP¤LQDVLPSOHDQGUDFHIUHHZD\
# Atomically remove an email address from a user document race-free using the
# $pull update modifier
user_doc = {
"username":"foouser",
"emails":[
{
"email":"[email protected]",
"primary":True
},
{
"email":"[email protected]",
"primary":False
},
{
"email":"[email protected]",
"primary":False
}
]
}
# Insert the user document
dbh.users.insert(user_doc, safe=True)
# Use $pull to atomically remove the "[email protected]" email sub-document
dbh.users.update({"username":"foouser"},
{"$pull":{"emails":{"email":"[email protected]"}}}, safe=True)

,Q WKLV H[DPSOH $pull LV XVHG WR PDWFK DQ HPEHGGHG GRFXPHQW ZLWK
"email":"[email protected]"LQWKH£HPDLOV¤ILHOG $pullZLOOUHPRYHWKHHQWLUH
GRFXPHQWIURPWKHDUUD\LQDQDWRPLFIDVKLRQPHDQLQJWKHUHLVQRRSSRUWXQLW\IRUD
UDFHFRQGLWLRQ<RXFDQDOVRXVHTXHU\PRGLILHUVZLWK$pullIRUH[DPSOHWRUHPRYHDOO
VXEGRFXPHQWVZLWKD£SULPDU\¤YDOXHWKDWLVQRWHTXDOWR7UXH\RXFRXOGZULWHWKH
IROORZLQJ
# Use $pull to atomically remove all email sub-documents with primary not equal to True
dbh.users.update({"username":"foouser"},
{"$pull":{"emails":{"primary":{"$ne":True}}}, safe=True)

7KHIXOOUDQJHRITXHU\PRGLILHUV VHHWDEOHLQ&KDSWHU DUHDYDLODEOHIRUXVHLQFOXGLQJ


JWOWDQGVRRQ$GGLWLRQDOO\$pullFDQEHXVHGZLWKDUUD\VFRQWDLQLQJDWRPV QXP
EHUVVWULQJVGDWHV2EMHFW,'VHWF ,QRWKHUZRUGV$pullGRHVQ¦WZRUNRQO\ZLWKHP
EHGGHGGRFXPHQWV¢LI\RXVWRUHDOLVWRISULPLWLYHW\SHVLQDQDUUD\\RXFDQUHPRYH
HOHPHQWVDWRPLFDOO\ZLWK$pullWRR

A Uniquely Document-Oriented Pattern: Embedding | 27

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
7KH$pushXSGDWHPRGLILHULVXVHGWRDWRPLFDOO\DSSHQGDQHOHPHQWWRDQDUUD\$WWKH
WLPHRIZULWLQJ$pushFDQRQO\VXSSRUWDGGLQJLWHPVWRWKHHQGRIWKHDUUD\¢WKHUHLV
QRXSGDWHPRGLILHUWRDGGDQHOHPHQWWRWKHEHJLQQLQJRIDQDUUD\RUWRLQVHUWLWDWDQ
DUELWUDU\LQGH[$pushLVVLPSOHWRXVHEHFDXVHXQOLNH$pullLWGRHVQRWWDNHDQ\ILHOG
PDWFKRUFRQGLWLRQDODUJXPHQWV
)RUH[DPSOHWRDWRPLFDOO\DGGDQHZHPDLODGGUHVVWRRXUXVHUGRFXPHQWZHFRXOG
XVHWKHIROORZLQJTXHU\
# Use $push to atomically append a new email sub-document to the user document
new_email = {"email":"[email protected]", "primary":False}
dbh.users.update({"username":"foouser"},
{"$push":{"emails":new_email}}, safe=True)

7KHILQDOFDVHLVXSGDWLQJDQH[LVWLQJVXEGRFXPHQWLQSODFH7KLVFDQEHDFKLHYHG
XVLQJZKDWLVFDOOHGWKH£SRVLWLRQDO¤RSHUDWRU7KHSRVLWLRQDORSHUDWRULVUHSUHVHQWHG
E\WKHGROODUVLJQ £¤ %DVLFDOO\LWLVUHSODFHGE\WKHVHUYHUZLWKWKHLQGH[RIWKHLWHP
PDWFKHGE\WKHGRFXPHQWVSHF)RUH[DPSOHVXSSRVHZHZLVKWRPDNHRXUXVHUGRFX
PHQW¦V£IRRXVHU#H[DPSOHFRP¤HPDLODGGUHVVSULPDU\:HFRXOGLVVXHWKHIROORZ
LQJXSGDWHTXHU\WRPRGLI\LWLQSODFH
# Demonstrate usage of the positional operator ($) to modify
# matched sub-documents in-place.
user_doc = {
"username":"foouser",
"emails":[
{
"email":"[email protected]",
"primary":True
},
{
"email":"[email protected]",
"primary":False
},
{
"email":"[email protected]",
"primary":False
}
]
}
# Insert the user document
dbh.users.insert(user_doc, safe=True)
# Now make the "[email protected]" email address primrary
dbh.users.update({"emails.email":"[email protected]"},
{"$set":{"emails.$.primary":True}}, safe=True)
# Now make the "[email protected]" email address not primary
dbh.users.update({"emails.email":"[email protected]"},
{"$set":{"emails.$.primary":False}}, safe=True)

1RWHWKDWWKH $RSHUDWRUFDQQRWEHXVHGZLWKXSVHUWV VHHVHFWLRQRQ


m
XSVHUWV ODWHU LQ WKLV FKDSWHU  DGGLWLRQDOO\LWRQO\ZRUNVZLWKWKHILUVW
UP, PDWFKHGHOHPHQW

28 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
:KHQZRUNLQJZLWKHPEHGGLQJLWLVLPSRUWDQWWREHDZDUHRIWKHSHUIRUPDQFHFKDU
DFWHULVWLFVRIGRFXPHQWVDQGVXEGRFXPHQWVLQ0RQJR'%)LUVWDQGIRUHPRVWZKHQ
DGRFXPHQWLVIHWFKHGIURPWKHGDWDEDVHWRDQVZHUDTXHU\WKHHQWLUHGRFXPHQW¢
LQFOXGLQJDQ\DQGDOOHPEHGGHGVXEGRFXPHQWV¢LVORDGHGLQWRPHPRU\7KLVPHDQV
WKDWWKHUHLVQRH[WUDFRVW DVLGHIURPWKHDGGLWLRQDOQHWZRUNDQGGHFRGHHQFRGH&38
RYHUKHDGLQFXUUHGE\DODUJHUUHVXOWVHW WRIHWFKHPEHGGHGGDWD2QFHWKHWRSOHYHO
GRFXPHQWKDVEHHQUHWULHYHGLWVVXEGRFXPHQWVDUHLPPHGLDWHO\DYDLDOEOHWRR&RQ
WUDVWWKLVZLWKDUHODWLRQDOVFKHPDGHVLJQXWLOL]LQJMRLQVZKHUHWKHGDWDEDVHPD\QHHG
WRUHDGIURPRQHRUPRUHDGGLWLRQDOWDEOHVWRIHWFKDVVRFLDWHGGDWD'HSHQGLQJRQWKH
VLWXDWLRQWKHVHMRLQVFRXOGLPSDFWTXHU\SHUIRUPDQFHFRQVLGHUDEO\
6HFRQGO\LWLVDOVRYHU\LPSRUWDQWWREHDZDUHWKDWWKHUHLVDVL]HOLPLWRQGRFXPHQWV
LQ0RQJR'%$GGLWLRQDOO\WKHGRFXPHQWVL]HOLPLWKDVEHHQLQFUHDVHGRYHUVXFFHVVLYH
PDMRU0RQJR'%UHOHDVHV,Q0RQJR'%[DQG[WKHPD[LPXPGRFXPHQWVL]H
ZDV0%EXWLQ[LWZDVLQFUHDVHGWR0%2QHFDQH[SHFWWKDWWKLVOLPLWPD\
FRQWLQXHWRLQFUHDVH¢SHUKDSVHYHQWXDOO\WREHDUELWUDULO\ODUJH¢EXWIRUQRZNHHSLQ
PLQGWKDWGRFXPHQWVKDYHDILQLWHVL]HZKHQPRGHOLQJ\RXUGDWD
,QSUDFWLFHLWLVUDUHWRUHDFKHYHQD0%GRFXPHQWVL]HXQOHVVWKHGHVLJQLVVXFKWKDW
GRFXPHQWVFRQWLQXHWRJURZRYHUWLPH)RUH[DPSOHDVFHQDULRZKHUHQHZSURSHUWLHV
DUHFUHDWHGRQDQKRXUO\RUGDLO\EDVLV,QVXFKFDVHVLWLVZLVHWRHQVXUHWKHUHLVVRPH
DSSOLFDWLRQORJLFWRKDQGOHSXUJLQJROGH[SLUHGHPEHGGHGVXEGRFXPHQWVWRSUHYHQW
WKHOLPLWEHLQJKLW
$QRWKHUH[DPSOHZRXOGEHEXLOGLQJDGRFXPHQWSXEOLVKLQJSODWIRUPZKLFKHPEHGGHG
HYHU\VLQJOHGRFXPHQWSRVWHGE\DXVHUDVDVXEGRFXPHQWLQVLGHRIWKHXVHUGRFXPHQW
:KLOHSHUIRUPDQFHZRXOGEHH[FHOOHQWVLQFHDVLQJOHTXHU\IRUWKHXVHUGRFXPHQWFRXOG
UHWLHYHDOOWKHLUSXEOLVKHGGRFXPHQWVLQDVLQJOHVKRWLWLVTXLWHOLNHO\WKDWVRPHXVHUV
ZRXOGHYHQWXDOO\SXEOLVKPRUHWKDQ0%RIFRQWHQW
+HQFHWKHUHLVRIWHQDMXGJHPHQWFDOOWREHPDGHZKHQGHVLJQLQJ0RQJR'%VFKHPDV
7RHPEHGRUQRWWRHPEHG
7KHDOWHUQDWLYHWRHPEHGGLQJLVVWRULQJWKHGRFXPHQWVLQDVHSDUDWHFROOHFWLRQDQG
SHUIRUPLQJDMRLQLQ\RXURZQDSSOLFDWLRQFRGHE\TXHU\LQJWZLFHRUPRUH8VXDOO\
PDQ\WRPDQ\UHODWLRQVKLSVDUHPRGHOHGLQWKLVZD\ZKLOHRQHWRPDQ\UHODWLRQVKLSV
DUHHPEHGGHG

Fast Lookups: Using Indexes with MongoDB


7KHUROHRILQGH[HVLQ0RQJR'%LVYHU\VLPLODUWRWKHLUUROHLQWUDGLWLRQDO5'%06VXFK
DV0\64/3RVWJUH64/HWF0RQJR'%RIIHUVWZRNLQGVRILQGH[HVRXWRIWKHER[
%WUHHLQGH[HVDQGJHRVSDWLDOLQGH[HV7KHEWUHHLQGH[HVLQ0RQJR'%DUHPXFKWKH
VDPHDVWKHHTXLYDOHQWVLQ0\64/RU3RVWJUH64/:KHQLQDUHODWLRQDOV\VWHP\RX
ZRXOGSXWDQLQGH[RQDFROXPQWRJHWIDVWORRNXSVRQWKDWILHOG\RXGRDQDQDORJRXV
WKLQJLQ0RQJR'%E\SODFLQJDQLQGH[RQDSDUWLFXODUSURSHUW\LQDFROOHFWLRQ-XVWDV

Fast Lookups: Using Indexes with MongoDB | 29

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
ZLWKDQ5'%060RQJR'%LQGH[HVFDQVSDQPXOWLSOHILHOGV DNDFRPSRXQGLQGH[HV
¢XVHIXOLI\RXNQRZLQDGYDQFHWKDW\RXZLOOEHTXHU\LQJEDVHGRQWKHYDOXHRIPRUH
WKDQDVLQJOHSURSHUW\$FRPSRXQGLQGH[ZRXOGEHXVHIXOIRUH[DPSOHLI\RXZHUH
TXHU\LQJGRFXPHQWVE\ILUVWQDPHDQGODVWQDPH,Q0RQJR'%EWUHHLQGH[HVFDQKDYH
D£GLUHFWLRQ¤7KLVGLUHFWLRQLVRQO\XVHIXOLQWKHFDVHRIFRPSRXQGLQGH[HVZKHUHWKH
LQGH[GLUHFWLRQVKRXOGPDWFKWKHVRUWGLUHFWLRQRUUDQJHTXHU\GLUHFWLRQIRURSWLPDO
SHUIRUPDQFH)RUH[DPSOHLI\RXDUHTXHU\LQJDUDQJH VD\$WKURXJK& RQILUVWQDPH
DQGODVWQDPHDQGWKHQVRUWLQJLQDVFHQGLQJRUGHURQODVWQDPH\RXUFRPSRXQGLQGH[
GLUHFWLRQVKRXOGDOVREHDVFHQGLQJ
8VLQJDEWUHHLQGH[ZLOOLQFXUDSHUIRUPDQFHKLWRQZULWHVDVWKHGDWDEDVHPXVWQRZ
XSGDWHWKHLQGH[LQDGGLWLRQWRWKHGDWD)RUWKLVUHDVRQLWLVZLVHWRFKRRVH\RXULQGH[HV
FDUHIXOO\$YRLGVXSHUIOXRXVLQGH[HVLIDWDOOSRVVLEOH,QGH[HVDOVRWDNHXSYDOXDEOH
VWRUDJH¢QRWVRPXFKRIDQLVVXHZLWKRQGLVNVSDFHWRGD\JLYHQWKHORZSULFHSHU
WHUUDE\WH¢EXWLQPHPRU\WRR<RXUGDWDEDVHZLOOUXQIDVWHVWZKHQLWUHVLGHVHQWLUHO\
LQPHPRU\DQGLQGH[HVFDQFRQVLGHUDEO\DGGWRLWVVL]H,WLVDFODVVLF&RPSXWHU6FLHQFH
WLPHYVVSDFHWUDGHRIIVFHQDULR
0RQJR'%EWUHHLQGH[HVFDQDOVREHXVHGWRHQIRUFHDXQLTXHFRQVWUDLQWRQDSDUWLFXODU
SURSHUW\LQDFROOHFWLRQ%\GHIDXOWWKH _idSULPDU\NH\SURSHUW\KDVDXQLTXHLQGH[
FUHDWHGLQ0RQJR'%7KHXQLTXHFRQVWUDLQWZLOOSUHYHQWWKHSURWHFWHGSURSHUW\IURP
HYHUKDYLQJDGXSOLFDWHYDOXHZLWKLQWKHFROOHFWLRQ7KLVFDQEHXVHIXOIRUYDOXHVZKLFK
DUHH[SHFWHGWREHJOREDOO\XQLTXHLQWKHFROOHFWLRQ¢DFRPPRQH[DPSOHEHLQJXVHU
QDPHV%HZDUHRIRYHUUHOLDQFHRQWKLVIHDWXUHKRZHYHUDVLQWKHFXUUHQWLPSOHPHQ
WDWLRQRIVKDUGLQJXQLTXHLQGH[HVDUHVXSSRUWHGRQO\RQWKH_idSURSHUW\¢RWKHUZLVH
WKH\DUHQRWHQIRUFHGJOREDOO\DFURVVWKHFOXVWHU
%WUHHLQGH[HVDOVRWUDQVSDUHQWO\VXSSRUWLQGH[LQJPXOWLYDOXHSURSHUWLHVWKDWLVSURS
HUWLHVZKHUHWKHYDOXHLVDQDUUD\(DFKLWHPLQWKHDUUD\ZLOOEHSURSHUO\VWRUHGLQWKH
LQGH[WRHQDEOHIDVWUHWULHYDORIWKHSDUHQWGRFXPHQW7KLVFDQEHXVHIXOIRUSHUIRUPDQW
LPSOHPHQWDWLRQV RI WDJJLQJ ZKHUH HDFK WDJ LV VWRUHG DV D VWULQJ LQVLGH D £WDJV¤ OLVW
SURSHUW\RQWKHGRFXPHQW/RRNXSVIRUGRFXPHQWVPDWFKLQJRQHRUPRUHRIWKRVHWDJV
SRWHQWLDOO\XVLQJWKH$inTXHU\RSHUDWRU ZLOOWKHQEHORRNHGXSLQWKH£WDJV¤LQGH[
)XUWKHUPRUHEWUHHLQGH[HVDUHHTXDOO\ZHOOVXSSRUWHGZKHQSODFHGRQHPEHGGHGVXE
GRFXPHQWV,IIRUH[DPSOH\RXVWRUHHPDLODGGUHVVHVDVHPEHGGHGVXEGRFXPHQWV
DQG\RXZLVKWREHDEOHWRORRNXSE\WKHYDOXHRIWKHHPDLODGGUHVVXVLQJDQLQGH[
0RQJR'%DOORZVWKLV+HQFHWKHIROORZLQJGRFXPHQWDQGTXHU\FRXOGWDNHDGYDQWDJH
RIDQLQGH[
user_doc = {
"username":"foouser",
"emails":[
{
"email":"[email protected]",
"primary":True
},
{
"email":"[email protected]",

30 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
"primary":False
},
{
"email":"[email protected]",
"primary":False
}
]
}

dbh.users.insert(user_doc)
# If we place an index on property "emails.email",
# e.g. dbh.users.create_index("emails.email")
# this find_one query can use a btree index
user = dbh.users.find_one({"emails.email":"[email protected]"})

%WUHHLQGH[HVLQ0RQJR'%DUHDOVRLPSRUWDQWZKHQSHUIRUPLQJVHUYHUVLGHVRUWLQJRI
UHVXOWV:LWKRXWDQLQGH[RQWKHSURSHUW\\RXDUHVRUWLQJE\0RQJR'%ZLOOUXQRXW
RIPHPRU\ZKHQWU\LQJWRVRUWDQ\WKLQJJUHDWHUWKDQDUHODWLYHO\VPDOOUHVXOWVVHW DS
SUR[0EDWWLPHRIZULWLQJ ,I\RXH[SHFWWKDW\RXZLOOEHVRUWLQJUHVXOWVHWVODUJHU
WKDQ0E\RXVKRXOGVSHFLI\DQLQGH[RQWKHVRUWNH\,WLVHDV\WRXQGHUHVWLPDWHWKLV
DQGILQGH[FHSWLRQVDUHEHLQJUDLVHGRQTXHULHVDJDLQVWODUJHUUHDOZRUOGGDWDZKLFK
ZHUHQRWDQWLFLSDWHGGXULQJGHYHORSPHQW
7R FUHDWH DQ LQGH[ ZLWK WKH 3\0RQJR GULYHU XVH WKH Collection.create_index()
PHWKRG7KLVPHWKRGFDQFUHDWHVLQJOHNH\LQGH[HVRUFRPSRXQGLQGH[HV)RUDVLQJOH
NH\LQGH[RQO\WKHNH\QHHGVWREHSURYLGHG$FRPSRXQGLQGH[LVVOLJKWO\PRUHFRP
SOLFDWHG¢DOLVWRIWXSOHV NH\GLUHFWLRQ PXVWEHVXSSOLHG
)RUH[DPSOHWRFUHDWHDQLQGH[RQWKH usernameSURSHUW\RIDFROOHFWLRQFDOOHG users
\RXFRXOGZULWHWKHIROORZLQJ
# Create index on username property
dbh.users.create_index("username")

7RFUHDWHDFRPSRXQGLQGH[IRUH[DPSOHRQWKHILUVWBQDPHDQGODVWBQDPHZLWKDQ
DVFHQGLQJGLUHFWLRQ\RXFRXOGVSHFLI\
# Create a compound index on first_name and last_name properties
# with ascending index direction
dbh.users.create_index([("first_name", pymongo.ASCENDING), ("last_name",
pymongo.ASCENDING)])

,QGH[HVLQ0RQJR'%HDFKKDYHQDPHV%\GHIDXOW0RQJR'%ZLOOJHQHUDWHDQDPH
EXW\RXPD\ZLVKWRJLYHDFXVWRPQDPH¢SDUWLFXODUO\IRUFRPSRXQGLQGH[HVZKHUH
WKHJHQHUDWHGQDPHVDUHQRWHVSHFLDOO\UHDGDEOHE\KXPDQV7RJLYHDFXVWRPQDPH
GXULQJFUHDWLRQVXSSO\WKHname=<str>SDUDPHWHUWRWKHcreate_index()PHWKRG
# Create a compound index called "name_idx" on first_name and last_name properties
# with ascending index direction
dbh.users.create_index([
("first_name", pymongo.ASCENDING),
("last_name", pymongo.ASCENDING)
],
name="name_idx")

Fast Lookups: Using Indexes with MongoDB | 31

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
,WVKRXOGEHQRWHGWKDWLQGH[FUHDWLRQORFNVWKHGDWDEDVHE\GHIDXOW)RUODUJHFROOHF
WLRQV LQGH[ FUHDWLRQ FDQ EH WLPH FRQVXPLQJ 7R KHOS PLWLJDWH WKH LPSDFW RI WKHVH
RSHUDWLRQVRQOLYHSURGXFWLRQGDWDEDVHV0RQJR'%LVFDSDEOHRIEXLOGLQJLQGH[HVLQ
WKH EDFNJURXQG ZLWKRXW EORFNLQJ GDWDEDVH DFFHVV %XLOGLQJ DQ LQGH[ LQ WKH EDFN
JURXQGPD\WDNHVOLJKWO\ORQJHUDQGZLOOVWLOOFDXVHDGGLWLRQDOORDGRQWKHV\VWHPEXW
WKHGDWDEDVHVKRXOGRWKHUZLVHUHPDLQDYDLODEOH
7RVSHFLI\WKDWDQLQGH[VKRXOGEHEXLOWLQWKHEDFNJURXQGSDVVWKHbackground=True
SDUDPHWHUWRWKHcreate_index()PHWKRG
# Create index in the background
# Database remains usable
dbh.users.create_index("username", background=True)

$VPHQWLRQHGHDUOLHULQWKLVVHFWLRQ0RQJR'%EWUHHLQGH[HVFDQEHXVHGWRHQIRUFHD
XQLTXHQHVVFRQVWUDLQWRQDSDUWLFXODUSURSHUW\8QLTXHFRQVWUDLQWVFDQEHDSSOLHGWR
ERWK VLQJOHNH\ LQGH[HV DQG FRPSRXQG LQGH[HV 7R FUHDWH DQ LQGH[ ZLWK D XQLTXH
FRQVWUDLQWVLPSO\SDVVWKHunique=TrueSDUDPHWHUWRWKHcreate_index()PHWKRG
# Create index with unique constraint on username property
dbh.users.create_index("username", unique=True)

%HDZDUHWKDWXQLTXHLQGH[HVLQ0RQJR'%GRQRWIXQFWLRQH[DFWO\WKHVDPHDVLQGH[HV
LQ5'%06V\VWHPV,QSDUWLFXODUDGRFXPHQWZLWKDPLVVLQJSURSHUW\ZLOOEHDGGHG
WRWKHLQGH[DVLILWWKHYDOXHRIWKDWSURSHUW\ZHUHQXOO7KLVPHDQVWKDWZKHQDXQLTXH
FRQVWUDLQWLVDGGHGWRDEWUHHLQGH[LQ0RQJR'%WKHGDWDEDVHZLOOSUHYHQW\RXIURP
KDYLQJPXOWLSOHGRFXPHQWVLQWKHFROOHFWLRQZKLFKDUHPLVVLQJWKHLQGH[HGSURSHUW\
)RUH[DPSOHLI\RXKDYHFUHDWHGDXQLTXHLQGH[IRUWKH usernameSURSHUW\LQDXVHUV
FROOHFWLRQRQO\RQHGRFXPHQWLQWKDWFROOHFWLRQPD\EHSHUPLWWHGWRODFND username
SURSHUW\:ULWHVRIDGGLWLRQDOGRFXPHQWVZLWKRXWD usernameSURSHUW\ZLOOUDLVHDQ
H[FHSWLRQ ,I \RX WU\ WR DGG D XQLTXH LQGH[ WR D FROOHFWLRQ ZKLFK DOUHDG\ FRQWDLQV
GXSOLFDWHVRQWKHVSHFLILHGSURSHUW\0RQJR'%ZLOO XQVXUSULVLQJO\ UDLVHDQH[FHSWLRQ
+RZHYHULI\RXGRQ¦WPLQGWKURZLQJDZD\GXSOLFDWHGDWD\RXFDQLQVWUXFW0RQJR'%
WRGURSDOOEXWWKHILUVWGRFXPHQWLWILQGVXVLQJWKHdropDupsRUdrop_dupsSDUDPHWHU
# Create index with unique constraint on username property
# instructing MongoDB to drop all duplicates after the first document it finds.
dbh.users.create_index("username", unique=True, drop_dups=True)
# Could equally be written:
# dbh.users.create_index("username", unique=True, dropDups=True)

2YHUWLPH\RXUVFKHPDPD\HYROYHDQG\RXPD\ILQGWKDWDSDUWLFXODULQGH[LVQR
ORQJHU QHHGHG )RUWXQDWHO\ LQGH[HV DUH HDV\ WR UHPRYH LQ 0RQJR'% 7KH Collec
tion.drop_index()PHWKRGGHOHWHVRQHLQGH[DWDWLPH,I\RXFUHDWHG\RXULQGH[ZLWK
D FXVWRP QDPH DV GHVFULEHG DERYH  \RX PXVW VXSSO\ WKLV VDPH QDPH WR WKH
drop_index()PHWKRGLQRUGHUWRGHOHWHLW)RUH[DPSOH
# Create index on username property called "username_idx"
dbh.users.create_index("username", name="username_idx")
# Delete index called "username_idx"
dbh.users.drop_index("username_idx")

32 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
,IRQWKHRWKHUKDQG\RXGLGQRWJLYH\RXULQGH[DFXVWRPQDPH\RXFDQGHOHWHE\
SDVVLQJWKHRULJLQDOLQGH[VSHFLILHU)RUH[DPSOH
# Create a compound index on first_name and last_name properties
# with ascending index direction
dbh.users.create_index([("first_name", pymongo.ASCENDING), ("last_name",
pymongo.ASCENDING)])
# Delete this index
dbh.users.drop_index([("first_name", pymongo.ASCENDING), ("last_name",
pymongo.ASCENDING)])

$OO LQGH[HV LQ D FROOHFWLRQ FDQ EH GURSSHG LQ D VLQJOH VWDWHPHQW XVLQJ WKH Collec
tion.drop_indexes()PHWKRG
,I\RXZLVKWRSURJUDPDWLFDOO\LQVSHFWWKHLQGH[HVRQ\RXUFROOHFWLRQVIURP3\WKRQ
\RXFDQXVHWKHCollection.index_information()PHWKRG7KLVUHWXUQVDGLFWLRQDU\LQ
ZKLFK HDFK NH\ LV WKH QDPH RI DQ LQGH[ 7KH YDOXH DVVRFLDWHG ZLWK HDFK NH\ LV DQ
DGGLWLRQDO GLFWLRQDU\ 7KHVH VHFRQGOHYHO GLFWLRQDULHV DOZD\V FRQWDLQ D VSHFLDO NH\
FDOOHGkeyZKLFKLVDQHQWU\FRQWDLQLQJWKHRULJLQDOLQGH[VSHFLILHU¢LQFOXGLQJLQGH[
GLUHFWLRQ 7KLV RULJLQDO LQGH[ VSHFLILHU ZDV WKH GDWD SDVVHG WR WKH create_index()
PHWKRGZKHQWKHLQGH[ZDVILUVWFUHDWHG7KHVHFRQGOHYHOGLFWLRQDULHVPD\DOVRFRQ
WDLQDGGLWLRQDORSWLRQVVXFKDVXQLTXHFRQVWUDLQWVDQGVRRQ

Location-based Apps with MongoDB: GeoSpatial Indexing


$VPHQWLRQHGLQWKHSUHYLRXVVHFWLRQRQLQGH[HV0RQJR'%KDVVXSSRUWIRUWZRNLQGV
RILQGH[%WUHHDQGJHRVSDWLDO%WUHHLQGH[HVKDYHEHHQFRYHUHGTXLWHWKRURXJKO\LQWKH
SUHFHHGLQJVHFWLRQKRZHYHUZHKDYHQRW\HWGHVFULEHG*HR6SDWLDOLQGH[HV
)LUVWRIDOOOHWXVGLVFXVVZK\JHRVSDWLDOLQGH[LQJPLJKWEHXVHIXODWDOO0DQ\DSSV
WRGD\DUHEHLQJEXLOWZLWKWKHUHTXLUHPHQWRIORFDWLRQDZDUHQHVV7\SLFDOO\WKLVWUDQV
ODWHVLQWRIHDWXUHVZKHUHSRLQWVRILQWHUHVW 32, QHDUDSDUWLFXODUXVHUORFDWLRQPD\EH
UDSLGO\UHWULHYHGIURPDGDWDEDVH)RUH[DPSOHDORFDWLRQDZDUHPRELOHDSSPLJKW
ZLVK WR TXLFNO\ IHWFK D OLVW RI QHDUE\ FRIIHHVKRSV EDVHG XSRQ WKH FXUUHQW *36 FR
RUGLQDWHV7KHFRPSOLFDWLQJLVVXHIXQGDPHQWDOO\LVWKDWWKHZRUOGLVERWKTXLWHODUJH
DQGTXLWHIXOORILQWHUHVWLQJSRLQWV¢DQGVRWRWU\WRDQVZHUVXFKDTXHU\E\LWHUDWLQJ
WKURXJKWKHHQWLUHOLVWRIDOO32,VLQWKHZRUOGWRILQGRQHVZKLFKDUHQHDUE\ZRXOGWDNH
DQXQDFFHSWDEO\ORQJWLPH+HQFHWKHQHHGIRUVRPHVRUWRI*HR6SDWLDOLQGH[LQJWR
VSHHGXSWKHVHVHDUFKHV
)RUWXQDWHO\IRUDQ\ERG\WDVNHGZLWKEXLOGLQJORFDWLRQDZDUHDSSOLFDWLRQV0RQJR'%
LVRQHRIWKHUDUHIHZGDWDEDVHVZLWKRXWRIWKHER[VXSSRUWIRUJHRVSDWLDOLQGH[LQJ
0RQJR'%XVHVJHRKDVKLQJDSXEOLFGRPDLQDOJRULWKPGHYHORSHGE\*XVWDYR1LH
PH\HUZKLFKWUDQVODWHVJHRJUDSKLFSUR[LPLW\LQWROH[LFDOSUR[LPLW\+HQFHDGDWDEDVH
VXSSRUWLQJUDQJHTXHULHV VXFKDV0RQJR'% FDQEHHIILFLHQWO\XVHGWRTXHU\IRUSRLQWV
QHDUDQGZLWKLQERXQGV

Location-based Apps with MongoDB: GeoSpatial Indexing | 33

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
,WVKRXOGEHQRWHGWKDWDWSUHVHQW0RQJR'%¦VJHRVSDWLDOLQGH[LQJVXSSRUWLVOLPLWHG
SXUHO\WRSRLQWEDVHGTXHU\LQJ7KHVXSSOLHGRSHUDWRUVFDQRQO\EHXVHGIRUILQGLQJ
LQGLYLGXDOSRLQWV¢QRWURXWHVRUVXEVKDSHV
0RQJR'% SURYLGHV WKH $near DQG $within RSHUDWRUV ZKLFK FRQVWLWXWH WKH SULPDU\
PHDQVIRUSHUIRUPLQJJHRVSDWLDOTXHULHVLQWKHV\VWHP8VLQJ$near\RXFDQHIILFLHQWO\
VRUWGRFXPHQWVLQDFROOHFWLRQE\WKHLUSUR[LPLW\WRDJLYHQSRLQW7KH$withinRSHUDWRU
DOORZV\RXWRVSHFLI\DERXQGVIRUWKHTXHU\6XSSRUWHGERXQGDU\GHILQLWLRQVLQFOXGH
$boxIRUDUHFWDQJXODUVKDSH $circleIRUDFLUFOH,Q0RQJR'%DQGXSWKH $poly
gonRSHUDWRUDOORZVIRUFRQYH[DQGFRQFDYHSRO\JRQERXQGDULHV
%HIRUH\RXFDQXVHWKHJHRVSDWLDOTXHULHV\RXPXVWKDYHDJHRVSDWLDOLQGH[,Q0RQ
JR'%YHUVLRQVXSWRDQGLQFOXGLQJ[JHRVSDWLDOLQGH[HVDUHOLPLWHGWRDVLQJOHLQGH[
SHUFROOHFWLRQ7KLVPHDQVWKDWHDFKGRFXPHQWFDQKDYHRQO\RQHORFDWLRQSURSHUW\
TXHULHG HIILFLHQWO\ E\ 0RQJR'% 7KLV FDQ KDYH VRPH LPSRUWDQW LPSOLFDWLRQV IRU
VFKHPDGHVLJQZKLFKLVZK\LWLVJRRGWRNQRZIURPWKHRXWVHW
if %

*HRVSDWLDOLQGH[HVE\GHIDXOWOLPLWDFFHSWDEOHYDOXHVIRUWKHORFDWLRQ
SURSHUW\RQGRFXPHQWVWRWKRVHZLWKLQ*367KDWLVFRRUGLQDWHVPXVW
4r<
tp, EHLQWKHUDQJH,I\RXKDYHFRRUGLQDWHVRXWVLGHRIWKLV
UDQJH0RQJR'%ZLOOUDLVHDQH[FHSWLRQZKHQ\RXDWWHPSWWRFUHDWHWKH
JHRVSDWLDOLQGH[RQWKHFROOHFLWRQ,I\RXZLVKWRLQGH[YDOXHVRXWVLGH
RIWKHUDQJHRIUHJXODU*36\RXFDQVSHFLI\WKLVDWLQGH[FUHDWLRQWLPH

7KHORFDWLRQSURSHUW\RQ\RXUGRFXPHQWVPXVWEHHLWKHUDQDUUD\RUVXEGRFXPHQW
ZKHUHWKHILUVWWZRLWHPVDUHWKH[DQG\FRRUGLQDWHVWREHLQGH[HG7KHRUGHURIWKH
FRRUGLQDWHV ZKHWKHU[\RU\[ GRHVQRWPDWWHUVRORQJDVLWLVFRQVLVWHQWRQDOOGRFX
PHQWV)RUH[DPSOH\RXUGRFXPHQWFRXOGORRNOLNHDQ\RIWKHIROORZLQJ
# location property is an array with x,y ordering
user_doc = {
"username":"foouser",
"user_location":[x,y]
}
# location property is an array with y,x ordering
user_doc = {
"username":"foouser",
"user_location":[y,x]
}
import bson
# location property is a sub-document with y,x ordering
loc = bson.SON()
loc["y"] = y
loc["x"] = x
user_doc = {
"username":"foouser",
"user_location":loc
}

34 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
import bson
# location property is a sub-document with x,y ordering
loc = bson.SON()
loc["x"] = x
loc["y"] = y
user_doc = {
"username":"foouser",
"user_location":loc
}

1RWHWKDWLQ3\WKRQWKHGHIDXOWGLFWLRQDU\W\SH dictFODVV RUGHULVQRW


SUHVHUYHG:KHQXVLQJORFDWLRQLQDVXEGRFXPHQWIURP3\WKRQXVHD
a,:' bson.SONREMHFWLQVWHDGbson.SONFRPHVZLWKWKH3\0RQJRGULYHUDQG
LVXVHGLQH[DFWO\WKHVDPHZD\DV3\WKRQ¦VdictFODVV

2QFHWKHGRFXPHQWVLQ\RXUFROOHFWLRQKDYHWKHLUORFDWLRQSURSHUWLHVFRUUHFWO\IRUPHG
ZHFDQFUHDWHWKHJHRVSDWLDOLQGH[$VZLWKEWUHHLQGH[HVJHRVSDWLDOLQGH[HVLQ0RQ
JR'%DUHFUHDWHGZLWK3\0RQJR¦VCollection.create_index()PHWKRG'XHWRWKHRQH
JHRVSDWLDOLQGH[SHUFROOHFWLRQOLPLWDWLRQLQ0RQJR'%YHUVLRQVXSWRDQGLQFOXGLQJ
[LI\RXDUHSODQQLQJWRTXHU\E\RWKHUSURSHUWLHVLQDGGLWLRQWRWKHORFDWLRQSURS
HUW\\RXFDQPDNH\RXUJHRVSDWLDOLQGH[DFRPSRXQGLQGH[)RUH[PDSOHLI\RXNQRZ
WKDW\RXZLOOEHVHDUFKLQJ\RXUFROOHFWLRQE\ERWK£XVHUQDPH¤DQG£XVHUBORFDWLRQ¤
SURSHUWLHV\RXFRXOGFUHDWHDFRPSRXQGJHRLQGH[DFURVVERWKILHOGV7KLVFDQKHOS
WRZRUNDURXQGWKHVLQJOHJHRVSDWLDOLQGH[OLPLWDWLRQLQPDQ\FDVHV
5HWXUQLQJWRRXUH[DPSOHRIGRFXPHQWVLQDFROOHFWLRQFDOOHG£XVHUV¤ZLWKWKHORFDWLRQ
SURSHUW\EHLQJ£XVHUBORFDWLRQ¤ZHZRXOGFUHDWHDJHRVSDWLDOLQGH[ZLWKWKHIROORZLQJ
VWDWHPHQW
# Create geospatial index on "user_location" property.
dbh.users.create_index([("user_location", pymongo.GEO2D)])

7RFUHDWHDFRPSRXQGJHRVSDWLDOLQGH[ZKLFKZRXOGOHWXVTXHU\HIILFLHQWO\RQORFDWLRQ
DQGXVHUQDPHZHFRXOGLVVXHWKLVVWDWHPHQW
# Create geospatial index on "user_location" property.
dbh.users.create_index([("user_location", pymongo.GEO2D), ("username",
pymongo.ASCENDING)])

1RZWKDWZHKDYHJHRVSDWLDOLQGH[HVDYDLODEOHZHFDQWU\RXWVRPHHIILFLHQWORFDWLRQ
EDVHGTXHULHV7KH$nearRSHUDWRULVSUHWW\HDV\WRXQGHUVWDQGVRZHVKDOOVWDUWWKHUH
$VKDVDOUHDG\EHHQH[SODLQHG $nearZLOOVRUWTXHU\UHVXOWVE\SUR[LPLW\WRVSHFLILHG
SRLQW%\GHIDXOW$nearZLOOWU\WRILQGWKHFORVHVWUHVXOWV
$QLPSRUWDQWSHUIRUPDQFHFRQVLGHUDWLRQZKLFKLVQRWPHQWLRQHGFOHDUO\LQWKHRIILFLDO
0RQJR'%GRFXPHQWDWLRQLVWKDWZKHQXVLQJ $near\RXZLOODOPRVWDOZD\VZDQWWR
VSHFLI\DPD[LPXPGLVWDQFHRQWKHTXHU\:LWKRXWDFODPSRQWKHPD[LPXPGLVWDQFH
LQRUGHUWRUHWXUQWKHVSHFLILHGQXPEHURIUHVXOWV GHIDXOW 0RQJR'%KDVWRVHDUFK
WKURXJKWKHHQWLUHGDWDEDVH7KLVWDNHVDORWRIWLPH,QPRVWFDVHVDPD[GLVWDQFHRI

Location-based Apps with MongoDB: GeoSpatial Indexing | 35

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
DURXQGGHJUHHVVKRXOGEHVXIILFLHQW6LQFHZHDUHXVLQJGHFLPDOGHJUHHV DND*36
FRRUGLQDWHVWKHXQLWVRIPD[GLVWDQFHLVGHJUHHVGHJUHHLVURXJKO\PLOHV,I\RX
RQO\FDUHDERXWDUHODWLYHO\VPDOOVHWRIUHVXOWV IRUH[DPSOHWKHQHDUHVWFRIIHHVKRSV 
OLPLWLQJWKHTXHU\WRUHVXOWVVKRXOGDOVRDLGSHUIRUPDQFH
/HW¦VVWDUWZLWKDQH[DPSOHRIILQGLQJWKHQHDUHVWXVHUVWRWKHSRLQWOLPLWLQJ
WRDPD[GLVWDQFHRIGHJUHHV
# Find the 10 users nearest to the point 40, 40 with max distance 5 degrees
nearest_users = dbh.users.find(
{"user_location":
{"$near" : [40, 40],
"$maxDistance":5}}).limit(10)
# Print the users
for user in nearest_users:
# assume user_location property is array x,y
print "User %s is at location %s,%s" %(user["username"], user["user_location"][0],
user["user_location"[1])

1H[WOHWXVWU\XVLQJWKH $withinJHRVSDWLDORSHUDWRUWRILQGSRLQWVZLWKLQDFHUWDLQ
ERXQGDU\7KLVFDQEHXVHIXOZKHQVHDUFKLQJIRU32,¦VLQDVSHFLILFFRXQW\FLW\RUHYHQ
ZHOOGHILQHGQHLJKERXUKRRGZLWKLQDFLW\,QWKHUHDOZRUOGWKHVHERXQGDULHVDUHIX]]\
DQGFKDQJLQJFRQVWDQWO\KRZHYHUWKHUHDUHJRRGHQRXJKGDWDEDVHVDYDLODEOHIRUWKHP
WREHXVHIXO
7RVSHFLI\DUHFWDQJOHWRVHDUFKZLWKLQ\RXVLPSO\SURYLGHWKHORZHUOHIWDQGWRSULJKW
FRRUGLQDWHVDVHOHPHQWVLQDQDUUD\)RUH[DPSOH
box = [[50.73083, -83.99756], [50.741404, -83.988135]]

:HFRXOGTXHU\IRUSRLQWVZLWKLQWKLVERXQGE\XVLQJWKHIROORZLQJJHRVSDWLDOTXHU\
box = [[50.73083, -83.99756], [50.741404, -83.988135]]
users_in_boundary = dbh.users.find({"user_location":{"$within": {"$box":box}}})

7RVSHFLI\DFLWFOHWRVHDUFKZLWKLQ\RXMXVWVXSSO\WKHFHQWHUSRLQWDQGWKHUDGLXV$V
ZLWK $maxDistancePHQWLRQHGSUHYLRXVO\WKHXQLWVRIWKHUDGLXVDUHGHJUHHV+HUHLV
KRZZHFRXOGPDNHDJHRVSDWLDOORRNXSIRUXVHUVZLWKLQDUDGLXVRIGHJUHVVFHQ
WHUHGDWWKHSRLQW
users_in_circle = dbh.users.find({"user_location":{"$within":{"$center":[40, 40,
5]}}}).limit(10)

1RWLFHWKDWZLWKWKHFLUFOHERXQGDU\XVLQJ$centerZHSDVVDQDUUD\WKHILUVWWZRYDOXHV
RIZKLFKDUHWKHFRRUGLQDWHVRIWKHFHQWHUDQGWKHWKLUGSDUDPHWHULVWKHUDGLXV LQ
GHJUHHV 
$OOWKHTXHULHVZH¦YHPHQWLRQHGVRIDUZKLFKPDNHXVHRIDJHRVSDWLDOLQGH[DFWXDOO\
DUHQRWHQWLUHO\DFFXUDWH7KLVLVEHFDXVHWKH\XVHDIODWHDUWKPRGHOZKHUHHDFKDUF
GHJUHHRIODWLWXGHDQGORQJLWXGHWUDQVODWHVWRWKHVDPHGLVWDQFHHYHU\ZKHUHRQWKHHDUWK
,QUHDOLW\WKHHDUWKLVDVSKHUHDQGVRWKHVHYDOXHVGLIIHUGHSHQGLQJXSRQZKHUH\RX
DUH)RUWXQDWHO\0RQJR'%LQ[DQGXSLPSOHPHQWVDVSKHULFDOPRGHORIWKHHDUWK
IRUJHRVSDWLDOTXHULHV

36 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
7KH QHZ VSKHULFDO PRGHO FDQ EH XVHG E\ HPSOR\LQJ WKH $nearSphere DQG $circle
SphereYDULDQWVRQWKH$nearDQG$circleRSHUDWRUV0RQJR'%¦VVSKHULFDOPRGHOKDVD
IHZH[WUDFDYHDWV)LUVWDQGIRUHPRVW\RXPXVWXVH ORQJLWXGHODWLWXGH RUGHULQJRI
\RXUFRRUGLQDWHV:KLOHWKHUHDUHPDQ\RWKHUDSSOLFDWLRQDQGIRUPDWVZKLFKXVHWKH
ODWLWXGHORQJLWXGH RUGHULQJ\RXVKRXOGEHFDUHIXOWRUHRUGHUWRXVHZLWK0RQJR'%¦V
VSKHULFDOPRGHO6HFRQGO\XQOLNHWKH$nearDQG$centerRSHUDWRUVZHMXVWGHVFULEHG
WKHXQLWVIRUGLVWDQFHVZLWK $nearSphereDQG $centerSphereDUHDOZD\VH[SUHVVHGLQ
UDGLDQV7KLVLQFOXGHVZKHQXVLQJ $maxDistanceZLWK $nearSphereRU $centerSphere
/XFNLO\LWLVQRWGLIILFXOWWRFRQYHUWIURPDPRUHKXPDQO\XQGHUVWDQGDEOHXQLWVXFK
DVNLORPHWHUVWRUDGLDQV7RWUDQVODWHIURPNLORPHWHUVWRUDGLDQVVLPSO\GLYLGHWKH
NLORPHWHUYDOXHE\WKHUDGLXVRIWKHHDUWKZKLFKLVDSSUR[LPDWHO\NP RU
PLOHV 7RGHPRQVWUDWHOHW¦VWU\RXUHDUOLHUH[DPSOHRIILQGLQJWKHXVHUVQHDUHVWWR
WKHSRLQWZLWKDPD[GLVWDQFHRINP¢EXWWKLVWLPHXVLQJWKHVSKHULFDOPRGHO
# Find the 10 users nearest to the point 40, 40 with max distance 5 degrees
# Uses the spherical model provided by MongoDB 1.8.x and up

earth_radius_km = 6371.0
max_distance_km = 5.0
max_distance_radians = max_distance_km / earth_radius_km
nearest_users = dbh.users.find(
{"user_location":
{"$nearSphere" : [40, 40],
"$maxDistance":max_distance_radians}}).limit(10)
# Print the users
for user in nearest_users:
# assume user_location property is array x,y
print "User %s is at location %s,%s" %(user["username"], user["user_location"][0],
user["user_location"[1])

Code Defensively to Avoid KeyErrors and Other Bugs


2QHRIWKHWUDGHRIIVRIDGRFXPHQWRULHQWHGGDWDEDVHYHUVXVDUHODWLRQDOGDWDEDVHLV
WKDWWKHGDWDEDVHGRHVQRWHQIRUFHVFKHPDIRU\RX)RUWKLVUHDVRQZKHQZRUNLQJZLWK
0RQJR'%\RXPXVWEHYLJLODQWLQ\RXUKDQGOLQJRIGDWDEDVHUHVXOWV'RQRWEOLQGO\
DVVXPHWKDWUHVXOWVZLOODOZD\VKDYHWKHSURSHUWLHV\RXH[SHFW
&KHFNIRUWKHLUSUHVHQFHEHIRUHDFFHVVLQJWKHP$OWKRXJK3\WKRQZLOOJHQHUDOO\UDLVH
D.H\(UURUDQGVWRSH[HFXWLRQGHSHQGLQJRQ\RXUDSSOLFDWLRQWKLVVWLOOPD\UHVXOWLQ
ORVVRIGDWDLQWHJULW\&RQVLGHUWKHFDVHRIXSGDWLQJHYHU\GRFXPHQWLQDFROOHFWLRQRQH
E\RQH¢DVLQJOHXQIRUHVHHQ.H\(UURUFRXOGOHDYHWKHGDWDEDVHLQDQLQFRQVLVWHQWVWDWH
ZLWKVRPHGRFXPHQWVKDYLQJEHHQXSGDWHGDQGRWKHUVQRW
)RUH[DPSOH
all_user_emails = []
for username in ("jill", "sam", "cathy"):
user_doc = dbh.users.find_one({"username":username})
# KeyError will be raised if any of these does not exist
dbh.emails.insert({"email":user_doc["email"]})

Code Defensively to Avoid KeyErrors and Other Bugs | 37

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
6RPHWLPHV\RXZLOOZDQWWRKDYHDGHIDXOWIDOOEDFNWRDYRLG.H\(UURUVVKRXOGDGRFX
PHQWEHUHWXUQHGZKLFKLVPLVVLQJDSURSHUW\UHTXLUHGE\\RXUSURJUDP7KH3\WKRQ
dictFODVV¦getPHWKRGHDVLO\OHWV\RXVSHFLI\DGHIDXOWYDOXHIRUDSURSHUW\VKRXOGLWEH
PLVVLQJ
2IWHQLWPDNHVVHQVHWRXVHWKLVGHIHQVLYHO\)RUH[DPSOHLPDJLQHZHKDYHDFROOHFWLRQ
RIXVHUGRFXPHQWV6RPHXVHUVKDYHD£VFRUH¤SURSHUW\VHWWRDQXPEHUZKLOHRWKHUV
GRQRW,WZRXOGEHVDIHWRKDYHDGHIDXOWIDOOEDFNRI]HUR  LQWKHFDVHWKDWQRVFRUH
SURSHUW\LVSUHVHQW:HFDQWDNHDPLVVLQJVFRUHWRPHDQD]HURVFRUH7KHdictFODVV¦V
getPHWKRGOHWVXVGRWKLVHDVLO\
total_score = 0
for username in ("jill", "sam", "cathy"):
user_doc = dbh.users.find_one({"username":username})
total_score += user_doc.get("score", 0)

7KLVDSSURDFKFDQDOVRZRUNZHOOZKHQORRSLQJRYHUHPEHGGHGOLVWV)RUH[DPSOHWR
GHIHQVLYHO\KDQGOHWKHFDVHZKHUHDGRFXPHQWUHSUHVHQWLQJDSDUWLFXODUSURGXFWGRHV
QRW\HWKDYHDOLVWRIVXSSOLHUVHPEHGGHG SHUKDSVEHFDXVHLWLVQRW\HWRQWKHPDUNHW
RULVQRORQJHUEHLQJSURGXFHG \RXPLJKWZULWHFRGHOLNHWKLV
# Email each supplier of this product.
# Default value is the empty list so no special casing
# is needed if the suppliers property is not present.
for supplier in product_doc.get("suppliers", []):
email_supplier(supplier)

0RQJR'%DOVRPDNHVQRJXDUDQWHHVDERXWWKHW\SHRIDSURSHUW\¦VYDOXHRQDJLYHQ
GRFXPHQW
,QPRVW5'%06LPSOHPHQWDWLRQV WKHQRWDEOHH[FHSWLRQ,¦PDZDUHRIEHLQJ64/LWH
WKHGDWDEDVHZLOOTXLWHULJRURXVO\HQIRUFHFROXPQW\SHV,I\RXWU\WRLQVHUWDVWULQJLQWR
DQLQWHJHUFROXPQWKHGDWDEDVHZLOOUHMHFWWKHZULWH
0RQJR'%RQWKHRWKHUKDQGZLOORQO\LQH[FHSWLRQDOFLUFXPVWDQFHVUHMHFWVXFKZULWHV
,I\RXVHWWKHYDOXHRIDSURSHUW\RQRQHGRFXPHQWWREHDVWULQJDQGRQDQRWKHUGRFX
PHQWLQWKHVDPHFROOHFWLRQVHWWKHYDOXHRIWKDWSURSHUW\WRDQXPEHULWZLOOYHU\
KDSSLO\VWRUHWKDW
# Perfectly legal insert - MongoDB will not complain
dbh.users.insert({"username":"janedoe"})
# Also perfectly legal - MongoDB will not complain
dbh.users.insert({"username":l337})

:KHQ\RXFRXSOHWKLVZLWK3\WKRQ¦VZLOOLQJQHVVWROHW\RXIRUJRH[SOLFLWO\W\SLQJ\RXU
YDULDEOHV\RXFDQVRRQUXQLQWRWURXEOH3HUKDSVWKHPRVWFRPPRQVFHQDULRLVZKHQ
ZULWLQJ LQSXWV IURP :HE DSSOLFDWLRQV WR WKH GDWDEDVH 0RVW :6*,EDVHG 3\WKRQ
IUDPHZRUNV ZLOO VHQG \RX DOO +773 3267 DQG *(7 SDUDPHWHU YDOXHV DV VWULQJV¢
UHJDUGOHVVRIZKHWKHURUQRWWKH\DUHLQIDFWVWULQJV
7KXVLWLVHDV\WRLQVHUWRUXSGDWHDQXPHULFSURSHUW\ZLWKDYDOXHWKDWLVDVWULQJ7KH
EHVWZD\RIFRXUVHWRDYRLGHUURUVRIWKLVQDWXUHLVWRSUHYHQWWKHZURQJW\SHRIGDWD

38 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
HYHUEHLQJZULWWHQWRWKHGDWDEDVHLQWKHILUVWSODFH7KXVLQWKHFRQWH[WRID:HE
DSSOLFDWLRQYDOLGDWLQJDQGRUFRHUFLQJWKHW\SHVRIDQ\LQSXWVWRZULWHTXHULHVEHIRUH
LVVXLQJWKHPLVVWURQJO\DGYLVHG<RXPD\FRQVLGHUXVLQJWKH)RUP(QFRGHRU&RODQGHU
3\WKRQOLEUDULHVWRKHOSZLWKVXFKYDOLGDWLRQ

Update-or-Insert: Upserts in MongoDB


$UHODWLYHO\FRPPRQWDVNLQDGDWDEDVHSRZHUHGDSSOLFDWLRQLVWRXSGDWHDQH[LVWLQJ
HQWU\RULIQRWIRXQGLQVHUWLWDVDQHZUHFRUG0RQJR'%FRQYHQLHQWO\VXSSRUWVWKLV
DVDVLQJOHRSHUDWLRQIUHHLQJ\RXIURPKDYLQJWRLPSOHPHQW\RXURZQ£LIH[LVWVXSGDWH
HOVHLQVHUW¤ORJLFJHQUHIHUWRWKLVW\SHRIZULWHRSHUDWLRQDVDQ£XSVHUW¤
,Q3\0RQJRWKHUHDUHWKUHHSRVVLEOHPHWKRGVRQHFDQXVHWRSHUIRUPDQXSVHUW7KHVH
DUH Collection.save() Collection.update()DQG Collection.find_and_modify():H
VKDOOVWDUWE\GHVFULELQJCollection.save()DVLWLVWKHPRVWVWUDLJKWIRUZDUGPHWKRG
,Q WKH HDUOLHU VHFWLRQ £,QVHUWLQJ D 'RFXPHQW LQWR D &ROOHFWLRQ¤ ZH XVHG WKH Collec
tion.insert()PHWKRGWRZULWHDQHZGRFXPHQWWRWKHFROOHFWLRQ+RZHYHUZHFRXOG
KDYHMXVWDVHDVLO\XVHGWKHsave()PHWKRGsave()RIIHUVDOPRVWLGHQWLFDOIXQFWLRQDOLW\
WRinsert()ZLWKWKHIROORZLQJH[FHSWLRQVsave()FDQSHUIRUPXSVHUWVDQGsave()FDQ
QRWLQVHUWPXOWLSOHGRFXPHQWVLQDVLQJOHFDOO
save()LVTXLWHHDV\WRXQGHUVWDQG,I\RXSDVVLWDGRFXPHQWZLWKRXWDQ_idSURSHUW\
LWZLOOSHUIRUPDQinsert()FUHDWLQJDEUDQGQHZGRFXPHQW,IRQWKHRWKHUKDQG\RX
SDVVLWDGRFXPHQWZKLFKFRQWDLQVDQ_idSURSHUW\LWZLOOXSGDWHWKHH[LVWLQJGRFXPHQW
FRUUHVSRQGLQJWRWKDW _idYDOXHRYHUZULWLQJWKHDOUHDG\SUHVHQWGRFXPHQWZLWKWKH
GRFXPHQWSDVVHGWRsave()
7KLVLVWKHHVVHQFHRIDQXSVHUW,IDGRFXPHQWDOUHDG\H[LVWVXSGDWHLW2WKHUZLVH
FUHDWHDQHZGRFXPHQW
save()FDQEHXVHIXOEHFDXVHLWVXSSRUWVERWKZULWLQJQHZGRFXPHQWVDQGPRGLI\LQJ
H[LVWLQJGRFXPHQWVPRVWOLNHO\RQHVUHWULHYHGIURP0RQJR'%YLDDUHDGTXHU\+DYLQJ
D VLQJOH PHWKRG ZKLFK LV FDSDEOH RI ERWK PRGHV RI RSHUDWLRQ UHGXFHV WKH QHHG IRU
FRQGLWLRQDOKDQGOLQJLQ\RXUFOLHQWFRGHWKXVVLPSOLI\LQJ\RXUSURJUDP
0RUHXVHIXOSHUKDSVLVWKH£XSVHUW 7UXH¤SDUDPHWHUZKLFKPD\EHSDVVHGWRCollec
tion.update()$VKDVEHHQGLVFXVVHGLQWKHVHFWLRQ£8SGDWLQJ'RFXPHQWVLQD&RO
OHFWLRQ¤ DQG LV IXUWKHU GHVFULEHG LQ WKH VHFWLRQ £0RQJR'% 8SGDWH 0RGLILHUV¤ WKH
update()PHWKRGVXSSRUWVWKHXVHRI£XSGDWHPRGLILHUV¤7KHVHULFKRSHUDWRUVHQDEOH
\RXWRSHUIRUPZULWHVPRUHFRPSOH[WKDQWKHEDVLF£RYHUZULWHEXWNHHSH[LVWLQJBLG¤
VHPDQWLFVRIWKHsave()PHWKRG
)RUH[DPSOHLPDJLQH\RXDUHZULWLQJDPHWKRGedit_or_add_session()7KLVPHWKRG
HLWKHUHGLWVDQH[LVWLQJGRFXPHQWRULQVHUWVDQHZRQH)XUWKHUPRUHVHPDQWLFVRIWKH
PHWKRGGLFWDWHWKDWWKHPHWKRGZLOODOZD\VEHFDOOHGZLWKDVHVVLRQBLGEXWWKDWWKH
VHVVLRQBLGPD\RUPD\QRWDOUHDG\EHSUHVHQWLQWKHGDWDEDVH7KHQDLYHLPSOHPHQWD

Update-or-Insert: Upserts in MongoDB | 39

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
WLRQZRXOGILUVWTXHU\WRVHHZKHWKHUDVHVVLRQGRFXPHQWDOUHDG\H[LVWHGWKHQFRQGL
WLRQDOO\HLWKHULQVHUWDQHZVHVVLRQGRFXPHQWRUXSGDWHWKHH[LVWLQJGRFXPHQW
# Naive, bad implementation without upsert=True
def edit_or_add_session(description, session_id):
# We must query first, becase we don't know whether this session_id already exists.
# If we attempt to update a non-existent document, no write will occur.
session_doc = dbh.sessions.find_one({"session_id":session_id})
if session_doc:
dbh.sessions.update({"session_id":session_id},
{"$set":{"session_description":description}}, safe=True)
else:
dbh.sessions.insert({"session_description":description,
"session_id":session_id},
safe=True)

+RZHYHUE\HPSOR\LQJWKHXSVHUWIHDWXUHRICollection.update()WKLVFDQEHLPSOH
PHQWHGLQDVLQJOHPHWKRGFDOO¢VLPSOLI\LQJWKHFRGHFRQVLGHUDEO\DQGHOLPLQDWLQJWKH
QHHGIRUDQH[WUDUHDGTXHU\
# Good implementation using upsert=True
def edit_or_add_session(description, session_id):
dbh.sessions.update({"session_id":session_id},
{"$set":{"session_description":description}}, safe=True, upsert=True)

1RWHWKDWZHFRXOGQRWKDYHLPSOHPHQWHGWKHDERYHVHPDQWLFVXVLQJ Cursor.save()
EHFDXVHZHDUHWHVWLQJIRUH[LVWHQFHRQWKHSURSHUW\£VHVVLRQBLG¤UDWKHUWKDQ£BLG¤
5HFDOOWKDWWKHsave()XSVHUWPHWKRGRQO\ZRUNVZLWK£BLG¤
7KHWULFNWRXQGHUVWDQGLQJXSVHUWVZLWKWKH update()PHWKRGLVWRFRQVLGHUWKHWZR
H[HFXWLRQFDVHVVHSHUDWHO\,QWKHFDVHWKDWWKHGRFXPHQWDOUHDG\H[LVWVWKHQWKHXSGDWH
GRFXPHQWZLOOEHSURFHVVHGQRUPDOO\¢MXVWDVZLWKDUHJXODUupdate()FDOOZLWKRXWWKH
£XSVHUW 7UXH¤SDUDPHWHU+RZHYHULQWKHFDVHWKDWWKHGRFXPHQWGRHVQRWDOUHDG\
H[LVWWKHGRFXPHQWZULWWHQ XSVHUWHG ZLOOPDWFKERWKWKHGRFXPHQWVSHFVXSSOLHGDV
WKHILUVWDUJXPHQWWRWKHupdate()FDOODQGWKHXSGDWHGRFXPHQWZLWKDQ\PRGLILHUVLW
FRQWDLQV,QRWKHUZRUGVWKHREVHUYHGEHKDYLRXULVWKDWWKHGRFXPHQWLVILUVWFUHDWHG
ZLWK WKH SURSHUWLHV VSHFLILHG LQ WKH GRFXPHQW VSHF¢LQ WKLV FDVH "session_id":ses
sion_id¢DQGWKHQWKHXSGDWHGRFXPHQWLVH[HFXWHGDJDLQVWWKDW7KDWPD\QRWDFFX
UDWHO\UHIOHFWZKDWLVKDSSHQLQJLQWHUQDOO\LQWKHGDHPRQRUGULYHUEXWWKDWLVHTXLYDOHQW
WRZKDWHYHUGRHVJRRQ

Atomic Read-Write-Modify: MongoDB’s findAndModify


:H¦YHDOUHDG\LQWURGXFHGWKHDWRPLFXSGDWHPRGLILHUVVXSSRUWHGE\0RQJR'%7KHVH
DUHYHU\SRZHUIXODQGHQDEOHUDFHIUHHZULWHRSHUDWLRQVRIPDQ\NLQGV¢LQFOXGLQJDUUD\
PDQLSXODWLRQDQGLQFUHPHQWGHFUHPHQW+RZHYHULWLVRIWHQQHFHVVDU\WREHDEOHWR
PRGLI\WKHGRFXPHQWDWRPLFDOO\DQGDOVRUHWXUQWKHUHVXOWRIWKHDWRPLFRSHUDWLRQ¢
LQDVLQJOHVWHS

40 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
)RUH[DPSOHLPDJLQHDELOOLQJV\VWHP(DFKXVHUGRFXPHQWKDVDQ£DFFRXQWBEDODQFH¤
SURSHUW\7KHUHPD\EHZULWHVZKLFKDOWHUWKHDFFRXQWEDODQFH¢OHW¦VVD\DQDFFRXQW
WRSXSHYHQWZKLFKDGGVPRQH\WRWKHDFFRXQWDQGDSXUFKDVHDFWLRQZKLFKWDNHV
PRQH\IURPWKHDFFRXQW&RQVLGHUWKHIROORZLQJLPSOHPHQWDWLRQ
# User X adds $20 to his/her account, so we atomically increment
# account_balance
dbh.users.update({"username":username}, {"$inc":{"account_balance":20}}, safe=True)
# Fetch the updated account balance to display to user
new_account_balance = dbh.users.find_one({"username":username},
{"account_balance":1})["account_balance"]

7KLVZLOOZRUNILQHDVVXPLQJQRRWKHUZULWHVWRWKHDFFRXQWEDODQFHRFFXUEHWZHHQWKH
ZULWHDQGUHDGRSHUDWLRQV7KHUHLVDQREYLRXVUDFHFRQGLWLRQ,IDSXUFKDVHDFWLRQZHUH
WRWDNHSODFHEHWZHHQWKHEDODQFHXSGDWHDQGWKHEDODQFHUHDGWKHXVHUPD\EHGLV
SOHDVHGWREHSUHVHQWHGZLWKDSRVWSD\PHQWEDODQFHRIOHVVWKDQZKDWWKH\H[SHFWHG
# User X adds $20 to his/her account, so we atomically increment
# account_balance
dbh.users.update({"username":username}, {"$inc":{"account_balance":20}}, safe=True)

# In the meantime, in another thread or process, there is a payment operation,


# which decrements the account balance:
dbh.users.update({"username":username}, {"$dec":{"account_balance":5}}, safe=True)

# Fetch the updated account balance to display to user


new_account_balance = dbh.users.find_one({"username":username},
{"account_balance":1})["account_balance"]

:KDW\RXZDQWLQWKLVNLQGRIVLWXDWLRQLVDZD\WRXSGDWHWKHDFFRXQWEDODQFHDQG
UHWXUQWKHQHZYDOXHLQDVLQJOHDWRPLFRSHUDWLRQ0RQJR'%¦VILQG$QG0RGLI\FRP
PDQGDOORZV\RXWRGRMXVWWKLV3\0RQJRSURYLGHVDZUDSSHUDURXQGILQG$QG0RGLI\
LQWKH Collection.find_and_modify()PHWKRG8VLQJWKLVPHWKRGZHFDQUHZULWHWKH
FRGHWRDVLQJOHDWRPLFRSHUDWLRQ
# User X adds $20 to his/her account, so we atomically increment
# account_balance and return the resulting document
ret = dbh.users.find_and_modify({"username":username},
{"$inc":{"account_balance":20}}, safe=True, new=True)
new_account_balance = ret["account_balance"]

Fast Accounting Pattern


0DQ\RIWKHDSSOLFDWLRQVSHRSOHDUHEXLOGLQJWRGD\DUHUHDOWLPHZLWKYHU\ODUJHGDWD
VHWV7KDWLVWRVD\XVHUVH[SHFWFKDQJHVWKH\PDNHWREHUHIOHFWHGZLWKLQWKHDSSOLFDWLRQ
LQVWDQWO\)RUH[DPSOHLIDXVHUZLQVDQHZKLJKVFRUHLQDPXOWLSOD\HUJDPHWKH\H[SHFW
WKHKLJKVFRUHWDEOHLQWKHJDPHWREHXSGDWHGLPPHGLDWHO\+RZHYHULWPD\QRWEHD
VLQJOHKLJKVFRUHWDEOHZKLFKPXVWEHXSGDWHG3HUKDSV\RXDUHDOVRUDQNLQJE\KLJK
VFRUHWKLVZHHNRUWKLVPRQWKRUHYHQWKLV\HDU)XUWKHUPRUHDVWKHDSSOLFDWLRQGH
YHORSHU\RXPD\ZLVKWRNHHSDGHWDLOHGORJRIHDFKFKDQJH¢LQFOXGLQJZKHQLWRFFXUHG

Fast Accounting Pattern | 41

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
ZKDWWKHFOLHQW,3DGGUHVVZDVWKHVRIWZDUHYHUVLRQRIWKHFOLHQWHWF¢SHUXVHUIRU
DQDO\WLFVSXUSRVHV
7KLVSDWWHUQLVQ¦WOLPLWHGWRKLJKVFRUHV6LPLODUKLJKSHUIRUPDQFHDFFRXQWLQJUHTXLUH
PHQWVH[LVWIRULQDSSVRFLDODFWLYLW\IHHGVELOOLQJV\VWHPVZKLFKFKDUJHSHUE\WHDQG
VRRQ1RWRQO\GRWKHVHFRXQWVQHHGWREHIDVWWRUHDGIURPWKHGDWDEDVHWKH\QHHGV
WREHTXLFNWRZULWH$GGLWLRQDOO\ZLWKSRWHQWLDOO\PLOOLRQVRIXVHUVWKHGDWDVHWFDQ
JURZYHU\ODUJHYHU\TXLFNO\
<RXPLJKWEHWHPSWHGWRNHHSRQO\DGHWDLOHGORJZLWKRQHGRFXPHQWSHUFKDQJH
7RWDOVIRUWKHYDULRXVWLPHSHULRGVFDQWKHQEHFDOFXODWHGE\DQDJJUHJDWHTXHU\DFURVV
WKHFROOHFWLRQ7KLVPD\ZRUNZHOOLQLWLDOO\ZLWKRQO\KXQGUHGVRUWKRXVDQGVRIGRFX
PHQWV WR EH DJJUHJDWHG WR FRPSXWH WKH UHVXOW +RZHYHU ZKHQ WKH QXPEHU RI WKHVH
GRFXPHQWVJURZVLQWRWKHPLOOLRQVRUHYHQELOOLRQV¢ZKLFKWKH\PD\HDVLO\GRLQD
VXFFHVVIXODSSOLFDWLRQ¢WKLVDSSURDFKZLOOTXLFNO\EHFRPHLQWUDFWDEOH
2IFRXUVHDVZLWKPDQ\SUREOHPVLQ&RPSXWHU6FLHQFHWKHVROXWLRQLVXOWLPDWHO\D
IRUPRIFDFKLQJ0RQJR'%DQGLWVGRFXPHQWRULHQWHGGDWDPRGHOJLYHVXVDQLFHLGLRP
IRUWKLVNLQGRISHULRGEDVHGDFFRXQWLQJKRZHYHU*LYHQWKDWZHDUHFRXQWLQJRQD
SHUXVHUEDVLVZHFDQXWLOL]HHPEHGGHGVXEGRFXPHQWVFRQWDLQLQJSURSHUW\QDPHV
GHULYHGIURPWLPHSHULRG&RQVLGHUIRUH[DPSOHDKLJKVFRUHWDEOHVXSSRUWLQJUHVROX
WLRQVRIZHHNPRQWKDQGWRWDO DFURVVDOOWLPH 
)RUWKHZHHNO\UHVROXWLRQVFRUHFRXQWVZHFDQQDPHWKHSURSHUWLHVDIWHUWKHFXUUHQW
ZHHNQXPEHU7RGLVDPELJXDWHRYHUPXOWLSOH\HDUVZHFDQLQFOXGHWKHIRXUGLJLW\HDU
LQWKHNH\
# Store weekly scores in sub-document
user_doc = {
"scores_weekly":{
"2011-01":10,
"2011-02":3,
"2011-06":20
}
}

7RIHWFKWKHVFRUHIRUWKLVZHHNZHVLPSO\H[HFXWHWKHIROORZLQJVLPSOHGLFWLRQDU\
ORRNXS
# Fetch the score for the current week
import datetime
now = datetime.datetime.utcnow()
current_year = now.year
current_week = now.isocalendar()[1]
# Default missing keys to a score of zero
user_doc["scores_weekly"].get("%d-%d" %(current_year, current_week), 0)

6XFKDORRNXSLVLQFUHGLEO\IDVW7KHUHLVQRDJJUHJDWLRQWRSHUIRUPZKDWVRHYHU:LWK
WKLVSDWWHUQZHFDQDOVRZULWHYHU\TXLFNO\DQGVDIHO\%HFDXVHZHDUHFRXQWLQJZHFDQ
WDNH DGYDQWDJH RI 0RQJR'%¦V DWRPLF LQFUHPHQW DQG GHFUHPHQW XSGDWH PRGLILHUV
$incDQG$dec$WRPLFXSGDWHRSHUDWRUVDUHJUHDWEHFDXVHWKH\HQVXUHWKHXQGHUO\LQJ

42 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
GDWDLVLQDFRQVLVWHQWVWDWHDQGKHOSWRDYRLGQDVW\UDFHFRQGLWLRQV(VSHFLDOO\ZKHQ
GHDOLQJZLWKELOOLQJDFFXUDWHFRXQWVDUHYHU\LPSRUWDQW
,PDJLQHZHZLVKWRLQFUHPHQWWKHXVHU¦VVFRUHIRUWKLVZHHNE\:HFDQGRVRZLWK
WKHIROORZLQJTXHU\
# Update the score for the current week
import datetime
username = "foouser"
now = datetime.datetime.utcnow()
current_year = now.year
current_week = now.isocalendar()[1]
# Use atomic update modifier to increment by 24
dbh.users.update({"username":username},
{"$inc":{"scores_weekly.%s-%s" %(current_year, current_week):24}},
safe=True)

,IWKHDSSOLFDWLRQ QHHGV WR WUDFN PXOWLSOH WLPHSHULRGVWKHVHFDQEHUHSUHVHQWHGDV


DGGLWLRQDOVXEGRFXPHQWV
# Store daily, weekly, monthly and total scores in user document
user_doc = {
"scores_weekly":{
"2011-01":10,
"2011-02":3,
"2011-06":20
},
"scores_daily":{
"2011-35":2,
"2011-59":7,
"2011-83":15
},
"scores_monthly":{
"2011-09":30,
"2011-10":43,
"2011-11":24
},
"score_total":123
}

2IFRXUVHLQ\RXUZULWHV\RXVKRXOGLQFUHPHQWWKHFRXQWVIRUHDFKWLPHSHULRG
# Update the score for the current week
import datetime
username = "foouser"
now = datetime.datetime.utcnow()
current_year = now.year
current_month = new.month
current_week = now.isocalendar()[1]
current_day = now.timetuple().tm_yday
# Use atomic update modifier to increment by 24
dbh.users.update({"username":username},
{"$inc":{
"scores_weekly.%s-%s" %(current_year, current_week):24,
"scores_daily.%s-%s" %(current_year, current_day):24,
"scores_monthly.%s-%s" %(current_year, current_month):24,

Fast Accounting Pattern | 43

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
"score_total":24,
}
},
safe=True)

,QFDVHVZKHUH\RXZDQWWRUHSRUWWKHFRXQWLPPHGLDWHO\DIWHUWKHXSGDWHWKDWFDQEH
DFKLHYHGE\XVLQJWKHILQG$QG0RGLI\FRPPDQG GHVFULEHGLQSUHYLRXVVHFWLRQ WRUH
WXUQWKHQHZGRFXPHQWDIWHUWKHXSGDWHKDVEHHQDSSOLHG
7KLVSDWWHUQFDQKHOSJUHDWO\ZLWKKLJKVSHHGFRXQWLQJ,IPRUHGHWDLOHGORJVDUHVWLOO
QHHGHG¢VXFKDVZKHQHDFKDFWLRQWRRNSODFH¢IHHOIUHHWRPDLQWDLQWKRVHLQDVHSDUDWH
FROOHFWLRQ7KLVVXPPDU\GDWDLVPRVWXVHIXOIRUH[WUHPHO\IDVWUHDGVDQGZULWHV

44 | Chapter 3:ಗCommon MongoDB and Python Patterns

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
CHAPTER 4
MongoDB with Web Frameworks

:KLOH0RQJR'%FDQEHXVHGLQDOOVRUWVRIDSSOLFDWLRQVLWVPRVWREYLRXVUROHLVDVWKH
GDWDEDVHEDFNHQGIRUDZHEDSSOLFDWLRQ7KHVHGD\VDJUHDWPDQ\PRELOHDQGWDEOHW
DSSOLFDWLRQVDUHIXQFWLRQLQJDV£IDWFOLHQWV¤WRWKHVDPH+773EDVHG$3,¦VDVEURZVHU
EDVHGZHEDSSOLFDWLRQVKHQFHPRELOHDQGWDEOHWDSSVQHHGWKHVDPHVRUWRIEDFNHQG
GDWDEDVHLQIUDVWUXFWXUHDVPRUHWUDGLWLRQDOZHEDSSV
0DQ\ RUJDQL]DWLRQV DQG HQJLQHHUV DUH ILQGLQJ WKH DGYDQWDJHV RI 0RQJR'%¦V GRFX
PHQWRULHQWHGDUFKLWHFWXUHFRPSHOOLQJHQRXJKWRPLJUDWHSDUWVRUHYHQHQWLUHDSSOLFD
WLRQVIURPWUDGLWLRQDO5'%06VXFKDV0\64/WR0RQJR'%1XPHURXVZHOONQRZQ
FRPSDQLHVKDYHEXLOWWKHLUZKROHDSSOLFDWLRQIURPWKHJURXQGXSRQ0RQJR'%
,WLVP\RSLQLRQWKDWIRUWKHYDVWPDMRULW\RIZHEPRELOHDQGWDEOHWDSSOLFDWLRQV0RQ
JR'%LVDEHWWHUVWDUWLQJSRLQWWKDQ5'%06WHFKQRORJ\VXFKDV0\64/7KLVFKDSWHU
LVDQDWWHPSWWRJHW\RXRIIWKHJURXQGXVLQJ0RQJR'%ZLWKWKUHHFRPPRQ3\WKRQ
ZHEIUDPHZRUNV3\ORQV3\UDPLGDQG'MDQJR

Pylons 1.x and MongoDB


3\ORQVLVRQHRIWKHROGHU:6*,EDVHG3\WKRQZHEIUDPHZRUNVGDWLQJEDFNWR6HS
WHPEHU3\ORQVUHDFKHGYHUVLRQLQDQGLVFRQVLGHUHGYHU\VWDEOHDWWKLV
SRLQW ,Q IDFW QRW PXFK GHYHORSPHQW LV SODQQHG IRU 3\ORQV [ DQ\ PRUH DOO QHZ
GHYHORSPHQWLVKDSSHQLQJLQ3\UDPLG VHH£3\UDPLGDQG0RQJR'%¤RQSDJHIRU
GHWDLOV 7KH3\ORQVSKLORVRSK\LVWKHSUHFLVHRSSRVLWHRI£RQHVL]HILWVDOO¤$SSOLFD
WLRQGHYHORSHUVDUHIUHHWRFKRRVHIURPWKHYDULRXVGDWDEDVHWHPSODWLQJVHVVLRQVWRUH
RSWLRQVDYDLODEOH7KLVNLQGRIIUDPHZRUNLVH[FHOOHQWZKHQ\RXDUHQ¦WH[DFWO\VXUH
ZKDWSLHFHV\RXZLOOQHHGZKHQ\RXDUHVWDUWLQJZRUNRQ\RXUDSSOLFDWLRQ,ILWWXUQV
RXW\RXQHHGWRXVHDQ;0/EDVHGWHPSODWLQJV\VWHP\RXDUHIUHHWRGRVR
7KHH[LVWHQFHRI3\UDPLGDVLGH3\ORQV[LVDYHU\FDSDEOHDQGVWDEOHIUDPHZRUN$V
3\ORQVLVVRPRGXODULWLVHDV\WRDGG0RQJR'%VXSSRUWWRLW

45

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
)LUVW\RXQHHGWRFUHDWHDYLUWXDOHQYLURQPHQWIRU\RXUSURMHFW7KHVHLQVWUXFWLRQVDV
VXPH\RXKDYHWKHvirtualenvWRROLQVWDOOHGRQ\RXUV\VWHP,QVWDOOLQVWUXFWLRQVIRUWKH
virtualenvWRRODUHSURYLGHGLQWKHILUVWFKDSWHURIWKLVERRN
7RFUHDWHWKHYLUWXDOHQYLURQPHQWDQGLQVWDOO3\ORQVDORQJZLWKLWVGHSHQGHQFLHVUXQ
WKHIROORZLQJFRPPDQGV
virtualenv --no-site-packages myenv
cd myenv
source bin/activate
easy_install pylons

1RZZHKDYH3\ORQVLQVWDOOHGLQDYLUWXDOHQYLURQPHQW&UHDWHDQRWKHUGLUHFWRU\QDPHG
ZKDWHYHU\RXOLNHLQZKLFKWRFUHDWH\RXU3\ORQV[SURMHFWFKDQJH\RXUZRUNLQJ
GLUHFWRU\WRLWWKHQH[HFXWH
paster create -t pylons

<RXZLOOEHSURPSWHGWRHQWHUDQDPHIRU\RXUSURMHFWDORQJZLWKZKLFKWHPSODWH
HQJLQH\RXZDQWWRXVHDQGZKHWKHURUQRW\RXZDQWWKH64/$OFKHP\2EMHFW5HOD
WLRQDO0DSSHU 250 7KHGHIDXOWV £PDNR¤IRUWHPSODWLQJHQJLQH)DOVHWR64/$O
FKHP\ DUHILQHIRURXUSXUSRVHV¢QRWOHDVWVLQFHZHDUHGHPRQVWUDWLQJD1R64/GD
WDEDVH
$IWHU,UDQWKHpaster createFRPPDQGD£S\ORQVIRR¤GLUHFWRU\ ,FKRVH£S\ORQVIRR¤
DVP\SURMHFWQDPH ZDVFUHDWHGZLWKWKHIROORZLQJFRQWHQWV
MANIFEST.in
README.txt
development.ini
docs
ez_setup.py
pylonsfoo
pylonsfoo.egg-info
setup.cfg
setup.py
test.ini

1H[W\RXQHHGWRDGGWKH3\0RQJRGULYHUDVDGHSHQGHQF\IRU\RXUSURMHFW&KDQJH
\RXUZRUNLQJGLUHFWRU\WRWKHMXVWFUHDWHGGLUHFWRU\QDPHGDIWHU\RXUSURMHFW2SHQ
WKH setup.py ILOH SUHVHQW LQ LW ZLWK \RXU IDYRXULWH HGLWRU &KDQJH WKH
install_requiresOLVWWRLQFOXGHWKHVWULQJ pymongo<RXUILOHVKRXOGORRNVRPHWKLQJ
OLNHWKLV
try:
from setuptools import setup, find_packages
except ImportError:
from ez_setup import use_setuptools
use_setuptools()
from setuptools import setup, find_packages

setup(
name='pylonsfoo',
version='0.1',

46 | Chapter 4:ಗMongoDB with Web Frameworks

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
description='',
author='',
author_email='',
url='',
install_requires=[
"Pylons>=1.0", "pymongo",
],
setup_requires=["PasteScript>=1.6.3"],
packages=find_packages(exclude=['ez_setup']),
include_package_data=True,
test_suite='nose.collector',
package_data={'pylonsfoo': ['i18n/*/LC_MESSAGES/*.mo']},
#message_extractors={'pylonsfoo': [
# ('**.py', 'python', None),
# ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
# ('public/**', 'ignore', None)]},
zip_safe=False,
paster_plugins=['PasteScript', 'Pylons'],
entry_points="""
[paste.app_factory]
main = pylonsfoo.config.middleware:make_app

[paste.app_install]
main = pylons.util:PylonsInstaller
""",
)

1RZ\RXQHHGWRIHWFKWKH3\0RQJRGULYHULQWR\RXUYLUWXDOHQYLURQPHQW,WLVHDV\WR
GRWKLVE\H[HFXWLQJ
python setup.py develop

<RXU3\ORQVDSSLVQRZUHDG\WREHFRQILJXUHGZLWKD0RQJR'%FRQQHFWLRQ)LUVWZH
VKDOOFUHDWHDFRQILJILOHIRUGHYHORSPHQW
cp development.ini.sample development.ini

1H[WRSHQWKHILOH development.iniLQ\RXUIDYRXULWHHGLWRU8QGHUQHDWKWKHVHFWLRQ
[app:main]DGGWKHIROORZLQJWZRYDULDEOHVFKDQJLQJWKH85,DQGGDWDEDVHQDPHVWR
ZKDWHYHUZRUNVIRU\RXUVHWXS
mongodb.url = mongodb://localhost
mongodb.db_name = mydb

<RXFDQQRZWU\VWDUWLQJ\RXUSURMHFWZLWKWKHIROORZLQJFRPPDQG
paster serve --reload development.ini

<RXVKRXOGVHHWKHIROORZLQJRXWSXW
Starting subprocess with file monitor
Starting server in PID 82946.
serving on http://127.0.0.1:5000

,I\RXRSHQWKH85/KWWSORFDOKRVWLQDZHEEURZVHU\RXVKRXOGVHHWKHGHIDXOW
3\ORQVSDJH7KLVPHDQVWKDW\RXKDYHFRUUHFWO\VHWXS\RXUSURMHFW+RZHYHUZHGR
QRW\HWKDYHDZD\WRWDONWR0RQJR'%

Pylons 1.x and MongoDB | 47

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
1RZWKDWWKHFRQILJXUDWLRQLVLQSODFHZHFDQWHOO3\ORQVKRZWRFRQQHFWWR0RQJR'%
DQGZKHUHWRPDNHWKH3\0RQJRFRQQHFWLRQDYDLODEOHWRRXUDSSOLFDWLRQ3\ORQVSUR
YLGHVDFRQYHQLHQWSODFHIRUWKLVLQ <project_name>/lib/app_globals.py(GLWWKLVILOH
DQGFKDQJHWKHFRQWHQWVWRWKHIROORZLQJ
from beaker.cache import CacheManager
from beaker.util import parse_cache_config_options
from pymongo import Connection
from pylons import config

class Globals(object):
"""Globals acts as a container for objects available throughout the
life of the application

"""

def __init__(self, config):


"""One instance of Globals is created during application
initialization and is available during requests via the
'app_globals' variable

"""
mongodb_conn = Connection(config['mongodb.url'])
self.mongodb = mongodb_conn[config['mongodb.db_name']]
self.cache = CacheManager(**parse_cache_config_options(config))

2QFHWKLVKDVEHHQVHWXSD3\0RQJRDatabaseLQVWDQFHZLOOEHDYDLODEOHWR\RXU3\ORQV
FRQWUROOHUDFWLRQVWKURXJKWKHJOREDOVREMHFW7RGHPRQVWUDWHZHZLOOFUHDWHDQHZ
FRQWUROOHUQDPHG£PRQJRGE¤ZLWKWKHIROORZLQJFRPPDQG
paster controller mongodb

<RXVKRXOGVHHDILOHQDPHGPRQJRGES\LQWKH<project_name>/controllersGLUHFWRU\
)RUGHPRQVWUDWLRQSXUSRVHVZHVKDOOPRGLI\LWWRLQFUHPHQWDFRXQWHUGRFXPHQWLQ
0RQJR'%HYHU\WLPHWKHFRQWUROOHUDFWLRQLVUXQ
2SHQWKLVILOHZLWK\RXUHGLWRU0RGLI\LWWRORRNOLNHWKHIROORZLQJ UHPHPEHULQJWR
FKDQJHWKHfrom pylonsfooLPSRUWOLQHLQWRZKDWHYHU\RXQDPHG\RXUSURMHFW 
import logging

from pylons import app_globals as g, request, response, session, tmpl_context as c, url


from pylons.controllers.util import abort, redirect

from pylonsfoo.lib.base import BaseController, render

log = logging.getLogger(__name__)

class MongodbController(BaseController):

def index(self):
new_doc = g.mongodb.counters.find_and_modify({"counter_name":"test_counter"},
{"$inc":{"counter_value":1}}, new=True, upsert=True , safe=True)
return "MongoDB Counter Value: %s" % new_doc["counter_value"]

48 | Chapter 4:ಗMongoDB with Web Frameworks

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
2QFH\RXKDYHVDYHGWKHVHFKDQJHVLQDZHEEURZVHURSHQWKH85/KWWSORFDOKRVW
PRQJRGELQGH[(DFKWLPH\RXORDGWKLVSDJH\RXVKRXOGVHHDGRFXPHQWLQWKH
FRXQWHUVFROOHFWLRQEHXSGDWHGZLWKLWVcounter_valueSURSHUW\LQFUHPHQWHGE\

Pyramid and MongoDB


3\UDPLGLVDQXQRSLQLRQDWHGZHEIUDPHZRUNZKLFKUHVXOWHGIURPWKHPHUJHRIWKH
repoz.bfgIUDPHZRUNLQWRWKH3\ORQVXPEUHOODSURMHFW QRWWREHFRQIXVHGZLWK3\ORQV
[WKHZHEIUDPHZRUN 3\UDPLGFDQEHFRQVLGHUHGWREHDELWOLNHD3\ORQVLWLV
DFOHDQEUHDNDFRPSOHWHO\QHZFRGHEDVHZLWKQRFRGHOHYHOEDFNZDUGVFRPSDWLELOLW\
ZLWK3\ORQV[
+RZHYHUPDQ\RIWKHFRQFHSWVDUHYHU\VLPLODUWRWKHROGHU3\ORQV[3\UDPLGLV
ZKHUHDOOWKHQHZGHYHORSPHQWLVKDSSHQLQJDQGLWKDVIDQWDVWLFFRGHWHVWFRYHUDJH
DQGGRFXPHQWDWLRQ7KLVVHFWLRQLVRQO\LQWHQGHGWREHDEULHILQWURGXFWLRQWRVHWWLQJ
XSD3\UDPLGSURMHFWZLWKD0RQJR'%FRQQHFWLRQ7ROHDUQPRUHUHIHUWRWKHH[FHOOHQW
3\UDPLGERRNDQGRWKHUUHVRXUFHVDYDLODEOHIUHHRQOLQHDWKWWSGRFVS\ORQVSURMHFWRUJ
2QLWVRZQ3\UDPLGLVMXVWDIUDPHZRUNDVHWRIOLEUDULHV\RXFDQXVH3URMHFWVDUH
PRVW HDVLO\ VWDUWHG IURP D ZKDW LV NQRZQ DV D VFDIIROG $ VFDIIROG LV OLNH D SURMHFW
VNHOHWRQZKLFKVHWVXSSOXPELQJDQGSODFHKROGHUVIRU\RXUFRGH
$QXPEHURIGLIIHUHQWVFDIIROGVDUHLQFOXGHGZLWK3\UDPLGRIIHULQJGLIIHUHQWSHUVLVWHQFH
RSWLRQV85/PDSSHUVDQGVHVVLRQLPSOHPHQWDWLRQV&RQYHQLHQWO\HQRXJKWKHUHLVD
VFDIIROGFDOOHGpyramid_mongodbZKLFKZLOOEXLOGRXWDVNHOHWRQSURMHFWZLWK0RQJR'%
VXSSRUWIRU\RX pyramid_mongodbHOLPLQDWHVWKHQHHGIRU\RXWRZRUU\DERXWZULWLQJ
WKHJOXHFRGHWRPDNHD0RQJR'%FRQQHFWLRQDYDLODEOHIRUUHTXHVWSURFHVVLQJLQ3\U
DPLG
$VZLWK3\ORQV[WRVWDUWXVLQJ3\UDPLG\RXILUVWQHHGWRFUHDWHDYLUWXDOHQYLURQPHQW
IRU\RXUSURMHFW7KHVHLQVWUXFWLRQVDVVXPH\RXKDYHWKHvirtualenvWRROLQVWDOOHGRQ
\RXUV\VWHP,QVWDOOLQVWUXFWLRQVIRUWKHvirtualenvWRRODUHSURYLGHGLQWKHILUVWFKDSWHU
RIWKLVERRN
7RFUHDWHWKHYLUWXDOHQYLURQPHQWDQGLQVWDOO3\UDPLGDQGLWVGHSHQGHQFLHVUXQWKH
IROORZLQJFRPPDQGV
virtualenv --no-site-packages myenv
cd myenv
source bin/activate
easy_install pyramid

7DNHQRWHRIWKHOLQHVRXUFLQJWKHbin/activateVFULSW,WLVLPSRUWDQWWRUHPHPEHUWR
GRWKLVRQFHLQHYHU\VKHOOWRPDNHWKHYLUWXDOHQYLURQPHQWDFWLYH:LWKRXWWKLVVWHS
\RXUGHIDXOWV\VWHP3\WKRQLQVWDOOZLOOEHLQYRNHGZKLFKGRHVQRWKDYH3\UDPLGLQ
VWDOOHG

Pyramid and MongoDB | 49

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
1RZ\RXUYLUWXDOHQYLURQPHQWKDV3\UDPLGDQGDOOLWVGHSHQGHQFLHVLQVWDOOHG+RZ
HYHU\RXVWLOOQHHG pyramid_mongodbDQGLWVGHSHQGHQFLHVOLNH3\0RQJRHWF5XQWKH
IROORZLQJFRPPDQGWRLQVWDOOpyramid_mongodbLQ\RXUYLUWXDOHQYLURQPHQW
easy_install pyramid_mongodb

:LWK3\DPLGDQGpyramid_mongodbLQVWDOOHGLQ\RXUYLUWXDOHQYLURQPHQW\RXDUHUHDG\
WRFUHDWHD3\UDPLGSURMHFWZLWK0RQJR'%VXSSRUW'HFLGHXSRQDSURMHFWGLUHFWRU\
DQGDSURMHFWQDPH)URPWKDWSURMHFWGLUHFWRU\H[HFXWHLQWKHVKHOO
paster create -t pyramid_mongodb <project_name>

$IWHU,UDQWKHpaster createFRPPDQGD£PRQJRIRR¤GLUHFWRU\ ,FKRVH£PRQJRIRR¤


DVP\SURMHFWQDPH ZDVFUHDWHGZLWKWKHIROORZLQJFRQWHQWV
README.txt
development.ini
mongofoo
mongofoo.egg-info
production.ini
setup.cfg
setup.py

7KHGHIDXOWFRQILJXUDWLRQILOHVWHOO3\UDPLGWRFRQQHFWWRD0RQJR'%VHUYHURQlocal
hostDQGDGDWDEDVHFDOOHG£P\GE¤,I\RXQHHGWRFKDQJHWKDWVLPSO\HGLWWKH mon
godb.urlDQGmongodb.db_nameVHWWLQJVLQWKH,1,ILOHV1RWHWKDWLI\RXGRQRWKDYHD
0RQJR'%VHUYHUUXQQLQJDWWKHDGGUHVVFRQILJXUHGLQWKH,1,ILOH\RXU3\UDPLGSURMHFW
ZLOOIDLOWRVWDUW
%HIRUH\RXFDQUXQRUWHVW\RXUDSS\RXQHHGWRH[HFXWH
python setup.py develop

7KLVZLOOHQVXUHDQ\DGGLWLRQDOGHSHQGHQFLHVDUHLQVWDOOHG7RUXQ\RXUSURMHFWLQGHEXJ
PRGHVLPSO\H[HFXWH
paster serve --reload development.ini

,IDOOZHQWZHOO\RXVKRXOGVHHRXWSXWOLNHWKHIROORZLQJ
Starting subprocess with file monitor
Starting server in PID 54019.
serving on 0.0.0.0:6543 view at http://127.0.0.1:6543

<RX FDQ QRZ RSHQ KWWSORFDOKRVW LQ D ZHE EURZVHU DQG VHH \RXU 3\UDPLG
SURMHFWZLWKWKHGHIDXOWWHPSODWH,I\RXPDGHLWWKLVIDU3\UDPLGLVFRUUHFWO\LQVWDOOHG
DQG pyramid_mongodb ZDV DEOH WR VXFFHVVIXOO\ FRQQHFW WR WKH FRQILJXUHG 0RQJR'%
VHUYHU
7KHpyramid_mongodbVFDIIROGVHWVXS\RXU3\UDPLGSURMHFWLQVXFKDZD\WKDWWKHUHLV
D3\0RQJR DatabaseREMHFWDWWDFKHGWRHDFK requestREMHFW7RGHPRQVWUDWHKRZWR
XVHWKLVRSHQWKHILOH<project_name>/views.pyLQ\RXUIDYRXULWHHGLWRU7KHUHVKRXOG
EHDVNHOHWDO3\WKRQIXQFWLRQQDPHGmy_view

50 | Chapter 4:ಗMongoDB with Web Frameworks

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
def my_view(request):
return {'project':'mongofoo'}

7KLVLVDYHU\VLPSOH3\UDPLGYLHZFDOODEOH3\UDPLGYLHZFDOODEOHVDUHVLPLODUWRFRQ
WUROOHUDFWLRQVLQ3\ORQV[DQGDUHZKHUHPXFKRIWKHDSSOLFDWLRQGHILQHGUHTXHVW
SURFHVVLQJRFFXUV6LQFHYLHZFDOODEOHVDUHSDVVHGDQLQVWDQFHRIDrequestREMHFWZKLFK
LQWXUQKDVDSURSHUW\FRQWDLQLQJWKH3\0RQJR DatabaseREMHFWWKLVLVDQLGHDOSODFH
WRLQWHUDFWZLWK0RQJR'%
,PDJLQHDVRPHZKDWFRQWULYHGH[DPSOHZKHUHE\ZHZLVKWRLQVHUWDGRFXPHQWLQWRD
FROOHFWLRQFDOOHG£SDJHBKLWV¤HDFKWLPHWKHmy_viewYLHZFDOODEOHLVH[HFXWHG:HFRXOG
GRWKHIROORZLQJ
import datetime
def my_view(request):
new_page_hit = {"timestamp":datetime.datetime.utcnow(), "url":request.url}
request.db.page_hits.insert(new_page_hit, safe=True)
return {"project":"mongofoo"}

,I\RXQRZUHORDGWKHZHESDJHDWKWWSORFDOKRVW\RXVKRXOGVHHDFROOHFWLRQ
FDOOHG£SDJHBKLWV¤LQWKH0RQJR'%GDWDEDVH\RXFRQILJXUHGLQ\RXU,1,ILOH,QWKLV
FROOHFWLRQWKHUHVKRXOGEHDVLQJOHGRFXPHQWIRUHDFKWLPHWKHYLHZKDVEHHQFDOOHG
)URPKHUH\RXVKRXOGEHZHOORQ\RXUZD\WREXLOGLQJZHEDSSOLFDWLRQVZLWK3\UDPLG
DQG0RQJR'%

Django and MongoDB


'MDQJRLVSURDEDEO\WKHPRVWZLGHO\XVHG3\WKRQZHEIUDPHZRUN,WKDVDQH[FHOOHQW
FRPPXQLW\DQGPDQ\SOXJLQVDQGH[WHQVLRQPRGXOHV7KH'MDQJRSKLORVRSK\LVWKH
RSSRVLWHRI3\ORQVRU3\UDPLGLWRIIHUVRQHZHOOLQWHJUDWHGSDFNDJHLQFOXGLQJLWVRZQ
GDWDEDVHDQG250OD\HUWHPSODWLQJV\VWHP85/PDSSHUDGPLQLQWHUIDFHDQGVRRQ
7KHUHDUHDQXPEHURIRSWLRQVIRUUXQQLQJ'MDQJRZLWK0RQJR'%6LQFHWKH'MDQJR
250LVVXFKDQLQWHJUDOSDUWRI'MDQJRWKHUHLVDSURMHFWNQRZQDV'MDQJR0RQJR'%
(QJLQHZKLFKDWWHPSWVWRSURYLGHD0RQJR'%EDFNHQGIRUWKH'MDQJR250+RZHYHU
WKLVDSSURDFKKHDYLO\DEVWUDFWVWKHXQGHUO\LQJTXHU\ODQJXDJHDQGGDWDPRGHODORQJ
ZLWKPDQ\RIWKHORZOHYHOGHWDLOVGLVFXVVHGLQWKHFRXUVHRIWKHERRN,I\RXDUHDOUHDG\
IDPLOLDUZLWKWKH'MDQJR250HQMR\XVLQJLWDQGDUHZLOOLQJWRXVHDIRUNRI'MDQJR
'MDQJR0RQJR'%(QJLQHLVZRUWKDORRN<RXFDQILQGPRUHLQIRUPDWLRQDWWKHZHEVLWH
KWWSGMDQJRPRQJRGERUJ
2XU UHFRPPHQGHG DSSURDFK IRU QRZ LV WR XVH WKH 3\0RQJR GULYHU GLUHFWO\ ZLWK
'MDQJR %H DZDUH KRZHYHU WKDW ZLWK WKLV PHWKRG WKH 'MDQJR FRPSRQHQWV ZKLFK
GHSHQGRQWKH'MDQJR250 DGPLQLQWHUIDFHVHVVLRQVWRUHHWF ZLOOQRWZRUNZLWK
0RQJR'%7KHUHLVDQRWKHUSURMHFWFDOOHG0DQJRZKLFKDWWHPSWVWRSURYLGH0RQ
JR'%EDFNHGVHVVLRQDQGDXWKHQWLFDWLRQVXSSRUWIRU'MDQJR<RXFDQILQG0DQJRDW
KWWSVJLWKXEFRPYSXOLPPDQJR

Django and MongoDB | 51

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
JHQKDYHPDGHDVDPSOH'MDQJRDSSZLWK3\0RQJRLQWHJUDWLRQDYDLODEOH7KLVVDP
SOHDSSFDQEHIRXQGDWKWWSVJLWKXEFRPPGLUROI'MDQ0RQ:HVKDOOVWHSWKURXJK
UXQQLQJWKHVDPSOH'MDQJR0RQJR'%DSSRQ\RXUORFDOPDFKLQHDQGH[DPLQHKRZ
LWVHWVXSWKH0RQJR'%FRQQHFWLRQ
)LUVWGRZQORDGWKHVDPSOH'MDQJRSURMHFW,I\RXDOUHDG\KDYHWKHJLWFRPPDQGOLQH
WRROVLQVWDOOHG\RXFDQUXQgit clone https://github.com/mdirolf/DjanMon.git2WK
HUZLVHVLPSO\FOLFNWKH£'RZQORDG¤EXWWRQDWKWWSVJLWKXEFRPPGLUROI'MDQ0RQ
,QRUGHUWRVXFFHVVIXOO\UXQWKHVDPSOHDSS\RXZLOOQHHGWREXLOGD3\WKRQYLUWXDO
HQYLURQPHQWZLWK'MDQJRS\PRQJRDQG3,/LQVWDOOHG$VZLWK3\ORQVDQG3\UDPLG
\RXZLOOILUVWQHHGWRKDYHWKHvirtualenvWRROLQVWDOOHGRQ\RXUV\VWHP¢GHWDLOVRQKRZ
WR GR WKLV DUH FRYHUHG LQ WKH ILUVW FKDSWHU RI WKLV ERRN 2QFH \RX KDYH virtualenv
LQVWDOOHGFKRVHDGLUHFWRU\LQZKLFKWRVWRUHYLUWXDOHQYWKHQH[HFXWHWKHIROORZLQJ
VKHOOFRPPDQGVLQLW
virtualenv --no-site-packages djangoenv
cd djangoenv
source bin/activate
pip install django pymongo PIL

7KLVZLOOFUHDWH\RXUYLUWXDOHQYLURQPHQWDFWLYDWHLWDQGWKHQLQVWDOO'MDQJRWKH3\
0RQJRGULYHUDQGWKH3,/LPDJHPDQLSXODWLRQOLEUDU\ UHTXLUHGE\WKHGHPRDSS LQWR
LW$VVXPLQJWKLVDOOVXFFHHGHG\RXDUHUHDG\WRVWDUWWKHVDPSOHDSSGHYHORSPHQW
VHUYHU1RWHWKDWWKHVDPSOHDSSH[SHFWVD0RQJR'%VHUYHUWREHUXQQLQJRQlocalhost
1RZZHFDQUXQJHQ¦V'MDQJRGHPRQVWUDWLRQDSS&KDQJH\RXUFXUUHQWZRUNLQJ
GLUHFWRU\WR\RXUFRS\RIWKH£'MDQ0RQ¤SURMHFW7KHUHVKRXOGEHDILOHFDOOHG man
age.pyLQWKHFXUUHQWZRUNLQJGLUHFWRU\7KHDSSFDQEHUXQZLWKWKH'MDQJRGHYHORS
PHQWVHUYHUZLWKWKHFRPPDQG
python manage.py runserver

<RXVKRXOGVHHRXWSXWRQWKHFRQVROHOLNHWKHIROORZLQJ
Validating models...

0 errors found
Django version 1.3, using settings 'DjanMon.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

1RZ\RXFDQRSHQDZHEEURZVHUDQGYLVLWKWWSORFDOKRVWDQGVHHWKHGHPRQ
VWUDWLRQDSS7KHDSSOHWV\RXFUHDWHVLPSOHPHVVDJHV RSWLRQDOO\ZLWKDWWDFKHGLPDJHV
ZKLFKDUHSHUVLVWHGLQ0RQJR'%
/HWXVH[DPLQHKRZWKHVDPSOHDSSZRUNV7DNHDORRNDWWKHILOHstatus/view.py7KLV
LVZKHUHWKH0RQJR'%FRQQHFWLRQLVFUHDWHGDQGZKHUHPRVWRIWKHDSSOLFDWLRQORJLF
LVVWRUHG,QWKHLU'MDQJR0RQJR'%LQWHJUDWLRQH[DPSOHJHQWDNHDGLIIHUHQWDS
SURDFKIURPWKHRWKHUVRXWOLQHGLQWKLVFKDSWHU7KH\FUHDWHD3\0RQJR DatabaseLQ

52 | Chapter 4:ಗMongoDB with Web Frameworks

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
WKHJOREDOVFRSHRIWKHYLHZVPRGXOHUDWKHUWKDQDWWDFKLQJLWWRUHTXHVWREMHFWVDVLQ
3\UDPLGRUPDNLQJLWDIUDPHZRUNZLGHJOREDODVLQ3\ORQV[
import datetime
import string
import random
import mimetypes
import cStringIO as StringIO

from PIL import Image


from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from pymongo.connection import Connection
from pymongo import DESCENDING
import gridfs

db = Connection().sms

7KLVDSSURDFKLVVLPSOHDQGZRUNVILQHIRUDGHPR+RZHYHULQODUJHU'MDQJRSURMHFWV
ZLWKPXOWLSOHLQVWDOOHGDSSOLFDWLRQV LQWKLVVDPSOHWKHUHLVDVLQJOHLQVWDOOHGDSS¢LW
LVQDPHG£VWDWXV¤ WKLVZRXOGUHTXLUHDVHSDUDWH3\0RQJRFRQQHFWLRQSRROWREHPDLQ
WDLQHGIRUHDFKDSS7KLVUHVXOWVLQZDVWHG0RQJR'%FRQQHFWLRQVDQGGXSOLFDWHGFRGH
,QVWHDGLWZRXOGEHUHFRPPHQGHGWRFUHDWHWKHFRQQHFWLRQLQDVLQJOHSODFHDQGLPSRUW
LWLQDQ\RWKHUPRGXOHVZKLFKQHHGDFFHVV
7KLVVKRXOGEHHQRXJKLQIRUPDWLRQWRJHW\RXVWDUWHGEXLOGLQJ\RXU'MDQJR0RQJR'%
DSSOLFDWLRQ

Going Further
,QWKLVERRNZHKDYHWULHGWRJLYH\RXDVROLGJUDVSRIKRZWROHYHUDJH0RQJR'%LQ
UHDOZRUOGDSSOLFDWLRQV<RXVKRXOGKDYHDGHFHQWXQGHUVWDQGLQJRIKRZWRJRDERXW
PRGHOLQJ\RXUGDWDZULWLQJHIIHFWLYHTXHULHVDQGDYRLGLQJFRQFXUUHQF\SUREOHPVVXFK
DVUDFHFRQGLWLRQVDQGGHDGORFNV7KHUHDUHDQXPEHURIRWKHUDGYDQFHGWRSLFVZKLFK
ZHGLGQ¦WKDYHVSDFHIRULQWKLVERRNEXWDUHQRQHWKHOHVVZRUWKORRNLQJLQWRDV\RX
EXLOG\RXUDSSOLFDWLRQ1RWDEO\PDSUHGXFHHQDEOHVFRPSXWLQJDJJUHJDWHVHIILFLHQWO\
6KDUGLQJSHUPLWV\RXWRVFDOH\RXUDSSOLFDWLRQEH\RQGWKHDYDLODEOHPHPRU\RIDVLQJOH
PDFKLQH*ULG)6DOORZV\RXWRVWRUHELQDU\GDWDLQ0RQJR'%&DSSHG&ROOHFWLRQVDUH
DVSHFLDOW\SHRIFROOHFWLRQZKLFKORRNOLNHDFLUFXODUEXIIHUDQGDUHJUHDWIRUORJGDWD
:LWKWKHVHIHDWXUHVDW\RXUGLVSRVDO3\WKRQDQG0RQJR'%DUHH[WUHPHO\SRZHUIXO
WRROVWRKDYHLQ\RXUWRROER[ZKHQGHYHORSLQJDQDSSOLFDWLRQ

Going Further | 53

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
About the Author
1LDOO2¦+LJJLQVLVDVRIWZDUHFRQVXOWDQWVSHFLDOL]LQJLQPRELOHWDEOHWDQGFORXGFRP
SXWLQJ+LVDFFRPSOLVKPHQWVLQFOXGHGHVLJQLQJDQGLPSOHPHQWLQJWKH&DWFKFRPSODW
IRUPEDFNHQGXVLQJ0RQJR'%3\WKRQDQG3\ORQV&DWFKLVRQHRIWKHPRVWSRSXODU
DSSVRQ$QGURLG3ULRUWR&DWFKKHZDVDVRIWZDUHHQJLQHHUDW0HWDZHE7HFKQRORJLHV
ZKHUHKHZRUNHGRQ)UHHEDVHFRP QRZRZQHGE\*RRJOH +HLVWKHIRXQGHUDQG
RUJDQL]HURIERWKWKH6DQ)UDQFLVFR3\WKRQ:HE7HFKQRORJ\0HHWXS3\:HE6)DQG
WKH%D\$UHD7DEOHW&RPSXWLQJ*URXS:H+DYH7DEOHWV+HKDVSXEOLVKHGTXLWHD
ELW RI 2SHQ 6RXUFH VRIWZDUH¢FRQWULEXWLQJ WR 2SHQ%6' DPRQJ RWKHUV¢DQG IUH
TXHQWO\VSHDNVDWFRQIHUHQFHVDQGHYHQWV<RXFDQILQGKLPRQ7ZLWWHUDV#QLDOORKLJ
JLQV

|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/
|||||||||||||||||||||||||||||||||||||||||||||||||
http://www.freepdf-books.com/

You might also like