diff --git a/docs/tutorial/crud.md b/docs/tutorial/crud.md index af09d5c88..813d99cd0 100644 --- a/docs/tutorial/crud.md +++ b/docs/tutorial/crud.md @@ -11,6 +11,38 @@ the [MongoDB Manual][crud]. [crud-spec]: https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst [crud]: https://docs.mongodb.org/manual/crud/ +This page covers the following common use cases: + + * Querying for [one](#finding-one-document) or [many](#finding-many-documents) + documents at a time + * [Projecting](#query-projection) fields in a query + * Applying [limit, sort, and skip options](#limit-sort-and-skip-options) to a + query + * Inserting [one](#inserting-one-document) or [many](#inserting-many-documents) + documents at a time + * Updating [one](#updating-one-document) or [many](#updating-many-documents) + documents at a time + * [Replacing](#replacing-a-document) a document + * [Upserting](#upserting-a-document) a document + * Deleting [one](#deleting-one-document) or [many](#deleting-many-documents) + documents at a time + * [Aggregating](#aggregating-documents) documents + +Note that the use of arrays to express documents in the following examples was +done for simplicity. The driver will also accept instances of stdClass or +[MongoDB\BSON\Serializable][serializable]) for these arguments (e.g. query +filters, inserted documents, update documents). + +[serializable]: http://php.net/mongodb-bson-serializable + +Documents destined for database storage (e.g. insert documents, replacement +documents, embedded documents included in an update operation) may also be +instances of [MongoDB\BSON\Persistable][persistable]. See +[Persistable Classes][persistable-classes] for more information. + +[persistable]: http://php.net/mongodb-bson-persistable +[persistable-classes]: bson.md#persistable-classes + ## Finding One Document The [findOne()][findone] method returns the first matched document, or null if @@ -160,7 +192,398 @@ The above example would output something similar to: 90201: BELL GARDENS, CA ``` -## Aggregation +## Inserting One Document + +The [insertOne()][insertone] method may be used to insert a single document. +This method returns an instance of `MongoDB\InsertOneResult`, which may be used +to access the ID of the inserted document. Note that if a document does not +contain an `_id` field at the time of insertion, the driver will generate a +`MongoDB\BSON\ObjectID` to use as its ID. + +[insertone]: ../classes/collection.md#insertone + +``` +demo->users; +$collection->drop(); + +$insertOneResult = $collection->insertOne(['name' => 'Bob']); + +printf("Inserted %d document(s)\n", $insertOneResult->getInsertedCount()); +var_dump($insertOneResult->getInsertedId()); +``` + +The above example would output something similar to: + +``` +Inserted 1 document(s) +object(MongoDB\BSON\ObjectID)#10 (1) { + ["oid"]=> + string(24) "5750905b6118fd170565aa81" +} +``` + +The following example inserts a document with an ID. Note that if an ID is not +unique for the collection, the insert will fail due to a duplicate key error. + +``` +demo->users; +$collection->drop(); + +$insertOneResult = $collection->insertOne(['_id' => 1, 'name' => 'Alice']); + +printf("Inserted %d document(s)\n", $insertOneResult->getInsertedCount()); +var_dump($insertOneResult->getInsertedId()); +``` + +The above example would output: + +``` +Inserted 1 document(s) +int(1) +``` + +## Inserting Many Documents + +The [insertMany()][insertmany] method may be used to insert multiple documents +at a time. This method returns an instance of `MongoDB\InsertManyResult`, which +may be used to access the IDs of the inserted documents. + +[insertmany]: ../classes/collection.md#insertmany + +``` +demo->users; +$collection->drop(); + +$insertManyResult = $collection->insertMany([ + ['name' => 'Bob'], + ['_id' => 1, 'name' => 'Alice'], +]); + +printf("Inserted %d document(s)\n", $insertManyResult->getInsertedCount()); +var_dump($insertManyResult->getInsertedIds()); +``` + +The above example would output something similar to: + +``` +Inserted 2 document(s) +array(2) { + [0]=> + object(MongoDB\BSON\ObjectID)#10 (1) { + ["oid"]=> + string(24) "5750927b6118fd1ed64eb141" + } + [1]=> + int(1) +} +``` + +## Updating One Document + +The [updateOne()][updateone] method may be used to update a single document +matching a filter. This method returns an instance of `MongoDB\UpdateResult`, +which may be used to access statistics about the update operation. + +[updateone]: ../classes/collection.md#updateone + +This method has two required parameters: a query filter and an update document. +The query filter is similar to what might be provided to [find()][find]. The +update document consists of one or more [update operators][updateops]. + +[updateops]: https://docs.mongodb.com/manual/reference/operator/update/ + +``` +demo->users; +$collection->drop(); + +$collection->insertOne(['name' => 'Bob', 'state' => 'ny']); +$collection->insertOne(['name' => 'Alice', 'state' => 'ny']); +$updateResult = $collection->updateOne( + ['state' => 'ny'], + ['$set' => ['country' => 'us']] +); + +printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); +printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); +``` + +The above example would output something similar to: + +``` +Matched 1 document(s) +Modified 1 document(s) +``` + +Note that it is possible for a document to match the filter but not be modified +by an update: + +``` +demo->users; +$collection->drop(); + +$collection->insertOne(['name' => 'Bob', 'state' => 'ny']); +$updateResult = $collection->updateOne( + ['name' => 'Bob'], + ['$set' => ['state' => 'ny']] +); + +printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); +printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); +``` + +The above example would output something similar to: + +``` +Matched 1 document(s) +Modified 0 document(s) +``` + +## Updating Many Documents + +The [updateMany()][updatemany] method may be used to update multiple documents +at a time. This method returns an instance of `MongoDB\UpdateResult`, which may +be used to access statistics about the update operation. + +[updatemany]: ../classes/collection.md#updatemany + +This method has two required parameters: a query filter and an update document. +The query filter is similar to what might be provided to [find()][find]. The +update document consists of one or more [update operators][updateops]. + +``` +demo->users; +$collection->drop(); + +$collection->insertOne(['name' => 'Bob', 'state' => 'ny', 'country' => 'us']); +$collection->insertOne(['name' => 'Alice', 'state' => 'ny']); +$collection->insertOne(['name' => 'Sam', 'state' => 'ny']); +$updateResult = $collection->updateMany( + ['state' => 'ny'], + ['$set' => ['country' => 'us']] +); + +printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); +printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); +``` + +The above example would output something similar to: + +``` +Matched 3 document(s) +Modified 2 document(s) +``` + +## Replacing a Document + +The [replaceOne()][replaceone] method may be used to replace a single document +matching a filter. This method returns an instance of `MongoDB\UpdateResult`, +which may be used to access statistics about the replacement operation. + +[replaceone]: ../classes/collection.md#replaceone + +This method has two required parameters: a query filter and a replacement +document. The query filter is similar to what might be provided to +[find()][find]. The replacement document will be used to overwrite the matched +document (excluding its ID, which is immutable) and must not contain +[update operators][updateops]. + +Note that the very nature of a replacement operation makes it easy to +inadvertently overwrite or delete fields in a document. When possible, users +should consider updating individual fields with [updateOne()][updateone] or +[updateMany()][updatemany]. + +``` +demo->users; +$collection->drop(); + +$collection->insertOne(['name' => 'Bob', 'state' => 'ny']); +$updateResult = $collection->replaceOne( + ['name' => 'Bob'], + ['name' => 'Robert', 'state' => 'ca'] +); + +printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); +printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); +``` + +The above example would output something similar to: + +``` +Matched 1 document(s) +Modified 1 document(s) +``` + +Note that it is possible for a document to match the filter but not be modified +by a replacement (i.e. the matched document and replacement may be the same). + +## Upserting a Document + +An upsert is a variation of an update or replace operation, whereby a new +document is inserted if the query filter does not match an existing document. +An upsert may be specified via the `upsert` option for [updateOne()][updateone], +[updateMany()][updatemany], or [replaceOne()][replaceone]. The logic by which +the inserted document is created is discussed in the [MongoDB manual][upsert]. + +[upsert]: https://docs.mongodb.com/manual/reference/method/db.collection.update/#upsert-parameter + +If a document has been upserted, its ID will be accessible via +`MongoDB\UpdateResult::getUpsertedId()`. + +The following example demonstrates an upsert via [updateOne()][updateone]: + +``` +demo->users; +$collection->drop(); + +$updateResult = $collection->updateOne( + ['name' => 'Bob'], + ['$set' => ['state' => 'ny']], + ['upsert' => true] +); + +printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); +printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); +var_dump($collection->findOne(['_id' => $updateResult->getUpsertedId()])); +``` + +The above example would output something similar to: + +``` +Matched 0 document(s) +Modified 0 document(s) +object(MongoDB\Model\BSONDocument)#16 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["_id"]=> + object(MongoDB\BSON\ObjectID)#15 (1) { + ["oid"]=> + string(24) "57509c4406d7241dad86e7c3" + } + ["name"]=> + string(3) "Bob" + ["state"]=> + string(2) "ny" + } +} +``` + +The following example demonstrates an upsert via [replaceOne()][replaceone]: + +``` +demo->users; +$collection->drop(); + +$updateResult = $collection->replaceOne( + ['name' => 'Bob'], + ['name' => 'Alice', 'state' => 'ny'], + ['upsert' => true] +); + +printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); +printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); +var_dump($collection->findOne(['_id' => $updateResult->getUpsertedId()])); +``` + +The above example would output something similar to: + +``` +Matched 0 document(s) +Modified 0 document(s) +object(MongoDB\Model\BSONDocument)#16 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["_id"]=> + object(MongoDB\BSON\ObjectID)#15 (1) { + ["oid"]=> + string(24) "57509c6606d7241dad86e7c4" + } + ["name"]=> + string(5) "Alice" + ["state"]=> + string(2) "ny" + } +} +``` + +## Deleting One Document + +The [deleteOne()][deleteone] method may be used to delete a single document +matching a filter. This method returns an instance of `MongoDB\DeleteResult`, +which may be used to access statistics about the delete operation. + +[deleteone]: ../classes/collection.md#deleteone + +This method has two required parameters: a query filter. The query filter is +similar to what might be provided to [find()][find]. + +``` +demo->users; +$collection->drop(); + +$collection->insertOne(['name' => 'Bob', 'state' => 'ny']); +$collection->insertOne(['name' => 'Alice', 'state' => 'ny']); +$deleteResult = $collection->deleteOne(['state' => 'ny']); + +printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); +``` + +The above example would output something similar to: + +``` +Deleted 1 document(s) +``` + +## Deleting Many Documents + +The [deleteMany()][deletemany] method may be used to delete multiple documents +at a time. This method returns an instance of `MongoDB\DeleteResult`, which may +be used to access statistics about the delete operation. + +[deletemany]: ../classes/collection.md#deletemany + +This method has two required parameters: a query filter. The query filter is +similar to what might be provided to [find()][find]. + +``` +demo->users; +$collection->drop(); + +$collection->insertOne(['name' => 'Bob', 'state' => 'ny']); +$collection->insertOne(['name' => 'Alice', 'state' => 'ny']); +$deleteResult = $collection->deleteMany(['state' => 'ny']); + +printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); +``` + +The above example would output something similar to: + +``` +Deleted 2 document(s) +``` + +## Aggregating Documents The [Aggregation Framework][aggregation] may be used to issue complex queries that filter, transform, and group collection data. The [aggregate()][aggregate] diff --git a/examples/bootstrap.php b/examples/bootstrap.php deleted file mode 100644 index fd711e007..000000000 --- a/examples/bootstrap.php +++ /dev/null @@ -1,11 +0,0 @@ -getInsertedCount(), - $result->getUpsertedCount(), - $result->getModifiedCount(), - $result->getDeletedCount() - ); - - if ($result->getUpsertedCount()) { - foreach ($result->getUpsertedIds() as $index => $id) { - printf("upsertedId[%d]: %s\n", $index, $id); - } - } -} - -function dumpCollection($collection) -{ - printf("Dumping all documents in: %s.%s\n", - $collection->getDatabaseName(), - $collection->getCollectionName() - ); - $n = 0; - foreach($collection->find() as $document) { - var_dump($document); - $n++; - } - printf("Found %d documents\n", $n); -} - -$result = $collection->bulkWrite([ - [ - "insertOne" => [ - [ - "name" => "Hannes Magnusson", - "company" => "10gen", - ] - ], - ], - [ - "insertOne" => [ - [ - "name" => "Jeremy Mikola", - "company" => "10gen", - ] - ], - ], - [ - "updateMany" => [ - ["company" => "10gen"], - ['$set' => ["company" => "MongoDB"]], - ], - ], - [ - "updateOne" => [ - ["name" => "Hannes Magnusson"], - ['$set' => ["viking" => true]], - ], - ], -]); - -dumpWriteResults($result); -echo "\n"; -dumpCollection($collection); -echo "\n"; - -$result = $collection->bulkWrite([ - [ - "deleteOne" => [ - ["company" => "MongoDB"], - ], - ], - [ - "updateOne" => [ - ["name" => "Hannes Magnusson"], - ['$set' => ["nationality" => "Icelandic"]], - ["upsert" => true], - ], - ], - [ - "deleteMany" => [ - ["nationality" => [ '$ne' => "Icelandic"]], - ], - ], -]); - -dumpWriteResults($result); -echo "\n"; -dumpCollection($collection); -echo "\n"; - -$result = $collection->bulkWrite([ - [ - "deleteMany" => [ - [], - ], - ], -]); - -dumpWriteResults($result); -echo "\n"; -dumpCollection($collection); diff --git a/examples/write.php b/examples/write.php deleted file mode 100644 index 6a9a3e247..000000000 --- a/examples/write.php +++ /dev/null @@ -1,234 +0,0 @@ - "Hannes", - "nick" => "bjori", - "citizen" => "Iceland", -]; -$hayley = [ - "name" => "Bayley", - "nick" => "Ninja", - "citizen" => "USA", -]; -$bobby = [ - "name" => "Robert Fischer", - "nick" => "Bobby Fischer", - "citizen" => "USA", -]; -$kasparov = [ - "name" => "Garry Kimovich Kasparov", - "nick" => "Kasparov", - "citizen" => "Russia", -]; -$spassky = [ - "name" => "Boris Vasilievich Spassky", - "nick" => "Spassky", - "citizen" => "France", -]; - - -try { - $result = $collection->insertOne($hannes); - printf("Inserted _id: %s\n\n", $result->getInsertedId()); - - $result = $collection->insertOne($hayley); - printf("Inserted _id: %s\n\n", $result->getInsertedId()); - - $result = $collection->insertOne($bobby); - printf("Inserted _id: %s\n\n", $result->getInsertedId()); - - $count = $collection->count(["nick" => "bjori"]); - printf("Searching for nick => bjori, should have only one result: %d\n\n", $count); - - $result = $collection->updateOne( - ["citizen" => "USA"], - ['$set' => ["citizen" => "Iceland"]] - ); - printf("Updated: %s (out of expected 1)\n\n", $result->getModifiedCount()); - - $cursor = $collection->find( - ["citizen" => "Iceland"], - ["comment" => "Excellent query"] - ); - echo "Searching for citizen => Iceland, verify Bayley is now Icelandic\n"; - foreach($cursor as $document) { - var_dump($document); - } - echo "\n"; -} catch(Exception $e) { - printf("Caught exception '%s', on line %d\n", $e->getMessage(), __LINE__); - exit; -} - - -try { - $cursor = $collection->find(); - echo "Find all docs, should be 3, verify 1x USA citizen, 2x Icelandic\n"; - foreach($cursor as $document) { - var_dump($document); - } - echo "\n"; - - $result = $collection->distinct("citizen"); - echo "Distinct countries:\n"; - var_dump($result); - echo "\n"; - - echo "aggregate\n"; - $result = $collection->aggregate( - [ - ['$project' => ["name" => 1, "_id" => 0]], - ], - [ "useCursor" => true, "batchSize" => 2 ] - ); - printf("Should be 3 different people\n"); - foreach($result as $person) { - var_dump($person); - } - echo "\n"; -} catch(Exception $e) { - printf("Caught exception '%s', on line %d\n", $e->getMessage(), __LINE__); - exit; -} - - -try { - $result = $collection->updateMany( - ["citizen" => "Iceland"], - ['$set' => ["viking" => true]] - ); - printf("Updated: %d (out of expected 2), verify Icelandic people are vikings\n", $result->getModifiedCount()); - $result = $collection->find(); - foreach($result as $document) { - var_dump($document); - } - echo "\n"; -} catch(Exception $e) { - printf("Caught exception '%s', on line %d\n", $e->getMessage(), __LINE__); - exit; -} - - -try { - $result = $collection->replaceOne( - ["nick" => "Bobby Fischer"], - ["name" => "Magnus Carlsen", "nick" => "unknown", "citizen" => "Norway"] - ); - printf("Replaced: %d (out of expected 1), verify Bobby has been replaced with Magnus\n", $result->getModifiedCount()); - $result = $collection->find(); - foreach($result as $document) { - var_dump($document); - } - echo "\n"; -} catch(Exception $e) { - printf("Caught exception '%s', on line %d\n", $e->getMessage(), __LINE__); - exit; -} - - -try { - $result = $collection->deleteOne($document); - printf("Deleted: %d (out of expected 1)\n\n", $result->getDeletedCount()); - - $result = $collection->deleteMany(["citizen" => "Iceland"]); - printf("Deleted: %d (out of expected 2)\n\n", $result->getDeletedCount()); -} catch(Exception $e) { - printf("Caught exception '%s', on line %d\n", $e->getMessage(), __LINE__); - exit; -} - - -try { - echo "FindOneAndReplace\n"; - $result = $collection->findOneAndReplace( - $spassky, - $kasparov, - ["upsert" => true] - ); - echo "Kasparov\n"; - var_dump($result); - echo "\n"; - - echo "Returning the old document where he was Russian\n"; - $result = $collection->findOneAndUpdate( - $kasparov, - ['$set' => ["citizen" => "Croatia"]] - ); - var_dump($result); - echo "\n"; - - echo "Deleting him, he isn't Croatian just yet\n"; - $result = $collection->findOneAndDelete(["citizen" => "Croatia"]); - var_dump($result); - echo "\n"; - - echo "This should be empty\n"; - $result = $collection->find(); - foreach($result as $document) { - var_dump($document); - } - echo "\n"; -} catch(Exception $e) { - printf("Caught exception '%s', on line %d\n", $e->getMessage(), __LINE__); - exit; -} - - -try { - $result = $collection->bulkWrite( - // Required writes param (an array of operations) - [ - // Operations identified by single key - [ - 'insertOne' => [ - ['x' => 1] - ], - ], - [ - 'updateMany' => [ - ['x' => 1], - ['$set' => ['x' => 2]], - ], - ], - [ - 'updateOne' => [ - ['x' => 3], - ['$set' => ['x' => 4]], - // Optional params are still permitted - ['upsert' => true], - ], - ], - [ - 'deleteOne' => [ - ['x' => 1], - ], - ], - [ - 'deleteMany' => [ - // Required arguments must still be specified - [], - ], - ], - ], - // Optional named params in an associative array - ['ordered' => false] - ); - printf("insertedCount: %d\n", $result->getInsertedCount()); - printf("matchedCount: %d\n", $result->getMatchedCount()); - printf("modifiedCount: %d\n", $result->getModifiedCount()); - printf("upsertedCount: %d\n", $result->getUpsertedCount()); - printf("deletedCount: %d\n", $result->getDeletedCount()); - - foreach ($result->getUpsertedIds() as $index => $id) { - printf("upsertedId[%d]: %s\n", $index, $id); - } - -} catch(Exception $e) { - printf("Caught exception '%s', on line %d\n", $e->getMessage(), __LINE__); - exit; -}