本章将涵盖以下主题:
理解MongoDB CRUD操作利用Ruby和Python驱动程序实行CRUD操作利用mongosh实行批量操作管理和实现MongoDB的认证与授权技能哀求
要按照本章中的代码操作,您须要在本地安装MongoDB或连接到MongoDB Atlas数据库。您可以从mongodb.com下载MongoDB社区版,或利用完备托管的数据库即做事(DBaaS)MongoDB Atlas供应的产品,该产品供应免费层以及无缝升级到最新版本。

大多数示例与新的mongosh shell兼容,但您可能希望利用旧版shell mongo,或利用mongosh片段启用mongosh的向后兼容性。
您还须要下载您选择的措辞的官方驱动程序:MongoDB官方驱动程序下载。
要按照本章中的代码操作,您将须要以下内容:
mongosh shell与MongoDB Atlas数据库的连接您选择的措辞的官方驱动程序MongoDB CRUD操作无论您为什么利用MongoDB做事器,您都须要在其上实行CRUD操作。这些基本方法,统称为CRUD操作,构成了与MongoDB做事器交互的根本。要修正MongoDB文档,该过程涉及连接到做事器,查询干系文档,调度指定属性,然后将数据传回数据库进行更新。每个CRUD操作都具有不同的目的:
创建操浸染于在MongoDB数据库中插入新文档读取操浸染于查询数据库中的文档更新操浸染于修正数据库中的现有文档删除操浸染于删除数据库中的文档利用mongosh进行CRUD
mongosh等同于关系数据库利用的管理掌握台。
要连接到mongosh,输入以下命令:
mongosh "mongodb+srv://mycluster.packt.mongodb.net/myDatabase" --apiVersion 1 --username <username> --password <password>
上述连接字符串连接到Atlas支配。在shell内,您可以通过输入以下命令查看可用的数据库:
show dbs
接下来,通过指天命据库名称连接到数据库:
use <db name>
mongosh可以用来查询和更新数据库中的数据。例如,您可以按以下办法将文档插入到名为books的凑集中:
db.books.insertOne({ title: 'Mastering MongoDB 7.0', isbn: '101' });
利用选择过滤器{ isbn: '101' },从名为books的凑集中查找您的文档,输入以下代码:
db.books.find({ isbn: '101' });
从MongoDB返回的结果会奉告写操作已成功,并将一个新文档插入到数据库中。
要更新此文档,利用mongosh方法updateOne():
db.books.updateOne({ isbn: '101' }, { $set: { price: 30 } });
现在,再次利用find()方法显示更新后的文档:
db.books.find({ isbn: '101' });
删除此文档的语法类似,结果如下:
db.books.deleteOne({ isbn: '101' });
在这里,您会把稳到几件事情:
updateOne()方法中的JSON文档{ isbn: '101' }作为查询过滤器,用于识别您想要更新的特定文档matchedCount工具关照查询匹配了一个文档modifiedCount工具关照查询修正了一个文档$set操作符许可您将字段的值设置为指定值:db.books.updateOne({ isbn: '101' }, { $set: { price: 30 } });
当多个文档符合过滤器的标准时,只有第一个匹配的文档会被updateOne()方法修正。现在,利用find()方法,您将看到您的文档符合预期:
db.books.find({ isbn: '101' });
要删除文档,有多种方法。最大略的方法是基于文档的唯一_id字段值进行过滤。例如,让我们删除isbn: 101的文档:
db.books.deleteOne({ isbn: '101' });
在这里,您可以看到如果没有结果,mongosh将不会返回任何东西,除了shell提示符本身:>。
MongoDB 7.0从这些基于删除命令的操作中移除了大多数韶光序列限定。然而,这些删除命令只有一个与韶光序列干系的限定:
deletedeleteOne()deleteMany()Bulk.find.delete()Bulk.find.deleteOne() 把稳您不能利用这些命令进行多文档事务。
为mongosh编写脚本
利用内置命令管理数据库是有帮助的,但这不是利用shell的紧张缘故原由。利用mongosh的真正力量在于它供应了一个JavaScript REPL环境。这意味着您可以实行须要一组命令作为整体实行的繁芜管理任务。
您可以在shell中声明并赋值变量,如下所示:
let title = 'MongoDB in a nutshell';print(title);db.books.insertOne({ title: title, isbn: 102 });db.books.find({ title: title, isbn: 102 });
上述示例声明了一个新的title变量为"MongoDB in a nutshell",并利用该变量将一个新文档插入到您的books凑集中。
由于它是一个JavaScript REPL环境,您可以利用它来编写函数和脚本,从数据库天生繁芜结果:
queryBooksByIsbn = function (isbn) { return db.books.find({ isbn: isbn }); }
这个单行命令创建了一个名为queryBooksByIsbn的新函数,它接管一个参数,即isbn值。
有了您在凑集中的数据,您可以利用新函数并通过isbn获取书本,如下所示:
queryBooksByIsbn(102);
您可以利用mongosh编写和测试这些脚本。一旦您满意,可以将它们存储在.js文件中,并直接从命令行调用它们,如下所示:
mongosh <script_name.js>
以下是一些关于这些脚本默认行为的有用解释:
写操作利用默认的写关注点w: "majority"。写关注点的大多数被打算为所有节点打算出的大多数和数据承载节点数量之间的最小值。这意味着当您有不是数据承载节点的仲裁器时,它们将不包括在大多数的打算中。例如,在包括三个做事器的副本集,个中一个是仲裁器,大多数的打算涉及确定所有节点打算出的大多数(2,最靠近的数字,使数字超过50%)和数据承载节点的数量之间的最小值,在这种情形下也是2。要从脚本中将操作结果检索回标准输出(stdout),您必须利用JavaScript的内置print()函数。下一节将磋商为mongosh编写脚本与直策应用它的差异。
为mongosh编写脚本与直策应用
当为mongosh编写脚本时,您不能利用shell帮助程序。MongoDB的命令,如use <database_name>、show collections以及其他内置于shell中的帮助程序,在您的脚本实行的JavaScript高下文中是无法访问的。幸运的是,如表5.1所示,从JavaScript实行高下文中有等效的命令可用:
表5.1: 壳帮助程序和JavaScript等效项
Shell帮助程序
JavaScript等效项
show dbs, show databases
db.adminCommand('listDatabases')
use <database_name>
db = db.getSiblingDB('<database_name>')
show collections
db.getCollectionNames()
show users
db.getUsers()
show roles
db.getRoles({ showBuiltinRoles: true })
show log <logname>
db.adminCommand({ 'getLog' : '<logname>' })
show logs
db.adminCommand({ 'getLog' : '' })
it
cursor = db.collection.find()<br>if ( cursor.hasNext() ){<br> cursor.next();<br>}
在表5.1中,it是mongosh shell在查询并返回太多结果而无法在单个批次中显示时返回的迭代游标。
利用mongosh,您可以从客户端脚本化险些所有内容。它是原型设计和快速洞察数据的强大工具。
利用mongosh实行批量插入
如果您想利用shell以编程办法插入许多文档,最大略的实现是,由于您正在利用JavaScript shell,涉及通过循环迭代,顺序天生每个文档,并在每次迭代中实行写操作,如下所示:
authorMongoDBFactory = function() { for (let loop = 0; loop < 1000; loop++) { db.books.insertOne({ name: "MongoDB factory book" + loop }); }}
上述示例创建了一个authorMongoDBFactory()方法,为作者天生1000本书本在MongoDB上,每本书的名称略有不同:
> authorMongoDBFactory()
这将在数据库中发出1000次写操作。虽然从开拓角度来看这很大略,但这种方法可能会对数据库造成压力。
作为替代方案,您可以利用批量写入,在您事先准备好的1000个文档上发出单个数据库插入命令:
fastAuthorMongoDBFactory = function() { let bulk = db.books.initializeUnorderedBulkOp(); for (let loop = 0; loop < 1000; loop++) { bulk.insert({ name: "MongoDB factory book" + loop }); } bulk.execute();}> fastAuthorMongoDBFactory();
终极结果将与之前相同,将1000个文档插入到您的books凑集中,每个文档都遵照以下构造:
db.books.find({ name: /MongoDB factory/ });
用户视角的差异在于实行速率和对数据库的压力减少。
在上述示例中,利用initializeUnorderedBulkOp()进行批量操作构建器设置。这是由于您不须要担心插入的顺序与利用bulk.insert()命令将它们添加到批量变量中的顺序相同。当您可以确保所有操作彼此无关或幂等时,这是故意义的。
如果您想保留插入的顺序,您必须利用initializeOrderedBulkOp(),如下所示:
let bulk = db.books.initializeOrderedBulkOp();
不才一节中,您将看到如何利用mongosh进行批量操作以提高操作性能。
利用mongosh实行批量操作
在插入的情形下,操作的顺序是无关紧要的。然而,批量命令可以与不仅仅是插入的更多操作一起利用。在以下示例中,您在bookOrders凑集中有一本isbn为101的书本,名称值为Mastering MongoDB,可用字段表示可供购买的副本数量,设置为99本书:
db.bookOrders.find()
在单个批量操作中,实行以下一系列操作将涉及将一本书添加到库存中,然后连续购买100本书,导致终极计数为0本可供复制:
let bulk = db.bookOrders.initializeOrderedBulkOp();bulk.find({ isbn: 101 }).updateOne({ $inc: { available: 1 } });bulk.find({ isbn: 101 }).updateOne({ $inc: { available: -100 } });bulk.execute();
利用initializeOrderedBulkOp(),您可以确保在订购100本书之前添加一本书,这样您就不会缺货。相反,如果您利用initializeUnorderedBulkOp(),您就不会有这样的担保,您可能会在添加新书之前收到100本书的订单,导致逻辑缺点,由于您没有那么多的书来知足订单。
当通过有序的操作列表实行时,MongoDB将操作分成100,000个批次,并按操为难刁难这些批次进行分组。例如,如果您有100,004个插入,99,998个更新,100,004个删除和5个插入,您将终极得到以下结果:
[100,000 inserts][4 inserts][99,998 updates][100,000 deletes][4 deletes][5 inserts]
图5.2阐明了上述代码:
Figure 5.2: Bulk operations ordering
这不会不影响操作系列,但它隐含地意味着您的操作将以100,000个批次的办法离开数据库。这种行为在未来版本中不担保会保持不变。
把稳
从MongoDB 3.2开始,批量写入有一个替代命令:bulkWrite()。
在以下代码片段中,bulkWrite的参数包括您希望实行的操作序列,writeConcern(默认为1),以及写操作是否应按照它们在数组中涌现的顺序运用(它们将默认按顺序):
db.collection.bulkWrite( [ <operation 1>, <operation 2>, ... ], { writeConcern : <document>, ordered : <boolean> })
由批量支持的以下操作与相同:
insertOne()updateOne()updateMany()deleteOne()deleteMany()replaceOne()updateOne()、deleteOne()和replaceOne()具有匹配的过滤器。如果它们匹配了多个文档,它们将只操作第一个。主要的是要设计这些查询,以确保它们不匹配多个文档;否则,行为将是未定义的。
在本节中,您学习了如何为mongosh编写脚本。不才一节中,您将通过mongosh进行管理任务。
利用Ruby驱动程序实行CRUD操作
Ruby驱动程序最初由一位后来被MongoDB雇佣的外部社区成员掩护。随后,Ruby成为MongoDB官方支持的首批措辞之一,并拥有官方驱动程序。
MongoDB Ruby驱动程序包括一个集成的查询缓存。一旦激活,此缓存保留先前的find和聚合操作的结果。当这些查询再次实行时,驱动程序供应缓存的结果,肃清了冗余的数据库交互。本章稍后在Mongoid ODM部分将供应一个利用查询缓存的示例。
利用Ruby连接到MongoDB实例的推举行法是通过GitHub上的官方MongoDB Ruby驱动程序。
连接到数据库
向您的Gemfile添加mongo:
gem "mongo"
要手动安装驱动程序,请实行以下命令:
gem install mongo
然后,在您的类中,您可以按以下示例连接到数据库:
connection_string = "mongodb://HOST:PORT/DATABASE_NAME"client = Mongo::Client.new(connection_string)db = client.databasedb.collection_names # 返回凑集名称列表db.list_collections # 返回凑集元数据哈希列表
创建文档
考虑您有一个指向mongodb_book数据库中books凑集的@collection实例变量。要利用您的定义插入单个文档,请实行以下代码:
@collection = client[:books]document = { isbn: '101', name: 'Mastering MongoDB 7.0', price: 30 }result = @collection.insert_one(document)puts result.n
类似地,要插入两个isbn值分别为102和103的文档,利用insert_many代替insert_one:
documents = [ { isbn: '102', name: 'MongoDB in 7 years', price: 50 }, { isbn: '103', name: 'MongoDB for experts', price: 40 }]result = @collection.insert_many(documents)
结果工具现在是Mongo::BulkWrite::Result类,这意味着利用了BulkWrite接口以提高性能。紧张差异是您现在有一个属性inserted_ids,它可以返回从BSON::ObjectId类中插入工具的ObjectId:
#<Mongo::BulkWrite::Result:0x000055e707ea5d28 @results={"n_inserted"=>2, "n"=>2, "inserted_ids"=>[BSON::ObjectId('6521706eb2e05257537b2fea'), BSON::ObjectId('6521706eb2e05257537b2feb')]}, @acknowledged=true>
读取数据
查找文档的事情办法与创建文档相同,在凑集级别上:
@collection.find({ isbn: '101' })
可以链接多个搜索条件,等同于SQL中的AND运算符:
@collection.find({ isbn: '101', name: 'Mastering MongoDB 7.0' })
MongoDB Ruby驱动程序的CRUD功能供应了几个查询选项以优化查询。表5.2概述了一些最常用的查询选项。
表5.2: MongoDB Ruby驱动程序的查询选项
除了查询选项,MongoDB Ruby驱动程序还供应了一些可以在方法调用级别链式利用的赞助函数:
count_documents:获取符合指定过滤器的文档总数,或检索凑集中的文档总数。estimated_document_count:粗略估计凑集中存在的文档数量。请把稳,此方法不许可过滤。distinct(:field_name):区分前面查询的结果。find():返回一个包含结果集的游标,您可以利用Ruby中的.each进行迭代,例如:result = @collection.find({ isbn: '101' })result.each do |doc| puts doc.inspectend
书本凑集的输出将如下所示:
{"_id"=>BSON::ObjectId('65216d4bb2e05254b3022d2f'), "isbn"=>"101", "name"=>"Mastering MongoDB 7.0", "price"=>30}
在find()中链式操作
默认情形下,find()利用AND运算符匹配多个字段。如果您想利用OR运算符,您的查询须要类似于以下形式:
result = @collection.find('$or' => [{ isbn: '101' }, { isbn:'102' }]).to_aputs result
上述代码的输出如下:
{"_id"=>BSON::ObjectId('65216d4bb2e05254b3022d2f'), "isbn"=>"101", "name"=>"Mastering MongoDB 7.0", "price"=>30}{"_id"=>BSON::ObjectId('6521706eb2e05257537b2fea'), "isbn"=>"102", "name"=>"MongoDB in 7 days", "price"=>50}
您也可以在前面的示例中利用$and代替$or:
result = @collection.find('$and' => [{ isbn: '101' }, { isbn: '102' }]).to_aputs result
当然,这将不返回任何结果,由于没有任何文档可以同时拥有isbn值101和102。
嵌套操作
MongoDB Ruby驱动程序简化了插入具有嵌套构造的文档的过程。如下例所示,您可以创建一个文档,该文档具有顶级字段(isbn、name和price)以及包含其自身子字段的嵌套字段(meta)。然后,可以利用insert_one方法将文档插入MongoDB凑集:
document = { 'isbn': '104', 'name': 'Python and MongoDB', 'meta': { 'version': 'MongoDB 7.0' }, 'price': 60}@collection.insert_one(document)
在检索数据时,驱动程序供应了一个简洁的方法。您可以利用点表示法和find一起访问所需的嵌入数据:
result = @collection.find({ 'meta.version': 'MongoDB 7.0' }).to_aputs result
把稳
您须要用引号('')括起键名以访问嵌入工具,就像您须要在以开头的操作(如开头的操作(如set)中那样。
更新数据
要利用MongoDB Ruby驱动程序更新文档,首先必须定位或识别它们。以您的例子书本凑集为例,发出以下命令:
@collection.update_one({ 'isbn': '101'}, { '$set' => { name:'Mastering MongoDB 7.0' } })
这将找到isbn值为101的文档,并将名称变动为Mastering MongoDB 7.0。
类似于update_one,您可以利用update_many通过方法的第一个参数检索的多个文档进行更新。
删除数据
删除文档的事情办法与查找文档类似。您须要找到文档,然后运用删除操作。例如,利用您的书本凑集,发出以下代码:
@collection.find({ isbn: '101' }).delete_one
这将删除单个文档。在您的情形下,由于每个文档的isbn是唯一的,这是预期的。如果您的find()子句匹配了多个文档,那么delete_one将只删除find()返回的第一个文档,这可能或可能不是您想要的。
如果您想删除所有匹配find()查询的文档,请利用delete_many,如下所示:
@collection.find({ price: { $gte: 30 } }).delete_many
在前面的示例中,您正在删除所有价格大于或即是30的书本。
批量操作
您可以利用bulkWrite方法进行批量操作。如在创建文档部分中的多个文档插入示例中所见,这将类似于以下形式:
@collection.bulk_write([{ insertMany: documents }], { ordered: true });
bulkWrite方法支持以下参数:
insertOneupdateOneupdateManyreplaceOnedeleteOnedeleteMany以One结尾的方法只影响单个文档,纵然多个文档与供应的过滤器匹配。因此,在利用这些方法时,请确保您的过滤器准确针对单个文档,以防止意外操作。相反,以Many结尾的方法旨在对匹配过滤器标准的多个文档采纳行动。
Mongoid ODM
Mongoid是一个盛行的MongoDB的工具-文档映射器(ODM),为开拓者供应了一种在Ruby on Rails框架内与MongoDB数据库无缝且直不雅观的事情办法。虽然低级驱动程序供应了广泛的灵巧性,但Mongoid通过供应与Rails命名约定紧密对齐的更高层次的抽象,进一步提升了开拓者体验。这种和谐的集成简化了模式定义、查询和数据建模等任务,使您能够更多地关注运用逻辑,而不是数据库细节。就像ORM(工具关系映射器)一样,ODM(工具文档映射器)架起了模型和数据库之间的桥梁。在Rails中,Mongoid是最广泛利用的Ruby MVC框架,可以像Active Record一样用于建模您的数据。
安装Gem
安装Mongoid gem类似于MongoDB Ruby驱动程序。在Gemfile中添加一个文件,如下所示:
gem 'mongoid'
根据Rails的版本,您可能还须要在application.rb中添加以下内容:
config.generators do |g| g.orm :mongoidend
通过mongoid.yml配置文件连接到数据库。配置选项以键值对的形式通报,利用语义缩进。
读取数据
利用类似于Active Record的查询DSL查找文档。与利用关系数据库的Active Record一样,Mongoid将一个类分配给MongoDB凑集,并将任何工具实例分配给一个文档:
Book.find('592149c4aabac953a3a1e31e')
这将通过_id字段查找文档,并返回ISBN为101的文档,通过名称属性的查询也是如此:
Book.where(name: 'Mastering MongoDB')
类似于通过属性动态天生的查询,您可以利用赞助方法:
Book.find_by(name: 'Mastering MongoDB')
这个查询类似于您之前利用的名称属性。您可以启用QueryCache以避免对同一查询多次访问数据库:
Mongoid::QueryCache.enabled = true
这可以添加到您想要启用的任何代码块中,或者添加到Mongoid的初始化器中。
范围查询
您可以利用类方法在Mongoid中对查询进行范围限定,如下所示:
class Book include Mongoid::Document field :price, type: Float scope :premium, -> { where(price: { '$gt' => 20 }) }end
然后,您可以利用以下查询:
Book.premium
这个查询将找到价格大于20的书本。
创建、更新和删除
Mongoid创建文档的接口与您熟习的Active Record API类似:
Book.where(isbn: 202, name: 'Mastering MongoDB, 4th Edition').create
要更新文档,您可以利用update或update_all。利用update方法将只更新查询部分检索到的第一个文档,而update_all将更新所有文档:
Book.where(isbn: 202).update(name: 'Mastering MongoDB, 4th Edition')Book.where(price: { '$gt': 20 }).update_all(price_range:'premium')
删除文档类似于创建文档;您供应delete以跳过回调,destroy以实行受影响文档中的任何可用回调。
delete_all和destroy_all是用于多个文档的便捷方法。
利用Python驱动程序实行CRUD
Python是一种强大的编程措辞,当与FastAPI等框架配对时,供应了强大的Web开拓能力。对付Python与MongoDB的集成,您可以利用MongoEngine以及官方的MongoDB低级驱动程序PyMongo。PyMongo可以很随意马虎地利用pip安装:
$ python -m pip install pymongo
您可以利用以下连接片段测试与MongoDB支配的连接:
from pymongo import MongoClient# 用您的连接字符串更换占位符uri = "<connection string>"# 创建一个新的客户端并连接到做事器client = MongoClient(uri)# 发送一个ping以确认成功的连接try: client.admin.command('ping') print("Pinged your deployment. You successfully connected to MongoDB!")except Exception as e: print(e)
PyMongo是MongoDB官方支持的Python驱动程序,为Python编程的动态天下和高效、面向文档的NoSQL数据库MongoDB之间供应了无缝的桥梁。
除了PyMongo,MongoDB社区还有另一个主要工具:Motor。Motor是Python的官方异步驱动程序。在实时Web运用程序的时期和非壅塞操作的需求下,Motor许可您在Python的异步框架中利用MongoDB。这确保了高效的数据库操作,特殊是在I/O绑定场景下,例如处理许多同时用户的Web运用程序。Motor可以很随意马虎地利用pip安装:
$ python -m pip install motor
您可以利用以下连接片段测试利用asyncio异步框架的MongoDB支配在Atlas上的连接:
import asynciofrom motor.motor_asyncio import AsyncIOMotorClientfrom pymongo.server_api import ServerApiasync def ping_server(): # 用您的Atlas连接字符串更换占位符 uri = "<connection string>" # 在创建新客户端时设置Stable API版本 client = AsyncIOMotorClient(uri, server_api=ServerApi('1')) # 发送一个ping以确认成功的连接 try: await client.admin.command('ping') print("Pinged your deployment. You successfully connected to MongoDB!") except Exception as e: print(e)asyncio.run(ping_server())
这段代码利用了MongoDB Stable API特性。要利用此特性,请确保您在连接到MongoDB Server版本5.0及以上时利用的是2.5或更新版本的Motor驱动程序。
不才一节中,您将看到如何利用PyMongo在MongoDB中创建、读取、更新和删除文档。
插入文档
MongoDB的Python驱动程序供应了一套全面的CRUD API,类似于Ruby中供应的。这使得利用Python与MongoDB凑集交互变得大略。
以下是演示如何将文档插入到mongodb_books数据库中的books凑集的大略示例:
# 利用'mongodb_books'数据库和'books'凑集books = client.mongodb_books.books# 插入一个新的书本文档book = { 'isbn': '301', 'name': 'Python and MongoDB', 'meta': {'version': 'MongoDB 7.0'}, 'price': 60}insert_result = books.insert_one(book)pprint(insert_result)
实行脚本后,将显示插入结果,然后是新插入的文档:
[{'_id': ObjectId('6521ae0a0e542d46b87947a4')}]
在上面的示例中,利用insert_one()方法插入单个文档。该文档利用Python的字典表示法构建。随后,您可以查询凑集以检索并显示其所有文档。
查找文档
当您想基于特定属性检索文档时,过程是直不雅观的。对付顶级属性,一个带有所需键值对的字典就可以见效。
以下是演示如何在mongodb_books数据库的books凑集中根据书名查找文档的示例:
# 利用'mongodb_books'数据库和'books'凑集books = client.mongodb_books.books# 查找名称为"Python and MongoDB"的文档result = books.find({"name": "Python and MongoDB"})# 打印获取的文档for document in result: pprint(document)
上述脚本打印了books凑集中所有名称为Python and MongoDB的文档。如果之前插入的文档存在于凑集中,您将在掌握台看到其详细信息:
{ '_id': ObjectId('6521ae0a0e542d46b87947a4'), 'isbn': '301', 'name': 'Python and MongoDB', 'meta': {'version': 'MongoDB 7.0'}, 'price': 60}
要检索嵌入文档中特定字段的文档,您可以利用点表示法。不才面的示例中,利用metadata.version来定位嵌入在meta文档中的版本字段:
query = { 'meta.version': { "$regex": ".?g.?7\.0$", "$options": "i" }}# 查找匹配查询的文档result = books.find(query)# 打印获取的文档for document in result: pprint(document)
在示例中,利用正则表达式搜索以7.0结尾并可能包含字母g的字符串模式在metadata.version字段中的任何涌现。由于参数设置为,此搜索不区分大小写。这种方法利用了中的options参数设置为i,此搜索不区分大小写。这种方法利用了PyMongo中的regex表示法,它对应于MongoDB处理正则表达式的方法。实行此脚本,您可以检索和显示在mongodb_books数据库的books凑集中,其metadata.version字段匹配此特定模式的文档。
比较运算符也以类似的办法得到支持。常见的比较运算符包括(即是)、eq(即是)、gt(大于)、(大于或即是)、gte(大于或即是)、lt(小于)、(小于或即是)和lte(小于或即是)和ne(不即是)。下面是一个示例:
# 利用$gt比较运算符定义查询query = { 'price': { "$gt": 50 }}# 查找匹配查询的文档result = books.find(query)# 打印获取的文档for document in result: pprint(document)
脚本返回了两个价格大于50的文档。两个都被称为Python and MongoDB,价格为60美元,但它们有不同的ISBN和元数据:
{ '_id': ObjectId('6521ae0a0e542d46b87947a4'), 'isbn': '301', 'name': 'Python and MongoDB', 'meta': {'version': 'MongoDB 7.0'}, 'price': 60}{ '_id': ObjectId('6521c1a0379c18f8df180e57'), 'isbn': '302', 'meta': {'version': 'MongoDB 7.0'}, 'name': 'Python and MongoDB', 'price': 60}{ '_id': ObjectId('6521d7e309731cfd8fa0ca04'), 'isbn': '303', 'name': 'Advanced MongoDB Techniques', 'price': 70}
将多个字典添加到查询结果中的逻辑AND查询:
# 定义具有逻辑AND条件的查询query = { 'name': 'Advanced MongoDB Techniques', 'price': 70}# 查找匹配查询的文档result = books.find(query)# 打印获取的文档for document in result: pprint(document)
您可以检讨结果:
{ '_id': ObjectId('6521d7e309731cfd8fa0ca04'), 'isbn': '303', 'name': 'Advanced MongoDB Techniques', 'price': 70}
现在,利用$or运算符查询books凑集,检索名称为Advanced MongoDB Techniques或ISBN号为301的文档:
# 定义具有$or条件的查询query = { "$or": [ {'name': 'Advanced MongoDB Techniques'}, {'isbn': '301'} ]}# 查找匹配查询的文档result = books.find(query)# 打印获取的文档for document in result: pprint(document)
结果将如下所示:
{ '_id': ObjectId('6521ae0a0e542d46b87947a4'), 'isbn': '301', 'name': 'Python and MongoDB', 'meta': {'version': 'MongoDB 7.0'}, 'price': 60}{ '_id': ObjectId('6521d7e309731cfd8fa0ca04'), 'isbn': '303', 'name': 'Advanced MongoDB Techniques', 'price': 70}
更新文档
在以下代码块中,您将看到一个利用update_one赞助方法更新单个文档的示例。此操作在搜索阶段匹配一个文档,并根据要运用于匹配文档的操作修正一个文档:
# 更新名称为"Advanced MongoDB Techniques"的书的价格update_result = books.update_one( {"name": "Advanced MongoDB Techniques"}, {"$set": {"price": 75}} # 将新价格设置为75)# 打印更新操作的结果pprint(update_result.raw_result)# 获取更新后的文档以验证变动updated_document = books.find_one({"name": "Advanced MongoDB Techniques"})pprint(updated_document)
此脚本将把标题为Advanced MongoDB Techniques的书的价格更新为75。更新操作后,它获取并打印更新后的文档以验证变动:
{'n': 1, 'nModified': 1, 'ok': 1.0, 'updatedExisting': True}{ '_id': ObjectId('6521d7e309731cfd8fa0ca04'), 'isbn': '303', 'name': 'Advanced MongoDB Techniques', 'price': 75}
删除文档
PyMongo中的delete_one方法许可您根据指定的过滤器从凑集中删除单个文档。如果您想删除符合某些条件的多个记录,PyMongo供应了delete_many方法。当您想从数据集中删除特定记录或一组记录时,这特殊有用。让我们看一个delete_one的示例:
# 要删除的书的ISBN号isbn_to_delete = '303'# 删除指定ISBN号的书delete_result = books.delete_one({"isbn": isbn_to_delete})# 打印删除操作的结果pprint(delete_result.raw_result)
结果表明删除操作成功。详细来说,'n': 1表示删除了一个文档,'ok': 1.0确认操作实行没有缺点:
{'n': 1, 'ok': 1.0}
正则表达式
在MongoDB中查询时,您须要考虑几个问题。让我们看看利用正则表达式、查询结果、游标和删除文档的最佳实践:
db.books.find({"name": /mongo/})
这是为了搜索books凑集中包含mongo名称的书本。它等同于SQL LIKE查询。
把稳
MongoDB利用Perl兼容的正则表达式(PCRE)版本8.42,支持UTF-8。
在查询时,您可以利用以下选项:
选项
描述
i
此选项查询不区分大小写。
m
此选项仅适用于具有锚点的多行字符串( 表示开始,$ 表示结束)。在这种情形下,定义m选项将匹配每行的开头或结尾的模式。如果没有m选项,锚点将匹配字符串的开头或结尾。
表5.3: 正则表达式的查询选项
在前面的示例中,如果您想搜索mongo、Mongo、MONGO或任何其他不区分大小写的变体,您须要利用i选项,如下所示:
db.books.find({"name": /mongo/i})
或者,您可以利用运算符,它供应了更多的灵巧性。利用regex运算符,它供应了更多的灵巧性。利用regex的相同查询如下所示:
db.books.find({'name': { '$regex': /mongo/ }})db.books.find({'name': { '$regex': /mongo/i }})
通过利用$regex运算符,您还可以利用下表中显示的选项:
选项
描述
x
此选项忽略$regex模式中的所有空缺字符。它还忽略未转义的井号或英镑符号字符以及下一个换行符之间的任何内容。这可以用来包含注释。如果字符包含在字符类中或以其他办法转义,则此选项将不会产生任何效果。它不会对处理VT字符产生任何影响。
s
此选项许可点字符(即.)匹配所有字符,包括换行符。
表5.4: $regex运算符的查询选项
利用$regex运算符扩展匹配文档会使您的查询实行变慢。利用正则表达式的索引只能在您的正则表达式查询索引字符串的开头时利用;即,以^或\A开头的正则表达式。如果您只想利用带有正则表达式的字符串进行查询,应避免编写更长的正则表达式,纵然它们匹配相同的字符串。
以以下代码块为例:
db.books.find({ 'name': { '$regex': /mongo/ } });db.books.find({ 'name': { '$regex': /^mongo./ } });
两个查询都将匹配以mongo开头的名称值(不区分大小写),但第一个查询会更快,由于它将在每个名称值的第六个字符处停滞匹配。
管理
由于其非关系型、无模式的设计,与MongoDB的集成供应了无缝的体验。没有模式迁移的约束,您可以简化数据库操作,从而最小化数据库管理开销。
然而,为了在MongoDB中得到最佳速率和性能,有履历的MongoDB开拓职员或架构师可以实行各种任务。管理常日涵盖四个不同层次,每个层次的粒度逐渐增加:进程、数据库、凑集和索引。
在进程层面,有shutDown命令来关闭MongoDB做事器。
在数据库层面,您有以下命令:
dropDatabase:删除全体数据库listCollections:检索当前数据库中的凑集名称比较之下,在凑集层面,利用以下命令:
drop:删除凑集create:创建凑集renameCollection:重命名凑集cloneCollectionAsCapped:将凑集克隆为新的固定凑集convertToCapped:将凑集转换为固定凑集。然而,MongoDB在分片集群中不支持convertToCapped命令compact:在WiredTiger数据库年夜将不须要的磁盘空间开释给操作系统在索引层面,您可以利用以下命令:
createIndexes:在当前凑集中创建新索引listIndexes:列出当前凑集中的现有索引dropIndexes:从当前凑集中删除所有索引reIndex:删除并重新创建当前凑集中的索引createSearchIndexes:在指定的凑集上创建一个或多个Atlas Search索引dropSearchIndex:删除现有的Atlas Search索引updateSearchIndex:更新现有的Atlas Search索引接下来的部分将重点先容从管理角度来看更主要的一些其他命令。
currentOp()和killOp()
db.currentOp()返回一个包含mongod实例正在进行的操作信息以及操作ID的文档。
killOp()根据指定的操作ID终止一个操作。始终要非常谨慎地终止正在运行的操作。仅利用killOp()终止由客户端发起的操作,不要终止内部数据库操作。
killOp()命令的利用方法如下:
db.adminCommand( { killOp: 1, op: <opid>, comment: <any> })
collMod
collMod许可您向凑集添加选项或修正视图定义。例如,您可以添加一个索引选项,该选项可以变动现有索引的属性,或者您可以添加一个验证器,许可用户为凑集指定验证规则或表达式。您还可以调度固定凑集的大小或修正韶光序列凑集。
例如,查看文档验证选项。文档验证可以指定一组规则,运用于对凑集的新更新和插入。这意味着如果当前文档被修正,它们将被检讨。
您只能对已经有效的文档运用验证,如果您将validationLevel设置为moderate。通过指定validationAction,您可以通过将其设置为warn来记录无效的文档,或者通过将其设置为error来阻挡更新发生。
例如,利用前面的bookOrders示例,您可以在每个插入或更新时设置isbn和name字段的验证器,如下代码片段所示:
db.runCommand({ collMod: "bookOrders", validator: { $and: [ { "isbn": { $exists: true } }, { "name": { $exists: true } } ] }});
现在,当您考试测验仅利用isbn字段插入一个新文档时,您将得到一个缺点,如下所示:
db.bookOrders.insertOne({ isbn: 102 })Uncaught:MongoServerError: Document failed validationAdditional information: { failingDocumentId: ObjectId("6521162942094e44892aa6f6"), details: { operatorName: '$and', clausesNotSatisfied: [ { index: 1, details: { operatorName: '$exists', specifiedAs: { name: { '$exists': true } }, reason: 'path does not exist' } } ] }}
这是由于您的验证失落败了。从shell管理验证很有用,由于您可以编写脚本来管理它,并确保统统都就绪。
在理解如何管理您的MongoDB做事器后,您将理解如何不才一节中通过认证和授权保护对MongoDB的访问。
保护对MongoDB的访问
随着存储在数据库中的数据量和敏感性的增长,强大的安全方法的主要性变得至关主要。MongoDB认识到这一点,并设计了一系列安全工具和协议,以确保您的数据免受未经授权的访问和潜在的违规行为的保护。它供应了各种功能,如认证、访问掌握和加密,以保护您的MongoDB支配。理解辅导MongoDB数据库安全方法的总体原则至关主要。
认证和授权
认证和授权紧密相连。认证是验证客户端身份的过程。当启用访问掌握(授权)时,MongoDB哀求所有客户端都必须进行身份验证,以确定他们的访问权限。
授权是关于确定用户可以在资源上实行哪些操作。在接下来的部分中,您将根据这些定义探索认证和授权。您还将根据最新版本检讨MongoDB的一些安全提示。
MongoDB的授权
MongoDB最基本的授权依赖于用户名/密码方法。要启用它,您须要利用-auth参数启动做事器,如下所示:
mongod --auth
localhost非常
localhost非常许可您启用访问掌握,然后在系统中建立初始用户或角色。一旦激活访问掌握,您可以连接到localhost接口,在admin数据库中设置第一个用户。对付mongod实例,此localhost非常仅在MongoDB环境中尚未定义任何用户或角色时才干系。
设置第一个管理员用户很大略,如下代码片段所示:
use admindb.createUser( { user: <adminUser>, pwd: passwordPrompt(), // 或者 "<明文密码>" roles: [ { role: <adminRole>, db: "admin" } ] })
这里,<adminUser>是您要创建的用户的名称,<cleartext password>是密码,<adminRole>可以是以下值之一,从最强大的到最不强大的自托管支配,如下列表所示:
rootdbAdminAnyDatabaseuserAdminAnyDatabasereadWriteAnyDatabasereadAnyDatabasedbOwnerdbAdminclusterAdminclusterManagerclusterMonitorhostManagerbackuprestoreuserAdminreadWritereadMongoDB Atlas还有一些专门用于Atlas的内置角色,如atlasAdmin。
在这些角色中,root是许可访问统统的超级用户。然而,除非在分外情形下,不建议利用。
所有AnyDatabase角色都供应对所有数据库的访问权限,个中dbAdminAnyDatabase结合了userAdminAnyDatabase和readWriteAnyDatabase的范围,再次成为所有数据库的管理员。
数据库中定义的别的角色适用于您希望它们适用的数据库。通过变动前面的db.createUser();中roles子文档;例如,如果您想为您的mongodb_book数据库创建一个dbAdmin角色,您可以利用以下代码:
use admindb.createUser( { user: "adminUser", pwd: "passwordPrompt()", // 或者 "<明文密码>" roles: [ { role: "adminRole", db: "admin" } ] })
认证和授权是任何生产级MongoDB系统的必备条件条件。有关安全实践的更深入信息,请参阅第15章“安全”。本章将帮助您理解如何确保对您的MongoDB支配进行强有力的保护。
MongoDB稳定API
MongoDB 5.0引入了稳定API,它供应了一个担保,即客户端与做事器通信的API不会毁坏。稳定API在利用任何驱动程序或mongosh时声明,类似于以下mongosh示例:
mongosh --apiVersion 1
把稳
截至MongoDB 7.0,1是唯一可用的API版本。
稳定API担保了MongoDB做事器升级之间的向后兼容性。这意味着您可以连续升级MongoDB做事器,而不会有任何重大风险,即连接到MongoDB做事器的运用程序将有不同的行为。
此担保在以下三个约束条件下精确:
您须要在客户端中声明apiVersion您须要利用受支持的官方MongoDB客户真个版本您只能利用此API版本中支持的命令和功能遵照第三个约束条件,截至apiVersion='1',您可以利用以下命令:
命令
稳定API版本
添加到稳定API的版本
count
V1
MongoDB 6.0, 5.0.9
abortTransaction
V1
MongoDB 5.0
aggregate
V1
MongoDB 5.0
authenticate
V1
MongoDB 5.0
collMod
V1
MongoDB 5.0
commitTransaction
V1
MongoDB 5.0
create
V1
MongoDB 5.0
createIndex
V1
MongoDB 5.0
delete
V1
MongoDB 5.0
drop
V1
MongoDB 5.0
dropDatabase
V1
MongoDB 5.0
dropIndex
V1
MongoDB 5.0
endSession
V1
MongoDB 5.0
explain
V1
MongoDB 5.0
find
V1
MongoDB 5.0
findAndModify
V1
MongoDB 5.0
getMore
V1
MongoDB 5.0
insert
V1
MongoDB 5.0
hello
V1
MongoDB 5.0
killCursors
V1
MongoDB 5.0
listCollections
V1
MongoDB 5.0
listDatabases
V1
MongoDB 5.0
listIndexes
V1
MongoDB 5.0
ping
V1
MongoDB 5.0
refreshSessions
V1
MongoDB 5.0
update
V1
MongoDB 5.0
表5.5: 稳定API命令及其对应的MongoDB版本
表中带有(有限定)注释的方法仅部分受到稳定API担保的支持。您还可以将apiStrict布尔标志设置为True,以禁止客户端利用未列入白名单的命令。在这种情形下,MongoDB将返回一个apiStrictError。
把稳
apiStrict默认为False。
总结
本章磋商了CRUD操作的根本知识。从mongosh开始,您学习了如何插入、删除、读取和修正文档,并理解了一次性插入和批量插入数据之间的差异,以提高性能。此外,本章还谈论了管理任务以及如何在mongosh中实行这些任务。末了,本章简要先容了MongoDB的安全和认证、新版本方案和新shell mongosh。
下一章将磋商MongoDB模式设计原则和技能,以实现有效的数据表示——这对付优化性能和可扩展性至关主要。