Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MongoDB in Symfony2 with Doctrine

1768d238acf404dadd501ba424d65bfd?s=47 dknx01
December 09, 2015

MongoDB in Symfony2 with Doctrine

1768d238acf404dadd501ba424d65bfd?s=128

dknx01

December 09, 2015
Tweet

Transcript

  1. How to use MongoDB in Symfony 2 with Doctrine by

    dknx01 (dknx01@yahoo.de) February 26, 2016 1
  2. Contents 1 Requirements 3 2 The folder structure 4 2.1

    'Document' Folder . . . . . . . . . . . . . . . . . . . . . . . . 5 2.2 'Subdocument' Folder . . . . . . . . . . . . . . . . . . . . . . . 5 2.3 Repository . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 3 Cong 6 4 Documents 7 4.1 Use statements . . . . . . . . . . . . . . . . . . . . . . . . . . 7 4.2 (Sub)Document annotation . . . . . . . . . . . . . . . . . . . 7 4.2.1 Document . . . . . . . . . . . . . . . . . . . . . . . . . 7 4.2.2 Subdocument . . . . . . . . . . . . . . . . . . . . . . . 7 4.3 Property annotations . . . . . . . . . . . . . . . . . . . . . . . 7 4.3.1 Mongo ObjectId . . . . . . . . . . . . . . . . . . . . . 7 4.3.2 Unique elds . . . . . . . . . . . . . . . . . . . . . . . 8 4.3.3 Strings and Integer elds . . . . . . . . . . . . . . . . . 8 4.3.4 DateTime elds . . . . . . . . . . . . . . . . . . . . . . 9 4.3.5 Boolean elds . . . . . . . . . . . . . . . . . . . . . . . 9 4.3.6 Subdocument elds . . . . . . . . . . . . . . . . . . . . 9 4.3.7 Array elds . . . . . . . . . . . . . . . . . . . . . . . . 9 4.4 The whole document class . . . . . . . . . . . . . . . . . . . . 10 4.5 The whole embedded document class . . . . . . . . . . . . . . 13 4.6 Example Entry . . . . . . . . . . . . . . . . . . . . . . . . . . 16 5 Repository 17 5.1 Saving a document . . . . . . . . . . . . . . . . . . . . . . . . 17 5.2 Find by a eld . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 5.3 Find with limit, skipping, sorting and one condition - part 1 . 17 5.4 Find with limit, skipping, sorting and one condition - part 2 . 18 5.5 Get last inserted entry . . . . . . . . . . . . . . . . . . . . . . 19 5.6 Get all entries based on one eld value . . . . . . . . . . . . . 19 5.7 The whole repository class . . . . . . . . . . . . . . . . . . . . 20 A Appendix 23 February 26, 2016 2 c dknx01
  3. 1 Requirements For using MongoDb in Symfony with the help

    of Doctrine ORM wie need at least the following libraries: • PHP: >=5.3.9 • MongoDB Server • Symfony: >=2.7 • Doctrine: 2.4.8 • Doctrine MongoDB-ODM: 1.0.3 • Doctrine MongoDB-ODM-Bundle: 3.1.x-dev For installation use composer and your prefered os package manager (e.g. apt-get). In this tutorial we try to parse the Twitter timeline API JSON and save some data in our MongoDB. February 26, 2016 3 c dknx01
  4. 2 The folder structure In our typical Symfony2 application we

    have a folder structure like this (ex- cluding the framework folders like vendor, web etc.): APPROOT app cong cong.yml ... src AppBundle ... Document Subdocument OriginalData.php TwitterEntry.php Repository TwitterRepository.php You can see that we've nearly a normal structure with a folder for service and repository. But instead of "Entity" we've a folder called "Document" (the MongoDB equivalent for a table) and one called "Subdocument" (a document inside an other document). February 26, 2016 4 c dknx01
  5. 2.1 'Document' Folder Inside this folder are all are PHP

    classes, that represent the MongoDB doc- uments. 2.2 'Subdocument' Folder If the MongoDB document has a eld that contains another document I put them into this folder, but that's not necessary it could be also another document. 2.3 Repository Here are all repositories for working (query, update, insert) a document. February 26, 2016 5 c dknx01
  6. 3 Cong To use MongoDB with Doctrine we need a

    separate connection and therefore an extra conguration. 1 # Doctrine Configuration 2 doctrine: 3 dbal: 4 # NORMAL CONFIGURATION E . G . MySQL 5 doctrine_mongodb: 6 connections: 7 default: 8 server: mongodb:// l o c a l h o s t :27017 9 options: { username: " % mongodb_user % " , p as sw or d : " % mongodb_password % " } 10 default_database: t e s t 11 document_managers: 12 default: 13 auto_mapping: ' true ' Listing 1: Cong connection February 26, 2016 6 c dknx01
  7. 4 Documents This section shows how a document will look

    like. We try to parse the Twitter timeline API JSON response into our database. The whole class including the Setter and Getter methods can be seen in section 4.4. The whole subdocument can be seen in section 4.5. 4.1 Use statements We has to use MongoDb-Mapping-Annotation, so that Doctrine knows how to map PHP behaviour into MongoDB. 1 use Doctrine \ODM\MongoDB\Mapping\ Annotations as MongoDB; Listing 2: Needed annotation 4.2 (Sub)Document annotation 4.2.1 Document Doctrine has to know that this class is a MongoDB document and to which repository it belong, if we had one. 1 /∗∗ 2 ∗ @MongoDB\Document( repositoryClass="TwitterBundle\ Repository \ TwitterRepository ") 3 ∗/ Listing 3: Document annotation 4.2.2 Subdocument Doctrine has to know that this class is a MongoDB subdocument. 1 /∗∗ 2 ∗ @MongoDB\EmbeddedDocument 3 ∗/ Listing 4: Subdocument annotation 4.3 Property annotations 4.3.1 Mongo ObjectId Each objeect in MongoDB has it's own unique object id, which we should use to reference to it (like a primary key). So we tell Doctrine that this property February 26, 2016 7 c dknx01
  8. is a string in Mongo (line 3), an ObjectId (line

    4), to map it on eld '_id' (line 5) and to let the database take care about how to generate it (line 5). 1 /∗∗ 2 ∗ @var s t r i n g 3 ∗ @MongoDB\ String 4 ∗ @MongoDB\ ObjectId 5 ∗ @MongoDB\Id (name="_id " , strategy="Auto") 6 ∗/ 7 protected $id ; Listing 5: Object_Id annotations 4.3.2 Unique elds We have a eld that contains unique value. So Doctrine has to know about the data type string (line 3) and that it is an unique id (line 4). The eld name is the same as the property name. 1 /∗∗ 2 ∗ @var s t r i n g 3 ∗ @MongoDB\ String 4 ∗ @MongoDB\UniqueIndex 5 ∗/ 6 protected $twitterId ; Listing 6: Unique eld annotations 4.3.3 Strings and Integer elds We have one eld that contains normal strings and one that contains normal integer values. The eld name is the same as the property name. 1 /∗∗ 2 ∗ @var s t r i n g 3 ∗ @MongoDB\ String 4 ∗/ 5 protected $text ; 6 7 /∗∗ 8 ∗ @var int 9 ∗ @MongoDB\ Int 10 ∗/ 11 protected $retweetCount ; Listing 7: String and integer eld annotations February 26, 2016 8 c dknx01
  9. 4.3.4 DateTime elds We have one eld that contains a

    PHP DateTime object that should (or bet- ter must) be save as an MongoDate object inside MongoDB. All conversion are made by the driver. The eld name is the same as the property name. 1 /∗∗ 2 ∗ @var DateTime 3 ∗ @MongoDB\Date 4 ∗/ 5 protected $createdAt ; Listing 8: DateTime eld annotations 4.3.5 Boolean elds We have one eld that contains a boolean value. If this value is NULL it's also treated like false and a null or not set value in the database is treated like false. The eld name is the same as the property name. 1 /∗∗ 2 ∗ @var boolean 3 ∗ @MongoDB\Boolean 4 ∗/ 5 protected $pinned ; Listing 9: Boolean eld annotations 4.3.6 Subdocument elds We have one eld holds a lot of other data or in other word that is an object inside this one. These are called subdocuments an represented like an external object (line 3). The eld name is the same as the property name. 1 /∗∗ 2 ∗ @var OriginalData 3 ∗ @MongoDB\EmbedOne( targetDocument="TwitterBundle\Document\ Subdocument\ OriginalData ") 4 ∗/ 5 protected $originalData ; Listing 10: Subdocument annotations 4.3.7 Array elds In the subdocument we've one eld that holds an array. This eld can be used in PHP like a normal array. So we can store multiple values for one eld. February 26, 2016 9 c dknx01
  10. 1 /∗∗ 2 ∗ @var array 3 ∗ @MongoDB\ Collection

    4 ∗/ 5 protected $mentions = array () ; Listing 11: Array annotations 4.4 The whole document class 1 <?php 2 3 namespace TwitterBundle\Document ; 4 5 use TwitterBundle\Document\Subdocument\ OriginalData ; 6 use DateTime ; 7 use Doctrine \ODM\MongoDB\Mapping\ Annotations as MongoDB; 8 9 /∗∗ 10 ∗ @MongoDB\Document( repositoryClass="TwitterBundle\ Repository \ TwitterRepository ") 11 ∗/ 12 c l a s s TwitterEntry 13 { 14 /∗∗ 15 ∗ @var s t r i n g 16 ∗ @MongoDB\ String 17 ∗ @MongoDB\ ObjectId 18 ∗ @MongoDB\Id (name="_id " , strategy="Auto") 19 ∗/ 20 protected $id ; 21 22 /∗∗ 23 ∗ @var s t r i n g 24 ∗ @MongoDB\ String 25 ∗ @MongoDB\UniqueIndex 26 ∗/ 27 protected $twitterId ; 28 29 /∗∗ 30 ∗ @var s t r i n g 31 ∗ @MongoDB\ String 32 ∗/ 33 protected $text ; 34 35 /∗∗ 36 ∗ @var int 37 ∗ @MongoDB\ Int February 26, 2016 10 c dknx01
  11. 38 ∗/ 39 protected $retweetCount ; 40 41 /∗∗ 42

    ∗ @var DateTime 43 ∗ @MongoDB\Date 44 ∗/ 45 protected $createdAt ; 46 47 /∗∗ 48 ∗ @var boolean 49 ∗ @MongoDB\Boolean 50 ∗/ 51 protected $pinned ; 52 53 /∗∗ 54 ∗ @var OriginalData 55 ∗ @MongoDB\EmbedOne( targetDocument="TwitterBundle\Document\ Subdocument\ OriginalData ") 56 ∗/ 57 protected $originalData ; 58 59 /∗∗ 60 ∗ @return s t r i n g 61 ∗ @MongoDB\ String 62 ∗/ 63 public function getTwitterId () 64 { 65 return $this −>twitterId ; 66 } 67 68 /∗∗ 69 ∗ @param s t r i n g $twitterId 70 ∗/ 71 public function setTwitterId ( $twitterId ) 72 { 73 $this −>twitterId = $twitterId ; 74 } 75 76 /∗∗ 77 ∗ @return s t r i n g 78 ∗/ 79 public function getText () 80 { 81 return $this −>text ; 82 } 83 84 /∗∗ 85 ∗ @param s t r i n g $text February 26, 2016 11 c dknx01
  12. 86 ∗/ 87 public function setText ( $text ) 88

    { 89 $this −>text = $text ; 90 } 91 92 /∗∗ 93 ∗ @return int 94 ∗/ 95 public function getRetweetCount () 96 { 97 return $this −>retweetCount ; 98 } 99 100 /∗∗ 101 ∗ @param int $retweetCount 102 ∗/ 103 public function setRetweetCount ( $retweetCount ) 104 { 105 $this −>retweetCount = $retweetCount ; 106 } 107 108 /∗∗ 109 ∗ @return s t r i n g 110 ∗/ 111 public function getId () 112 { 113 return $this −>id ; 114 } 115 116 /∗∗ 117 ∗ @param s t r i n g $id 118 ∗/ 119 public function setId ( $id ) 120 { 121 $this −>id = $id ; 122 } 123 124 /∗∗ 125 ∗ @return DateTime 126 ∗/ 127 public function getCreatedAt () 128 { 129 return $this −>createdAt ; 130 } 131 132 /∗∗ 133 ∗ @param DateTime $createdAt 134 ∗/ February 26, 2016 12 c dknx01
  13. 135 public function setCreatedAt ( DateTime $createdAt ) 136 {

    137 138 $this −>createdAt = $createdAt ; 139 } 140 141 /∗∗ 142 ∗ @return boolean 143 ∗/ 144 public function isPinned () 145 { 146 return $this −>pinned ; 147 } 148 149 /∗∗ 150 ∗ @param boolean $pinned 151 ∗/ 152 public function setPinned ( $pinned ) 153 { 154 $this −>pinned = $pinned ; 155 } 156 157 /∗∗ 158 ∗ @return OriginalData 159 ∗/ 160 public function getOriginalData () 161 { 162 return $this −>originalData ; 163 } 164 165 /∗∗ 166 ∗ @param OriginalData $originalData 167 ∗/ 168 public function setOriginalData ( $originalData ) 169 { 170 $this −>originalData = $originalData ; 171 } 172 } Listing 12: A document class 4.5 The whole embedded document class 1 <?php 2 3 namespace TwitterBundle\Document\Subdocument ; 4 5 use Doctrine \ODM\MongoDB\Mapping\ Annotations as MongoDB; 6 February 26, 2016 13 c dknx01
  14. 7 /∗∗ 8 ∗ @MongoDB\EmbeddedDocument 9 ∗/ 10 c l

    a s s OriginalData 11 { 12 /∗∗ 13 ∗ @var s t r i n g 14 ∗ @MongoDB\ String 15 ∗/ 16 protected $text ; 17 18 /∗∗ 19 ∗ @var array 20 ∗ @MongoDB\ Collection 21 ∗/ 22 protected $hashes = array () ; 23 24 /∗∗ 25 ∗ @var array 26 ∗ @MongoDB\ Collection 27 ∗/ 28 protected $mentions = array () ; 29 30 /∗∗ 31 ∗ @var array 32 ∗ @MongoDB\ Collection 33 ∗/ 34 protected $media = array () ; 35 36 /∗∗ 37 ∗ @return s t r i n g 38 ∗/ 39 public function getText () 40 { 41 return $this −>text ; 42 } 43 44 /∗∗ 45 ∗ @param s t r i n g $text 46 ∗/ 47 public function setText ( $text ) 48 { 49 $this −>text = $text ; 50 } 51 52 /∗∗ 53 ∗ @return array 54 ∗/ 55 public function getHashes () February 26, 2016 14 c dknx01
  15. 56 { 57 return $this −>hashes ; 58 } 59

    60 /∗∗ 61 ∗ @param mixed $hashValue 62 ∗/ 63 public function addHash ( $hashValue ) 64 { 65 $this −>hashes [ ] = $hashValue ; 66 } 67 68 /∗∗ 69 ∗ @return array 70 ∗/ 71 public function getMentions () 72 { 73 return $this −>mentions ; 74 } 75 76 /∗∗ 77 ∗ @param mixed $mentionValue 78 ∗/ 79 public function addMention ( $mentionValue ) 80 { 81 $this −>mentions [ ] = $mentionValue ; 82 } 83 84 /∗∗ 85 ∗ @return array 86 ∗/ 87 public function getMedia () 88 { 89 return $this −>media ; 90 } 91 92 /∗∗ 93 ∗ @param mixed $media 94 ∗/ 95 public function addMedia ( $media ) 96 { 97 $this −>media [ ] = $media ; 98 } 99 } Listing 13: A subdocument class February 26, 2016 15 c dknx01
  16. 4.6 Example Entry Here is an example entry in MongoDB

    with arrays/collections in the subdoc- ument. Figure 1: example entry February 26, 2016 16 c dknx01
  17. 5 Repository To use our MongoDB document in a real

    application we need of course a repository. The whole class can be seen in section 5.7. 5.1 Saving a document Saving a document is actually like a saving a normal MySQL entry. 1 /∗∗ 2 ∗ @param TwitterEntry $twitterEntry 3 ∗/ 4 public function save ( TwitterEntry $twitterEntry ) 5 { 6 $this −>dm−>p e r s i s t ( $twitterEntry ) ; 7 $this −>dm−>f l u s h ( $twitterEntry ) ; 8 } Listing 14: Saving document 5.2 Find by a eld Finding an entry by a eld is also not hard (herewe use our unique key eld). 1 /∗∗ 2 ∗ @param s t r i n g $id 3 ∗ @return null | TwitterEntry 4 ∗/ 5 public function findByTwitterId ( $id ) 6 { 7 return $this −>findOneBy ( array ( ' twitterId ' => $id ) ) ; 8 } Listing 15: Find by eld 5.3 Find with limit, skipping, sorting and one condition - part 1 Finding an entry by a eld is also not hard (here we use our unique key eld). We want all entries that have not set eld 'deleted' or where this eld is 'false' (line 10). We also can pass an limit (line 12) and skipping or starting value (line 11) (in SQL: LIMIT 10,5) and we want so sort it by 'twitterId' DESC (line 13). 1 /∗∗ 2 ∗ @param int $l imit February 26, 2016 17 c dknx01
  18. 3 ∗ @param int $skip 4 ∗ @return Cursor 5

    ∗/ 6 public function findWithLimit ( $ limit = 50 , $skip = 0) 7 { 8 $qb = $this −>createQueryBuilder () ; 9 /∗∗ @var Cursor $ r e s u l t ∗/ 10 $ r e s u l t = $qb−>f i e l d ( ' deleted ' )−>notEqual ( true ) 11 −>skip ( $skip ) 12 −>l i m i t ( $l imit ) 13 −>sort ( ' twitterId ' , −1) 14 −>getQuery () 15 −>execute () ; 16 return $result −>hydrate () ; 17 } Listing 16: More complex nding - part 1 5.4 Find with limit, skipping, sorting and one condition - part 2 This example is nearly the same than the previous one, beside that the eldname is dynamic and we want this eld as 'true' or 'set' (line 11). 1 /∗∗ 2 ∗ @param s t r i n g $ f i e l d 3 ∗ @param int $l imit 4 ∗ @param int $skip 5 ∗ @return Cursor 6 ∗/ 7 public function findByBooleanFieldWithLimit ( $ f i e l d , $limit = 50 , $skip = 0) 8 { 9 $qb = $this −>createQueryBuilder () ; 10 /∗∗ @var Cursor $ r e s u l t ∗/ 11 $ r e s u l t = $qb−>f i e l d ( $ f i e l d )−>equals ( true ) 12 −>skip ( $skip ) 13 −>l i m i t ( $l imit ) 14 −>sort ( ' twitterId ' , −1) 15 −>getQuery () 16 −>execute () ; 17 return $result −>hydrate () ; 18 } Listing 17: More complex nding - part 2 February 26, 2016 18 c dknx01
  19. 5.5 Get last inserted entry This example shows how to

    get the 'twitterId' from the last inserted entry based on our unique eld 'twitterId'. So we just want one eld in the result (line 9). 1 /∗∗ 2 ∗ @return s t r i n g 3 ∗ @throws \ Doctrine \ODM\MongoDB\MongoDBException 4 ∗/ 5 public function getLastId () 6 { 7 $qb = $this −>createQueryBuilder () ; 8 /∗∗ @var Cursor $ r e s u l t ∗/ 9 $ r e s u l t = $qb−>s e l e c t ( ' twitterId ' ) 10 −>l i m i t (1) 11 −>sort ( ' twitterId ' , −1) 12 −>getQuery () 13 −>execute () ; 14 return $result −>getNext ()−>getTwitterId () ; 15 } Listing 18: Get last unique eld value 5.6 Get all entries based on one eld value This example shows how to get all entries where the eld 'from' has exactly the value passed by $username (line 11). 1 /∗∗ 2 ∗ @param s t r i n g $userName 3 ∗ @param int $l imit 4 ∗ @param int $skip 5 ∗ @return Cursor 6 ∗/ 7 public function findByUserName ( $userName , $limit , $skip ) 8 { 9 $qb = $this −>createQueryBuilder () ; 10 /∗∗ @var Cursor $ r e s u l t ∗/ 11 $ r e s u l t = $qb−>f i e l d ( ' from ' )−>equals ( $userName ) 12 −>skip ( $skip ) 13 −>l i m i t ( $l imit ) 14 −>sort ( ' twitterId ' , −1) 15 −>getQuery () 16 −>execute () ; 17 return $result −>hydrate () ; Listing 19: Get all entries based on one eld value February 26, 2016 19 c dknx01
  20. 5.7 The whole repository class 1 <?php 2 3 namespace

    TwitterBundle\ Repository ; 4 5 use TwitterBundle\Document\ TwitterEntry ; 6 use Doctrine \ODM\MongoDB\Cursor ; 7 use Doctrine \ODM\MongoDB\DocumentRepository ; 8 9 c l a s s TwitterRepository extends DocumentRepository 10 { 11 12 /∗∗ 13 ∗ @param TwitterEntry $twitterEntry 14 ∗/ 15 public function save ( TwitterEntry $twitterEntry ) 16 { 17 $this −>dm−>p e r s i s t ( $twitterEntry ) ; 18 $this −>dm−>f l u s h ( $twitterEntry ) ; 19 } 20 21 /∗∗ 22 ∗ @param s t r i n g $id 23 ∗ @return null | TwitterEntry 24 ∗/ 25 public function findByTwitterId ( $id ) 26 { 27 return $this −>findOneBy ( array ( ' twitterId ' => $id ) ) ; 28 } 29 30 /∗∗ 31 ∗ @param int $l imit 32 ∗ @param int $skip 33 ∗ @return Cursor 34 ∗/ 35 public function findWithLimit ( $ limit = 50 , $skip = 0) 36 { 37 $qb = $this −>createQueryBuilder () ; 38 /∗∗ @var Cursor $ r e s u l t ∗/ 39 $ r e s u l t = $qb−>f i e l d ( ' deleted ' )−>notEqual ( true ) 40 −>skip ( $skip ) 41 −>l i m i t ( $l imit ) 42 −>sort ( ' twitterId ' , −1) 43 −>getQuery () 44 −>execute () ; 45 return $result −>hydrate () ; 46 } 47 February 26, 2016 20 c dknx01
  21. 48 /∗∗ 49 ∗ @param s t r i n

    g $ f i e l d 50 ∗ @param int $l imit 51 ∗ @param int $skip 52 ∗ @return Cursor 53 ∗/ 54 public function findByBooleanFieldWithLimit ( $ f i e l d , $limit = 50 , $skip = 0) 55 { 56 $qb = $this −>createQueryBuilder () ; 57 /∗∗ @var Cursor $ r e s u l t ∗/ 58 $ r e s u l t = $qb−>f i e l d ( $ f i e l d )−>equals ( true ) 59 −>skip ( $skip ) 60 −>l i m i t ( $l imit ) 61 −>sort ( ' twitterId ' , −1) 62 −>getQuery () 63 −>execute () ; 64 return $result −>hydrate () ; 65 } 66 67 /∗∗ 68 ∗ @return s t r i n g 69 ∗ @throws \ Doctrine \ODM\MongoDB\MongoDBException 70 ∗/ 71 public function getLastId () 72 { 73 $qb = $this −>createQueryBuilder () ; 74 /∗∗ @var Cursor $ r e s u l t ∗/ 75 $ r e s u l t = $qb−>s e l e c t ( ' twitterId ' ) 76 −>l i m i t (1) 77 −>sort ( ' twitterId ' , −1) 78 −>getQuery () 79 −>execute () ; 80 return $result −>getNext ()−>getTwitterId () ; 81 } 82 83 /∗∗ 84 ∗ @param s t r i n g $userName 85 ∗ @param int $l imit 86 ∗ @param int $skip 87 ∗ @return Cursor 88 ∗/ 89 public function findByUserName ( $userName , $limit , $skip ) 90 { 91 $qb = $this −>createQueryBuilder () ; 92 /∗∗ @var Cursor $ r e s u l t ∗/ 93 $ r e s u l t = $qb−>f i e l d ( ' from ' )−>equals ( $userName ) 94 −>skip ( $skip ) 95 −>l i m i t ( $l imit ) February 26, 2016 21 c dknx01
  22. 96 −>sort ( ' twitterId ' , −1) 97 −>getQuery

    () 98 −>execute () ; 99 return $result −>hydrate () ; 100 } 101 } Listing 20: A repository class February 26, 2016 22 c dknx01
  23. A Appendix Listings 1 Cong connection . . . .

    . . . . . . . . . . . . . . . . . . . . . 6 2 Needed annotation . . . . . . . . . . . . . . . . . . . . . . . . 7 3 Document annotation . . . . . . . . . . . . . . . . . . . . . . . 7 4 Subdocument annotation . . . . . . . . . . . . . . . . . . . . . 7 5 Object_Id annotations . . . . . . . . . . . . . . . . . . . . . . 8 6 Unique eld annotations . . . . . . . . . . . . . . . . . . . . . 8 7 String and integer eld annotations . . . . . . . . . . . . . . . 8 8 DateTime eld annotations . . . . . . . . . . . . . . . . . . . 9 9 Boolean eld annotations . . . . . . . . . . . . . . . . . . . . . 9 10 Subdocument annotations . . . . . . . . . . . . . . . . . . . . 9 11 Array annotations . . . . . . . . . . . . . . . . . . . . . . . . . 10 12 A document class . . . . . . . . . . . . . . . . . . . . . . . . . 10 13 A subdocument class . . . . . . . . . . . . . . . . . . . . . . . 13 14 Saving document . . . . . . . . . . . . . . . . . . . . . . . . . 17 15 Find by eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 16 More complex nding - part 1 . . . . . . . . . . . . . . . . . . 17 17 More complex nding - part 2 . . . . . . . . . . . . . . . . . . 18 18 Get last unique eld value . . . . . . . . . . . . . . . . . . . . 19 19 Get all entries based on one eld value . . . . . . . . . . . . . 19 20 A repository class . . . . . . . . . . . . . . . . . . . . . . . . . 20 List of Figures 1 Example entry . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 February 26, 2016 23 c dknx01