MongoDB在数据库管理领域的突出地位
MongoDB作为一种强大、灵活且可扩展的NoSQL解决方案,在数据库管理领域脱颖而出。随着企业和开发者逐渐适应以数据为中心的范式,对数据库与各种编程语言无缝集成的需求变得日益重要。
无论您是一位希望扩展工具包的经验丰富的开发者,还是一位渴望将MongoDB集成到不同开发环境中的初学者,本章都旨在提供清晰的逐步指导。
本章将涵盖以下主题:
- 直接驱动程序方法
- 对象-文档映射(ODM)库
- MongoDB在PHP、Python、Ruby和Node.js以及TypeScript中的集成
- 连接方法
MongoDB提供的连接方法
MongoDB提供了多种连接数据库的方法,从直接驱动程序交互到对象-文档映射(ODM)层的便利性,后者优雅地处理模型对象的映射。虽然MongoDB拥有广泛的语言支持,包括但不限于Java、C++、C#、Kotlin和Rust,但本章重点关注四种独特且广泛使用的语言—PHP、Ruby、Node.js和Python。每种语言都提供了一套独特的功能和优势,需要量身定制的连接技术来充分发挥MongoDB的潜力。
使用Ruby连接
Ruby是MongoDB支持的语言中的佼佼者,拥有一个提供卓越兼容性的官方驱动程序。要成功建立到本地MongoDB主机的连接,请遵循以下简单步骤:
要安装,您必须向Gemfile添加驱动程序,如下例所示:
gem 'mongo'
然后,您可以按如下例所示连接到数据库:
require 'mongo'
client = Mongo::Client.new(['127.0.0.1:27017'], database: 'test')
或者,您也可以使用URI连接字符串:
require 'mongo'
client = Mongo::Client.new('mongodb://127.0.0.1:27017/test')
这是最简单的示例:连接到本地主机上名为test的单个数据库实例。在大多数用例中,您至少会有一个副本集要连接,如下段所示:
client_host = ['server1_host:server1_port_number, server2_host:server2_port_number']
client_options = {
database: 'YOUR_DATABASE_NAME',
replica_set: 'REPLICA_SET_NAME',
user: 'YOUR_USERNAME',
password: 'YOUR_PASSWORD'
}
client = Mongo::Client.new(client_host, client_options)
或者您可以按如下代码段所示使用URI语法连接:
client = Mongo::Client.new("mongodb://127.0.0.1:27017,127.0.0.1:27018/mydb")
client_host服务器作为客户端驱动程序的种子服务器,提供可用于连接的服务器列表。一旦连接,驱动程序会根据主/从读写配置确定要连接的适当服务器。要建立成功的连接,replica_set属性必须与指定的REPLICA_SET_NAME匹配。用户名和密码是可选的,但在任何MongoDB实例中都强烈推荐使用。在mongod.conf文件中默认启用认证是个好习惯。连接到分片集群的过程与副本集类似,有一个关键区别。不是提供服务器主机/端口,而是连接到作为MongoDB路由器的MongoDB进程。
require 'mongo'
# 假设mongos在localhost上运行
# 并使用默认端口27017
client = Mongo::Client.new(['localhost:27017'], :database =>'my_sharded_database')
您可以按如下示例连接到共享集群:
require 'mongo'
# 假设mongos在localhost上运行
# 并使用默认端口27017
client = Mongo::Client.new(['localhost:27017'], :database =>'my_sharded_database')
如果您有多个mongos实例以实现高可用性,您只需在数组中扩展主机列表:
require 'mongo'
# 连接到多个mongos实例
client = Mongo::Client.new(['mongos1_host:27017', 'mongos2_host:27017', 'mongos3_host:27017'], :database => 'my_sharded_database')
现在您已经学会了如何使用Ruby库连接,下一节将介绍如何使用ODM库。
Mongoid
Mongoid ODM是连接MongoDB与您的Ruby或Rails应用程序的简化选择。它不仅保持了Ruby驱动程序固有的灵活性,还通过减少开发时间和代码量来优化了过程。与对象关系映射(ORM)解决方案工具类似,ODMs无缝地弥合了您的模型和数据库之间的差距。
Mongoid ODM的好处包括:
- 数据抽象:Mongoid提供了一个更高层次的编程接口,允许您使用对象而不是直接处理文档表示来与数据库交互。
- 一致性:通过使用Mongoid提供的标准化接口,您可以确保整个应用程序中数据访问模式保持一致。
- 减少样板代码:Mongoid自动化了许多重复的数据库操作,这可以减少您需要编写和维护的代码量。
- 模式管理和验证:尽管MongoDB是无模式的,但Mongoid允许定义模式,提供了一种在存储数据之前验证数据的结构化方式。
- 优化性能:Mongoid通过实现缓存机制提供性能优势。
- 中间件和插件:ODM可能支持在数据库操作的不同阶段执行的中间件或插件,为自定义逻辑、数据转换、日志记录等提供钩子。
- 轻松过渡:如果您熟悉关系数据库世界的ORM,Mongoid在过渡到MongoDB时可能感觉更直观。
- 无缝集成:Mongoid弥合了应用程序模型和底层MongoDB数据库之间的差距,确保了平稳的数据转换和处理。
- 支持事务:Mongoid提供事务支持,确保任何一系列操作以原子方式执行。
对于使用Ruby最流行的MVC框架—Ruby on Rails—的用户来说,Mongoid是一个典范工具,以优雅和简洁的方式对数据进行建模,让人想起Active Record。
可以通过如下修改Gemfile将mongoid gem添加到您的应用程序中:
gem 'mongoid'
您可能需要通过向application.rb添加以下内容来为您的Rails应用程序配置ORM以使用Mongoid:
config.generators do |g|
g.orm :mongoid
end
通过mongoid.yml配置文件建立数据库的连接。配置选项以键值对的形式传递,使用语义缩进。mongoid.yml配置文件类似于用于关系数据库的database.yml。
通过mongoid.yml文件传递的配置选项
您可以在mongoid.yml文件中传递的一些选项包括:
表4.1:Mongoid配置选项
选项 | 描述 |
database | 数据库名称 |
hosts | 数据库主机 |
write/w | 写入关注(默认 = { w: 1 }) |
auth_mech | 认证机制。有效选项包括::aws, :gssapi, :mongodb_cr, :mongodb_x509, :plain, :scram, 和 :scram256 |
min_pool_size/max_pool_size | 连接池中的最大和最小连接数。默认值:min_pool_size: 1 max_pool_size: 5 |
ssl, ssl_cert, ssl_key, ssl_key_pass_phrase, ssl_verify | SSL配置和选项 |
include_root_in_json | 在JSON序列化中包含根模型名称(默认:false) |
include_type_for_serialization | 在序列化中包含_type字段(默认:false) |
适应MongoDB的模型
要将模型存储在MongoDB中,只需在模型声明中包含一行代码,如下例所示:
class Person
include Mongoid::Document
include Mongoid::Timestamps
end
如上所示添加Mongoid::Timestamps将确保以类似于Active Record的方式生成created_at和updated_at字段。
数据字段不需要在模型中按类型声明,但这样做是一个好习惯。支持的数据类型包括:
表4.2:数据类型及其描述
数据类型 | 别名 | 描述 |
ObjectId | - | ObjectId是小的、可能是唯一的、快速生成的和有序的。ObjectId值长度为12字节,包括:一个4字节的时间戳,表示ObjectId的创建,以Unix纪元(1970年1月1日)以来的秒数测量;一个5字节的随机值,每个进程生成一次。这个随机值对于机器和进程是唯一的;一个3字节的递增计数器,初始化为一个随机值。 |
Double | double | 浮点数 |
String | String | 有效的UTF-8字符字符串 |
Object | Object | 嵌入式文档,可以包含一个或多个字段 |
Array | Array | 值的列表 |
Binary data | binData | 任何二进制数据 |
Boolean | Bool | 布尔值(true或false) |
Date | Date | BSON日期类型,存储自Unix纪元以来的毫秒数 |
Null | Null | 空值 |
Regular expression | Regex | 存储JavaScript正则表达式 |
JavaScript | Javascript | 与JavaScript类型相同,但具有作用域(一组具有值的变量) |
32-bit integer | Int | 32位整数值 |
Timestamp | timestamp | BSON时间戳类型 |
64-bit integer | Long | 64位整数值 |
Decimal128 | decimal | 128位基于小数的浮点数。适用于表示精确的货币值 |
Min key | minKey | 小于所有其他可能的BSON值的值 |
Max key | maxKey | 大于所有其他可能的BSON值的值 |
显式定义字段类型可以提高性能并支持所有数据类型。如果您没有显式定义字段类型,MongoDB将把字段转换为对象并将其存储在数据库中。
然而,这种方法并不支持所有数据类型,例如BigDecimal、Date、DateTime或Range。如果您尝试使用这些数据类型,将会出现错误。
Mongoid模型的继承
以下代码是使用Mongoid模型的继承示例:
class Canvas
include Mongoid::Document
field :name, type: String
embeds_many :shapes
end
class Shape
include Mongoid::Document
field :x, type: Integer
field :y, type: Integer
embedded_in :canvas
end
class Circle < Shape
field :radius, type: Float
end
class Rectangle < Shape
field :width, type: Float
field :height, type: Float
end
在上述示例中,您有一个Canvas类,其中嵌入了许多Shape对象。Mongoid将自动创建一个字段,即_type,以区分父子节点字段。当文档从其字段继承时,关系、验证和作用域将传播到子文档。
相反的情况不会发生;使用embeds_many和embedded_in对会创建嵌入式子文档以存储关系。如果您想通过引用ObjectId来存储这些关系,可以通过将它们替换为has_many和belongs_to来实现。
使用Python连接
另一种连接选项是使用Python。像Mongoid ODM用于Ruby一样,MongoEngine ODM也存在于Python中,以及官方的MongoDB Python驱动程序PyMongo。
可以使用pip或easy_install安装PyMongo,如下所示:
python -m pip install pymongo
python -m easy_install pymongo
注意
所需的PyMongo最低版本是4.4,Python的最低版本是3.7。
然后,您可以在类中按如下示例连接到数据库:
from pymongo import MongoClient
client = MongoClient()
连接到副本集需要副本集的一个或多个成员,以便客户端能够找出集合中的主节点、辅助节点或仲裁节点,如下所示:
client = pymongo.MongoClient('mongodb://user:passwd@node1:port1,node2:port2,node3:port3/?replicaSet=rsname')
使用连接字符串,您可以在单个字符串中传递用户名、密码和副本集名称。连接字符串URL的一些最有趣的选项将在下一节中介绍。
连接到分片需要mongos服务器的服务器主机和IP。
MongoEngine ODM
MongoEngine为从Python与MongoDB交互提供了一种强大的方式,将MongoDB的灵活性与熟悉的Pythonic API相结合。它更适合从关系数据库和ORM转型的开发者。然而,像任何工具一样,了解其优势和局限性对于有效使用至关重要。
可以通过pip安装mongoengine,如下所示:
pip install mongoengine
始终确保您使用的MongoEngine版本与安装的MongoDB版本兼容。
选项必须是成对的name=value,每对之间用&分隔。一些有趣的选项显示在表4.3中。
表4.3:MongoEngine配置选项
选项 | 描述 |
max_pool_size/min_pool_size | 连接池中的最大和最小连接数 |
W | 写入关注 |
w_timeout | 写入关注操作的超时时间 |
Journal | 日志选项 |
read_preference | 用于副本集,以下选项有效:Primary, primaryPreferred, secondary, secondaryPreferred, nearest |
maxStalenessSeconds | 指定秒数,指示副本集中的辅助节点在客户端停止用于读取操作之前可以落后主节点的数据多少 |
Ssl | SSL配置和选项 |
authentication_source | 与用户名一起使用,并指定与用户凭据相关联的数据库 |
当使用外部认证机制时,此选项应为$external,用于LDAP或Kerberos | |
authentication_mechanism | 认证机制,以下选项有效:SCRAM-SHA-1, SCRAM-SHA-256, MONGODB-X509, MONGODB-AWS |
MongoDB Enterprise提供两个更多选项:GSSAPI (Kerberos), PLAIN (LDAP SASL) |
以下代码展示了定义文档的示例类:
from mongoengine import Document, StringField
class User(Document):
email = StringField(required=True, unique=True, primary_key=True)
name = StringField(max_length=50)
这个User类有name和email字段,其中email是主字段。
像任何对象-文档映射器或对象-关系映射器一样,MongoEngine引入了一些开销。虽然这种开销通常可以忽略不计,并且通过提高开发者生产力得到了补偿,但对于性能关键型应用,直接考虑PyMongo(MongoDB的原生Python驱动程序)可能是一个值得考虑的选项。
使用PHP连接
MongoDB的PHP驱动程序的架构由多层组成,如图4.1所示。
图4.1:PHP驱动程序架构
这堆栈的顶部是一个PHP库,作为Composer包分发。这个库提供了与其他MongoDB驱动程序一致的API。在该库下方是一个PHP扩展,通过PECL分发。该扩展是PHP和MongoDB的系统库(libmongoc、libbson和libmongocrypt)之间的粘合剂。虽然可以直接使用该扩展,但该库具有最小的开销,应该是大多数使用MongoDB构建的应用程序的常见依赖项。
安装是一个两步过程:
第一步是安装MongoDB扩展。这个扩展依赖于您安装的PHP版本,可以使用PECL完成。
pecl install mongodb
使用MongoDB 7.0的最低要求是PHP 7.2和PHP Driver ext + lib 1.16。
然后,在您的php.ini文件末尾复制并放置以下行:
extension=mongodb.so
php --ri mongodb输出应引用libmongoc和libmongocrypt。
第二步是使用composer(PHP的广泛使用的依赖管理器),如下例所示:
composer require mongodb/mongodb
要连接到数据库,使用连接字符串和选项数组创建客户端实例:
$client = new MongoDB\Client('mongodb://myUsername:myPassword@rs1.example.com,rs2.example.com/?ssl=true&replicaSet=myReplicaSet&authSource=admin');
或者,您可以使用$uriOptions集来传递参数,而无需使用连接字符串:
$client = new MongoDB\Client(
'mongodb://rs1.example.com,rs2.example.com/',
[
'username' => 'myUsername',
'password' => 'myPassword',
'ssl' => true,
'replicaSet' => 'myReplicaSet',
'authSource' => 'admin',
],
);
$uriOptions集和连接字符串选项与Ruby和Python中使用的选项类似。
Eloquent ORM
Laravel以其优雅的语法和表达性编码风格而闻名,特别是在其Eloquent ORM中表现得尤为明显。Eloquent为与数据库交互提供了一个丰富、流畅的接口,特别是以其活动记录实现而闻名,与Doctrine的数据映射器模式形成对比。
要开始使用Eloquent与MongoDB,您需要安装将Laravel的Eloquent ORM与MongoDB桥接的包。要安装,请运行以下Composer命令:
composer require mongodb/laravel-mongodb
定义Eloquent模型
MongoDB的Eloquent模型定义与其他Eloquent模型一样,只是它们扩展自不同的Model基类。这里是一个设计用于与MongoDB一起工作的示例模型:
namespace App\Models;
use MongoDB\Laravel\Eloquent\Model;
class Students extends Model{
protected $connection = 'mongodb';
protected $collection = 'students';
protected $fillable = ['firstname', 'lastname'];
// 定义与'Class'模型的关系
public function classes() {
return $this->hasMany(Class::class);
}
public function address() {
return $this->embedsOne(Address::class);
}
public function Grades() {
return $this->embedMany(Grade::class);
}
}
这个Laravel模型示例展示了如何将MongoDB与Eloquent ORM一起使用,突出了三种关键的关系类型:hasMany用于一对多关系,embedsOne用于定义单个嵌入式文档嵌套在另一个文档中的关系,embedMany用于定义多个嵌入式文档嵌套在单个父文档中的关系。这些关系示例说明了Laravel如何优雅地处理MongoDB中的关联和嵌入式文档结构。
使用Node.js连接
Node.js是一个开源的、跨平台的运行时环境,因其卓越的性能而成为最受欢迎的Web技术之一。MongoDB和Node.js,以及Express.js(一个Node.js Web框架)和React.js(一个客户端JavaScript框架),已成为众所周知的MERN堆栈。这四个组合的力量来自于它们都建立在JavaScript之上,允许创建全栈Web解决方案。这使得工程师们不必学习多种语言,也不必花费宝贵的时间试图使它们协同工作。如今,已经有几个使用MERN构建的内容管理系统(CMS),如Strapi。
因此,介绍如何使用Node.js连接MongoDB至关重要。可以使用Node.js驱动程序,可以通过Node包管理器(NPM)安装,如下所示:
npm install mongodb
然后,您可以在代码中按如下示例连接到数据库:
const { MongoClient } = require("mongodb");
// 用您的连接字符串替换uri字符串。
const uri = "mongodb://user:pass@host:27017/?w=majority";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db('productions');
const movies = database.collection('movies');
// 查询标题为'200 meters'的电影
const query = { title: '200 meters' };
const movie = await movies.findOne(query);
console.log(movie);
} finally {
// 确保在完成/错误时关闭客户端
await client.close();
}
}
run().catch(console.dir);
连接到副本集需要一组种子服务器,以便客户端能够找出集合中的主节点、辅助节点或仲裁节点,如下所示:
const uri = "mongodb://user:pass@host1:27017,host2:27017,host3:27017/?replicaSet=mySet";
const client = new MongoClient(uri);
使用连接字符串,您可以在单个字符串中传递用户名、密码和副本集名称。连接字符串的一些最有趣的选项将在下一节中介绍。
连接字符串结构
您必须使用具有以下结构的连接字符串:
mongodb://[username:password@]host1[:port1][,host2[:port2],... [,hostN[:portN]]][/[database][?options]]
选项必须是name=value对,每对之间用&分隔。一些有趣的选项显示在下表中:
表4.4:Node.js配置选项
选项 | 描述 |
maxPoolSize | 指定驱动程序在其连接池中可以创建的最大客户端或连接数。此计数包括正在使用的连接。 |
minPoolSize | 指定即使没有操作发生,驱动程序应创建并维护的连接数。此计数包括正在使用的连接。 |
authMechanism | 指定用于连接到服务器的认证机制方法。如果您不指定值,驱动程序使用默认机制,根据服务器版本是SCRAM-SHA-1或SCRAM-SHA-256。有关更多信息,请参见认证机制文档。 |
authSource | 指定连接应针对的数据库进行认证。 |
directConnection | 指定是否强制将所有操作调度到连接URI中指定的主机。 |
journal | 指定客户端的默认写入关注j字段。 |
ssl | ssl是tls选项的别名。 |
tls | 指定是否需要TLS才能连接到服务器。使用srvServiceName值为mongodb+srv,或指定其他以tls为前缀的选项,将默认tls为true。 |
w | 指定客户端的默认写入关注w字段。 |
wTimeoutMS | 指定客户端的默认写入关注wtimeout字段。 |
连接压缩
像所有驱动程序一样,Node.js驱动程序提供了压缩消息的选项,这减少了MongoDB和应用程序之间通过网络传输的数据量。
Node.js驱动程序支持三种压缩算法:
- Snappy:这种算法旨在非常高速和合理的压缩。
- zlib:zlib是一个无损数据压缩库。
- Zstandard:Zstandard,或zstd,是一个快速无损压缩算法,针对实时压缩场景在zlib级别和更好的压缩比。
如果您指定了多个压缩算法,驱动程序将选择列表中MongoDB实例支持的第一个。
要使用连接字符串启用压缩,请在连接字符串中添加compressors参数。如果您想指定一个或多个压缩算法,请用逗号分隔它们:
const uri = "mongodb+srv://:@/?compressors=snappy,zlib";
const client = new MongoClient(uri);
使用TypeScript连接
TypeScript是JavaScript的类型超集,为大型应用程序提供了更好的工具和静态类型。将TypeScript与Node.js结合使用可以提供强大的后端解决方案,确保类型安全和提高开发者生产力。鉴于MongoDB和TypeScript都在现代应用程序开发中广泛使用,理解它们之间的连接机制至关重要。
要在TypeScript项目中使用MongoDB,请使用相同的Node.js驱动程序。然而,TypeScript可以从MongoDB提供的类型定义中受益,这些类型定义提供了自动完成、类型检查和其他好处。
在TypeScript文件中,您现在可以设置并连接到MongoDB:
import { MongoClient, Db, Collection } from "mongodb";
const uri = "mongodb://user:pass@host:27017/?w=majority";
const client: MongoClient = new MongoClient(uri);
async function run(): Promise {
try {
const database: Db = client.db('productions');
const movies: Collection = database.collection('movies');
// 带类型的示例查询
interface Movie {
title: string;
[key: string]: any;
}
const query: Partial = { title: '200 meters' };
const movie: Movie | null = await movies.findOne(query);
console.log(movie);
} finally {
await client.close();
}
}
run().catch(console.dir);
在上述代码中,您使用TypeScript接口来定义数据的形状,提供了对数据结构的清晰理解,并确保了查询数据库时的类型安全。
使用TypeScript连接到副本集与Node.js版本类似,但添加了类型注释:
const uri = "mongodb://user:pass@node1:port1,node2:port2,node3:port3/?replicaSet=mySet";
const client: MongoClient = new MongoClient(uri);
连接字符串的结构与Node.js示例中的结构相同。然而,使用TypeScript时,当您定义配置对象或处理来自MongoDB的结果时,您会从接口和类型中受益,以确保类型安全和清晰。
在TypeScript中启用压缩与Node.js示例类似。然而,如果您以编程方式定义压缩器,您将从枚举中受益:
enum Compressors {
SNAPPY = 'snappy',
ZLIB = 'zlib',
ZSTANDARD = 'zstd'
}
const uri = 'mongodb+srv://:@/?compressors=${Compressors.SNAPPY},${Compressors.ZLIB}';
const client: MongoClient = new MongoClient(uri);
总结
本章是关于使用PHP、Ruby、Node.js和Python连接到MongoDB的精心指南。它深入探讨了每种语言的连接过程,确保您具备实践知识,包括代码片段和与性能和安全相关的重要配置。
本章还强调了在连接过程中使用ODM的战略优势。除了ODM的好处,它还探讨了其效率、减少的开发时间,以及它在模型和MongoDB数据库之间提供的无缝桥接。
在下一章中,您将看到CRUD操作和基本查询的实际应用。