增删改查操作
在此页面上
CRUD 操作用于 创建 、 读取 、 更新 和 删除 文档。 MongoDB PHP 库的MongoDB\Collection
类实现 MongoDB 的跨驱动程序 CRUD 规范 ,提供对在 MongoDB 中插入、查找、更新和删除文档的方法的访问。
本文档概括了如何使用 MongoDB PHP 库插入、查询、更新和删除文档。MongoDB 手册的 CRUD 部分更全面地介绍了 MongoDB 的 CRUD 操作。
插入文档
插入一个文档
MongoDB\Collection::insertOne()
方法将单个文档插入到 MongoDB 中并返回 MongoDB\InsertOneResult
的实例,您可以使用该实例访问插入文档的 ID。
以下操作会将文档插入到 test
数据库的 users
集合中:
$collection = (new MongoDB\Client)->test->users; $insertOneResult = $collection->insertOne([ 'username' => 'admin', 'email' => 'admin@example.com', 'name' => 'Admin User', ]); printf("Inserted %d document(s)\n", $insertOneResult->getInsertedCount()); var_dump($insertOneResult->getInsertedId());
而输出将类似如下所示:
Inserted 1 document(s) object(MongoDB\BSON\ObjectId)#11 (1) { ["oid"]=> string(24) "579a25921f417dd1e5518141" }
输出包含了插入文档的ID。
如果在插入文档时包含一个 _id
值,MongoDB 会检查以确保 _id
值对集合来说是唯一的。如果 _id
值不唯一,则插入操作会因重复键错误而失败。
以下示例会在指定 _id
值的同时插入文档:
$collection = (new MongoDB\Client)->test->users; $insertOneResult = $collection->insertOne(['_id' => 1, 'name' => 'Alice']); printf("Inserted %d document(s)\n", $insertOneResult->getInsertedCount()); var_dump($insertOneResult->getInsertedId());
而输出将类似如下所示:
Inserted 1 document(s) int(1)
插入多个文档
MongoDB\Collection::insertMany()
方法支持您在一次写操作中插入多个文档,并返回 MongoDB\InsertManyResult
的实例,您可以使用该实例访问所插入文档的 ID。
以下操作将两个文档插入 test
数据库的 users
集合中:
$collection = (new MongoDB\Client)->test->users; $insertManyResult = $collection->insertMany([ [ 'username' => 'admin', 'email' => 'admin@example.com', 'name' => 'Admin User', ], [ 'username' => 'test', 'email' => 'test@example.com', 'name' => 'Test User', ], ]); printf("Inserted %d document(s)\n", $insertManyResult->getInsertedCount()); var_dump($insertManyResult->getInsertedIds());
而输出将类似如下所示:
Inserted 2 document(s) array(2) { [0]=> object(MongoDB\BSON\ObjectId)#11 (1) { ["oid"]=> string(24) "579a25921f417dd1e5518141" } [1]=> object(MongoDB\BSON\ObjectId)#12 (1) { ["oid"]=> string(24) "579a25921f417dd1e5518142" } }
查询文档
MongoDB PHP 库提供用于查询文档的MongoDB\Collection::findOne()
和 方法以及用于执行MongoDB\Collection::find()
聚合操作MongoDB\Collection::aggregate()
的 方法。
在评估查询条件时,MongoDB 会根据自己 的 BSON 类型比较规则来 比较类型和值,这与 PHP 的 比较 不同 和 类型杂技 规则。匹配特殊 BSON 类型时,查询条件应使用相应的 BSON 类 在扩展中(例如,使用 MongoDB\BSON\ObjectId 以匹配 ObjectId )。
查找一个文档
MongoDB\Collection::findOne()
返回与查询匹配的第一个文档,如果没有文档与查询匹配,则返回 null
。
以下示例搜索其 _id
为 "94301"
的文档:
$collection = (new MongoDB\Client)->test->zips; $document = $collection->findOne(['_id' => '94301']); var_dump($document);
而输出将类似如下所示:
object(MongoDB\Model\BSONDocument)#13 (1) { ["storage":"ArrayObject":private]=> array(5) { ["_id"]=> string(5) "94301" ["city"]=> string(9) "PALO ALTO" ["loc"]=> object(MongoDB\Model\BSONArray)#12 (1) { ["storage":"ArrayObject":private]=> array(2) { [0]=> float(-122.149685) [1]=> float(37.444324) } } ["pop"]=> int(15965) ["state"]=> string(2) "CA" } }
注意
此示例中的条件与具有string值 "94301"
的 _id
相匹配。 由于MongoDB针对BSON types的比较规则,相同的条件不会匹配整数值为 94301
的文档。 同样,用户应使用MongoDB \BSON \ObjectId _id
ObjectId对象,因为字符串和 不能直接比较。
查找多个文档
MongoDB\Collection::find()
返回一个 MongoDB\Driver\Cursor 对象,您可以对其进行迭代以访问所有匹配的文档。
以下示例会列出 zips
集合中具有指定 city 和 state 值的文档:
$collection = (new MongoDB\Client)->test->zips; $cursor = $collection->find(['city' => 'JERSEY CITY', 'state' => 'NJ']); foreach ($cursor as $document) { echo $document['_id'], "\n"; }
输出类似如下所示:
07302 07304 07305 07306 07307 07310
查询投影
默认情况下,MongoDB 中的查询返回匹配文档中的所有字段。为了限制 MongoDB 发送给应用程序的数据量,可以在查询操作中包含一个投影文档。
注意
除非您在投影文档中显示排除,否则 MongoDB 默认包含 _id
字段。。
以下示例根据cuisine
和borough
字段查找餐馆,并使用投影来限制返回的字段。 它还将结果限制为5文档。
$collection = (new MongoDB\Client)->test->restaurants; $cursor = $collection->find( [ 'cuisine' => 'Italian', 'borough' => 'Manhattan', ], [ 'projection' => [ 'name' => 1, 'borough' => 1, 'cuisine' => 1, ], 'limit' => 4, ] ); foreach($cursor as $restaurant) { var_dump($restaurant); };
而输出将类似如下所示:
object(MongoDB\Model\BSONDocument)#10 (1) { ["storage":"ArrayObject":private]=> array(4) { ["_id"]=> object(MongoDB\BSON\ObjectId)#8 (1) { ["oid"]=> string(24) "576023c6b02fa9281da3f983" } ["borough"]=> string(9) "Manhattan" ["cuisine"]=> string(7) "Italian" ["name"]=> string(23) "Isle Of Capri Resturant" } } object(MongoDB\Model\BSONDocument)#13 (1) { ["storage":"ArrayObject":private]=> array(4) { ["_id"]=> object(MongoDB\BSON\ObjectId)#12 (1) { ["oid"]=> string(24) "576023c6b02fa9281da3f98d" } ["borough"]=> string(9) "Manhattan" ["cuisine"]=> string(7) "Italian" ["name"]=> string(18) "Marchis Restaurant" } } object(MongoDB\Model\BSONDocument)#8 (1) { ["storage":"ArrayObject":private]=> array(4) { ["_id"]=> object(MongoDB\BSON\ObjectId)#10 (1) { ["oid"]=> string(24) "576023c6b02fa9281da3f99b" } ["borough"]=> string(9) "Manhattan" ["cuisine"]=> string(7) "Italian" ["name"]=> string(19) "Forlinis Restaurant" } } object(MongoDB\Model\BSONDocument)#12 (1) { ["storage":"ArrayObject":private]=> array(4) { ["_id"]=> object(MongoDB\BSON\ObjectId)#13 (1) { ["oid"]=> string(24) "576023c6b02fa9281da3f9a8" } ["borough"]=> string(9) "Manhattan" ["cuisine"]=> string(7) "Italian" ["name"]=> string(22) "Angelo Of Mulberry St." } }
限制、排序和跳过选项
除了投影条件之外,还可以在查询过程中指定限制、排序和跳过文档的选项。
以下示例会使用 limit
(显示)和 sort
(排序)选项查询美国人口最多的五个邮政编码:
$collection = (new MongoDB\Client)->test->zips; $cursor = $collection->find( [], [ 'limit' => 5, 'sort' => ['pop' => -1], ] ); foreach ($cursor as $document) { printf("%s: %s, %s\n", $document['_id'], $document['city'], $document['state']); }
而输出将类似如下所示:
60623: CHICAGO, IL 11226: BROOKLYN, NY 10021: NEW YORK, NY 10025: NEW YORK, NY 90201: BELL GARDENS, CA
正则表达式
筛选条件可包括正则表达式,方法是使用 MongoDB\BSON\Regex 类目录或$regex
操作符。
以下示例列出了 zips
集合中的文档,其中城市名称以“garden”开头,州为德克萨斯州:
$collection = (new MongoDB\Client)->test->zips; $cursor = $collection->find([ 'city' => new MongoDB\BSON\Regex('^garden', 'i'), 'state' => 'TX', ]); foreach ($cursor as $document) { printf("%s: %s, %s\n", $document['_id'], $document['city'], $document['state']); }
而输出将类似如下所示:
78266: GARDEN RIDGE, TX 79739: GARDEN CITY, TX 79758: GARDENDALE, TX
可以使用 $regex
操作符构造等效过滤器:
[ 'city' => ['$regex' => '^garden', '$options' => 'i'], 'state' => 'TX', ]
尽管 MongoDB 的正则表达式语法与 PHP 的 PCRE 语法并不完全相同,但 preg_quote() 可用于转义应按原样匹配的特殊字符。以下示例查找名称以“(Library)”开头的餐馆:
$collection = (new MongoDB\Client)->test->restaurants; $cursor = $collection->find([ 'name' => new MongoDB\BSON\Regex('^' . preg_quote('(Library)')), ]);
带聚合的复杂查询
MongoDB 的 聚合框架 允许您发出复杂的查询,对集合数据进行筛选、转换和分组。 MongoDB PHP 库的MongoDB\Collection::aggregate()
方法返回一个 Traversable 对象,您可以对其进行迭代以访问聚合操作的结果。有关方法输出的更多信息,请参阅MongoDB\Collection::aggregate()
方法的 行为参考 。
以下示例会列出与其关联的邮政编码数量最多的 5 个美国州:
$collection = (new MongoDB\Client)->test->zips; $cursor = $collection->aggregate([ ['$group' => ['_id' => '$state', 'count' => ['$sum' => 1]]], ['$sort' => ['count' => -1]], ['$limit' => 5], ]); foreach ($cursor as $state) { printf("%s has %d zip codes\n", $state['_id'], $state['count']); }
而输出将类似如下所示:
TX has 1671 zip codes NY has 1595 zip codes CA has 1516 zip codes PA has 1458 zip codes IL has 1237 zip codes
更新文档
更新一个文档
使用 MongoDB\Collection::updateOne()
方法更新与过滤器匹配的单个文档。MongoDB\Collection::updateOne()
返回 MongoDB\UpdateResult
对象,您可以使用该对象访问有关更新操作的统计信息。
更新方法有两个必需参数:标识要更新的一个或多个文档的查询筛选器,以及指定要执行哪些更新的更新文档。MongoDB\Collection::updateOne()
参考文件详细描述了每个参数。
以下示例使用 MongoDB\Collection::insertOne()
方法将两个文档插入到 test
数据库中的空 users
集合中,然后更新 state
字段值为 "ny"
的文档以包含设置为"us"
的 country
字段:
$collection = (new MongoDB\Client)->test->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());
由于更新操作使用 MongoDB\Collection::updateOne()
方法,即更新第一个文档以匹配筛选条件,因此结果如下所示:
Matched 1 document(s) Modified 1 document(s)
文档可能与筛选器匹配,但不会被更新修改,如本示例中更新将字段值设置为现有值的情况:
$collection = (new MongoDB\Client)->test->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());
因此,匹配的文档数和修改的文档数并不相等,操作的输出类似于:
Matched 1 document(s) Modified 0 document(s)
更新多个文档
MongoDB\Collection::updateMany()
会更新一个或多个符合筛选条件的文档,并返回 MongoDB\UpdateResult
对象,您可以使用该对象访问更新操作统计信息。
更新方法有两个必需参数:标识要更新的一个或多个文档的查询筛选器,以及指定要执行哪些更新的更新文档。MongoDB\Collection::updateMany()
参考文件详细描述了每个参数。
以下示例将三个文档插入到test
数据库中的空users
集合中,然后使用$set
操作符更新与筛选条件匹配的文档,以包含值为"us"
的country
字段:
$collection = (new MongoDB\Client)->test->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());
如果更新操作未导致文档发生更改,例如将字段值设置为当前值,则修改的文档数可能少于匹配的文档数。由于 name
为 "Bob"
的更新文档不会导致文档发生任何更改,因此该操作的输出类似于:
Matched 3 document(s) Modified 2 document(s)
替换文档
替换操作与更新操作类似,但替换操作不是更新文档以包含新字段或新字段值,而是用新文档替换整个文档,但保留原始文档的 _id
值。
MongoDB\Collection::replaceOne()
方法会替换符合筛选条件的单个文档并返回 MongoDB\UpdateResult
的实例,您可以使用该实例访问有关替换操作的统计信息。
MongoDB\Collection::replaceOne()
有两个必需的参数:识别要替换的一个或多个文档的查询筛选器,以及将替换 MongoDB 中原始文档的替换文档。MongoDB\Collection::replaceOne()
参考文件详细描述了每个参数。
重要
替换操作会替换文档中除 _id
值之外的所有字段。为避免意外覆盖或删除所需字段,请使用 MongoDB\Collection::updateOne()
或 MongoDB\Collection::updateMany()
方法更新文档中的单个字段,而不是替换整个文档。
以下示例会将一个文档插入到 test
数据库中的空 users
集合中,然后用新文档替换该文档:
$collection = (new MongoDB\Client)->test->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());
而输出将类似如下所示:
Matched 1 document(s) Modified 1 document(s)
更新插入
更新和替换操作支持更新或插入选项。当upsert
为true
且没有文档与指定的筛选器匹配时,该操作将创建一个新文档并将其插入。如果存在匹配的文档,则该操作会修改或替换匹配的一个或多个文档。
对文档执行更新或插入时,可以通过 MongoDB\UpdateResult::getUpsertedId()
访问 ID。
以下示例使用 MongoDB\Collection::updateOne()
,将 upsert
选项设置为 true
,并在 test
数据库中使用空的 users
集合,从而将文档插入到数据库:
$collection = (new MongoDB\Client)->test->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()); printf("Upserted %d document(s)\n", $updateResult->getUpsertedCount()); $upsertedDocument = $collection->findOne([ '_id' => $updateResult->getUpsertedId(), ]); var_dump($upsertedDocument);
而输出将类似如下所示:
Matched 0 document(s) Modified 0 document(s) Upserted 1 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" } }
删除文档
删除一个文档
MongoDB\Collection::deleteOne()
方法删除符合筛选条件的单个文档并返回 MongoDB\DeleteResult
,您可以用此结果访问有关删除操作的统计信息。
如果有多个文档与过滤条件匹配,则 MongoDB\Collection::deleteOne()
会删除第一个匹配的文档。
MongoDB\Collection::deleteOne()
有一个必需参数:指定要删除的文档的查询筛选器。请参阅 MongoDB\Collection::deleteOne()
参考文件,查看完整的方法文档。
以下操作删除 state
字段值为 "ny"
的第一个文档:
$collection = (new MongoDB\Client)->test->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());
而输出将类似如下所示:
Deleted 1 document(s)
删除多个文档
MongoDB\Collection::deleteMany()
删除所有符合过滤条件的文档并返回 MongoDB\DeleteResult
,您可以使用它来访问有关删除操作的统计信息。
MongoDB\Collection::deleteMany()
有一个必需参数:指定要删除的文档的查询筛选器。请参阅 MongoDB\Collection::deleteMany()
参考文件,查看完整的方法文档。
以下操作会删除 state
字段值为 "ny"
的所有文档:
$collection = (new MongoDB\Client)->test->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());
而输出将类似如下所示:
Deleted 2 document(s)