💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# MongoDB Ruby 教程 > 原文: [http://zetcode.com/db/mongodbruby/](http://zetcode.com/db/mongodbruby/) 在本教程中,我们展示了如何在 Ruby 中使用 MongoDB。 在 ZetCode 上有一个简洁的 [Ruby 教程](/lang/rubytutorial/)。 [Tweet](https://twitter.com/share) MongoDB 是 NoSQL 跨平台的面向文档的数据库。 它是可用的最受欢迎的数据库之一。 MongoDB 由 MongoDB Inc.开发,并作为免费和开源软件发布。 MongoDB 中的记录是一个文档,它是由字段和值对组成的数据结构。 MongoDB 文档与 JSON 对象相似。 字段的值可以包括其他文档,数组和文档数组。 MongoDB 将文档存储在集合中。 集合类似于关系数据库中的表以及行中的文档。 ## 安装 MongoDB 以下命令可用于在基于 Debian 的 Linux 上安装 MongoDB。 ```ruby $ sudo apt-get install mongodb ``` 该命令将安装 MongoDB 随附的必要包。 ```ruby $ sudo service mongodb status mongodb start/running, process 975 ``` 使用`sudo service mongodb status`命令,我们检查`mongodb`服务器的状态。 ```ruby $ sudo service mongodb start mongodb start/running, process 6448 ``` `mongodb`服务器由`sudo service mongodb start`命令启动。 ```ruby $ sudo gem install mongo ``` MongoDB Ruby 驱动程序通过`sudo gem install mongo`命令安装。 ## 建立数据库 `mongo`工具是 MongoDB 的交互式 JavaScript Shell 界面,它为系统管理员提供了一个界面,并为开发者提供了一种直接测试数据库查询和操作的方法。 ```ruby $ mongo testdb MongoDB shell version: 2.4.9 connecting to: testdb > db testdb > db.cars.insert({name: "Audi", price: 52642}) > db.cars.insert({name: "Mercedes", price: 57127}) > db.cars.insert({name: "Skoda", price: 9000}) > db.cars.insert({name: "Volvo", price: 29000}) > db.cars.insert({name: "Bentley", price: 350000}) > db.cars.insert({name: "Citroen", price: 21000}) > db.cars.insert({name: "Hummer", price: 41400}) > db.cars.insert({name: "Volkswagen", price: 21600}) ``` 我们创建一个`testdb`数据库,并在`cars`集合中插入八个文档。 ## 列出数据库集合 在数据库中`Mongo::Client`的`collections`方法列出可用的集合。 `list_collections.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') client.collections.each { |coll| puts coll.name } `client.close` ``` 该示例连接到`testdb`数据库并检索其所有集合。 ```ruby require 'mongo' ``` 我们包含`mongo`驱动程序。 ```ruby Mongo::Logger.logger.level = ::Logger::FATAL ``` 默认日志记录级别为`::Logger::DEBUG`,其中包含许多调试信息。 为了使输出更具可读性,我们选择`::Logger::FATAL`调试级别。 ```ruby client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') ``` `Mongo::Client`用于连接到 MongoDB 服务器。 我们指定 URL 和数据库名称。 27017 是 MongoDB 服务器监听的默认端口。 ```ruby client.collections.each { |coll| puts coll.name } ``` 我们遍历集合列表,并将其名称打印到控制台。 ```ruby `client.close` ``` 最后,我们关闭连接。 通常,不建议应用调用`close`。 连接很昂贵,正在重用。 但是,由于它是一个一次性程序,而不是长时间运行的可重用连接的应用,因此我们确实调用了该方法。 ```ruby $ ./list_collections.rb test cars ``` 这是`list_collections.rb`程序的示例输出。 ## 服务器选择超时 `:server_selection_timeout`是选择操作服务器的超时时间(以秒为单位)。 当我们无法连接到数据库服务器时,将引发`Mongo::Error::NoServerAvailable`。 `server_selection_timeout.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::DEBUG begin client = Mongo::Client.new([ '127.0.0.1:2717' ], :database => "testdb", :server_selection_timeout => 5) client[:cars].find.each { |doc| puts doc } client.close rescue Mongo::Error::NoServerAvailable => e p "Cannot connect to the server" p e end ``` 该示例的端口号错误。 默认情况下,服务器选择超时为三十秒。 我们将其设置为五秒钟。 ```ruby rescue Mongo::Error::NoServerAvailable => e ``` 未建立连接且超时已过期时,抛出`Mongo::Error::NoServerAvailable`。 ```ruby $ ./server_selection_timeout.rb D, [2016-05-02T15:32:20.231750 #8070] DEBUG -- : MONGODB | Adding 127.0.0.1:2717 to the cluster. D, [2016-05-02T15:32:20.232486 #8070] DEBUG -- : MONGODB | Connection refused - connect(2) D, [2016-05-02T15:32:20.732627 #8070] DEBUG -- : MONGODB | Connection refused - connect(2) D, [2016-05-02T15:32:21.232724 #8070] DEBUG -- : MONGODB | Connection refused - connect(2) ... ``` 调试日志记录级别在尝试连接到服务器时会提供这些消息。 ## 数据库统计 `dbstats`命令获取数据库的统计信息。 `dbstats.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ]) db = client.use("testdb") db.command({"dbstats" => 1}).documents[0].each do |key, value| puts "#{key}: #{value}" end `client.close` ``` 该示例连接到`testdb`数据库并显示其统计信息。 数据库对象的`command`方法用于执行命令。 ```ruby db = client.use("testdb") ``` `use`方法选择`testdb`数据库。 ```ruby db.command({"dbstats" => 1}).documents[0].each do |key, value| puts "#{key}: #{value}" end ``` `command`方法执行`dbstats`命令并解析返回的哈希值。 ```ruby $ ./dbstats.rb db: testdb collections: 4 objects: 21 avgObjSize: 43.23809523809524 dataSize: 908 storageSize: 16384 numExtents: 4 indexes: 2 indexSize: 16352 fileSize: 201326592 nsSizeMB: 16 dataFileVersion: {"major"=>4, "minor"=>5} ok: 1.0 ``` 这是`dbstats.rb`程序的输出。 ## 读取数据 `find`方法在集合中查找文档。 `read_all.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') client[:cars].find.each { |doc| puts doc } `client.close` ``` 在示例中,我们遍历`cars`集合的所有数据。 ```ruby client[:cars].find.each { |doc| puts doc } ``` 传递空查询将返回所有文档。 我们使用`each`方法遍历`:cars`集合的文档。 ```ruby $ ./read_all.rb {"_id"=>1, "name"=>"Audi", "price"=>52642} {"_id"=>2, "name"=>"Mercedes", "price"=>57127} {"_id"=>3, "name"=>"Skoda", "price"=>9000} {"_id"=>4, "name"=>"Volvo", "price"=>29000} {"_id"=>5, "name"=>"Bentley", "price"=>350000} {"_id"=>6, "name"=>"Citroen", "price"=>21000} {"_id"=>7, "name"=>"Hummer", "price"=>41400} {"_id"=>8, "name"=>"Volkswagen", "price"=>21600} ``` 这是`read_all.rb`示例的输出。 ## 计数文档 `count`方法返回集合中匹配文档的数量。 `count_documents.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') docs = client[:cars].find puts "There are #{docs.count} documents" `client.close` ``` 该示例计算`:cars`集合中的文档数。 ```ruby docs = client[:cars].find ``` 我们从`cars`集合中检索所有文档。 ```ruby puts "There are #{docs.count} documents" ``` 我们打印退回文档的数量。 ```ruby $ ./count_documents.rb There are 8 documents ``` `cars`集合中有八个文档。 ## 读取文档 `find`方法采用可选的`filter`参数,该参数用于过滤传入的数据。 `read_one.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') client[:cars].find(:name => 'Volkswagen').each do |doc| puts doc end `client.close` ``` 该示例从`:cars`集合中读取一个文档。 ```ruby client[:cars].find(:name => 'Volkswagen').each do |doc| ``` `find`方法仅显示包含大众汽车的文档。 ```ruby $ ./read_one.rb {"_id"=>8, "name"=>"Volkswagen", "price"=>21600} ``` 这是示例的输出。 ## 查询运算符 可以使用 MongoDB 查询运算符(例如`$gt`,`$lt`或`$ne`)过滤数据。 `read_op.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') puts client[:cars].find("price" => {'$lt' => 30000}).to_a puts "**************************" client[:cars].find("price" => {'$gt' => 30000}).each do |doc| puts doc end `client.close` ``` 该示例打印所有汽车价格低于 30,000 的文档,然后打印所有汽车价格高于 30,000 的文档。 ```ruby puts client[:cars].find("price" => {'$lt' => 30000}).to_a ``` `$lt`运算符用于获取价格低于 30,000 的汽车。 ```ruby $ ./read_op.rb {"_id"=>3, "name"=>"Skoda", "price"=>9000} {"_id"=>4, "name"=>"Volvo", "price"=>29000} {"_id"=>6, "name"=>"Citroen", "price"=>21000} {"_id"=>8, "name"=>"Volkswagen", "price"=>21600} ************************** {"_id"=>1, "name"=>"Audi", "price"=>52642} {"_id"=>2, "name"=>"Mercedes", "price"=>57127} {"_id"=>5, "name"=>"Bentley", "price"=>350000} {"_id"=>7, "name"=>"Hummer", "price"=>41400} ``` 这是示例的输出。 `$and`和`$or`逻辑运算符可用于组合多个表达式。 `read_and_or.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') puts client[:cars].find('$or' => [{:name => "Audi"}, {:name => "Skoda" }]).to_a puts "*************************************" puts client[:cars].find('$and' => [{:price => {'$gt' => 20000}}, {:price => {'$lt' => 50000 }}]).to_a client.close ``` 该示例同时显示了`$or`和`$and`运算符。 ```ruby puts client[:cars].find('$or' => [{:name => "Audi"}, {:name => "Skoda" }]).to_a ``` `$or`运算符用于返回名称为 Audi 或 Skoda 的文档。 ```ruby puts client[:cars].find('$and' => [{:price => {'$gt' => 20000}}, {:price => {'$lt' => 50000 }}]).to_a ``` `$and`运算符检索价格介于 20,000 和 50,000 之间的汽车。 ```ruby $ ./read_and_or.rb {"_id"=>1, "name"=>"Audi", "price"=>52642} {"_id"=>3, "name"=>"Skoda", "price"=>9000} ************************************* {"_id"=>4, "name"=>"Volvo", "price"=>29000} {"_id"=>6, "name"=>"Citroen", "price"=>21000} {"_id"=>7, "name"=>"Hummer", "price"=>41400} {"_id"=>8, "name"=>"Volkswagen", "price"=>21600} ``` 这是示例的输出。 ## 投影 投影确定要在结果集中的每个文档中包括或排除的字段。 `projection.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') cursor = client[:cars].find({}, { :projection => {:_id => 0} }) cursor.each { |doc| puts doc } `client.close` ``` 该示例从输出中排除`_id`字段。 ```ruby cursor = client[:cars].find({}, { :projection => {:_id => 0} }) ``` 我们在`find`方法的第二个参数中指定`:projection`选项。 ```ruby $ ./projection.rb {"name"=>"Audi", "price"=>52642} {"name"=>"Mercedes", "price"=>57127} {"name"=>"Skoda", "price"=>9000} {"name"=>"Volvo", "price"=>29000} {"name"=>"Bentley", "price"=>350000} {"name"=>"Citroen", "price"=>21000} {"name"=>"Hummer", "price"=>41400} {"name"=>"Volkswagen", "price"=>21600} ``` 这是示例的输出。 尚未包含`_id`。 ## 限制数据输出 `limit`方法指定要返回的文档数,`skip`方法指定要跳过的文档数。 `skip_limit.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') docs = client[:cars].find().skip(2).limit(5) docs.each do |doc| puts doc end `client.close` ``` 该示例从`testdb.cars`集合中读取,跳过前两个文档,并将输出限制为五个文档。 ```ruby docs = client[:cars].find().skip(2).limit(5) ``` `skip`方法跳过前两个文档,`limit`方法将输出限制为五个文档。 ```ruby $ ./skip_limit.rb {"_id"=>3, "name"=>"Skoda", "price"=>9000} {"_id"=>4, "name"=>"Volvo", "price"=>29000} {"_id"=>5, "name"=>"Bentley", "price"=>350000} {"_id"=>6, "name"=>"Citroen", "price"=>21000} {"_id"=>7, "name"=>"Hummer", "price"=>41400} ``` 这是示例的输出。 ## 聚合 聚合计算集合中数据的聚合值。 `sum_all_cars.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL agr = [{"$group" => {:_id => 1, :all => { "$sum" => "$price" } }}]; client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') client[:cars].aggregate(agr).each { |doc| puts doc } ``` 该示例计算集合中所有汽车的价格。 ```ruby agr = [{"$group" => {:_id => 1, :all => { "$sum" => "$price" } }}]; ``` `$sum`运算符计算并返回数值的总和。 `$group`运算符通过指定的标识符表达式对输入文档进行分组,并将累加器表达式(如果指定)应用于每个组。 ```ruby client[:cars].aggregate(agr).each { |doc| puts doc } ``` `aggregate`方法将聚合操作应用于`cars`集合。 ```ruby $ ./sum_all_cars.rb {"_id"=>1, "all"=>609727} ``` 所有价格的总和是 619,369。 我们可以使用`$match`运算符来选择要汇总的特定汽车。 `sum_two_cars.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL agr = [{"$match" => {"$or" => [ { :name => "Audi" }, { :name => "Volvo" }]}}, {"$group" => {:_id => 1, :sumOfTwo => { "$sum" => "$price" } }}]; client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') client[:cars].aggregate(agr).each { |doc| puts doc } `client.close` ``` 该示例计算奥迪和沃尔沃汽车的价格总和。 ```ruby agr = [{"$match" => {"$or" => [ { :name => "Audi" }, { :name => "Volvo" }]}}, {"$group" => {:_id => 1, :sumOfTwo => { "$sum" => "$price" } }}]; ``` 该表达式使用`$match`,`$or`,`$group`和`$sum`运算符执行任务。 ```ruby $ ./sum_two_cars.rb {"_id"=>1, "sumOfTwo"=>81000} ``` 两辆车的价格之和为 81,642。 ## 插入文档 `insert_one`方法将单个文档插入到集合中。 `insert_doc.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') doc = { :_id => 9, :name => "Toyota", :price => 37600 } client[:cars].insert_one doc `client.close` ``` 该示例将一辆汽车插入`cars`集合。 ```ruby doc = { :_id => 9, :name => "Toyota", :price => 37600 } ``` 这是要插入的文档。 ```ruby client[:cars].insert_one doc ``` `insert_one`方法将文档插入到集合中。 ```ruby > db.cars.find({_id:9}) { "_id" : 9, "name" : "Toyota", "price" : 37600 } ``` 我们用`mongo`工具确认插入。 ## 插入许多文档 `insert_many`方法将多个文档插入一个集合中。 `create_collection.rb` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') result = client[:continents].insert_many([ { :_id => BSON::ObjectId.new, :name => 'Africa' }, { :_id => BSON::ObjectId.new, :name => 'America' }, { :_id => BSON::ObjectId.new, :name => 'Antarctica' }, { :_id => BSON::ObjectId.new, :name => 'Australia' }, { :_id => BSON::ObjectId.new, :name => 'Asia' }, { :_id => BSON::ObjectId.new, :name => 'Europe' } ]) puts "#{result.inserted_count} documents were inserted" `client.close` ``` 该示例创建一个大洲集合并将六个文档插入其中。 ```ruby result = client[:continents].insert_many([ { :_id => BSON::ObjectId.new, :name => 'Africa' }, { :_id => BSON::ObjectId.new, :name => 'America' }, { :_id => BSON::ObjectId.new, :name => 'Antarctica' }, { :_id => BSON::ObjectId.new, :name => 'Australia' }, { :_id => BSON::ObjectId.new, :name => 'Asia' }, { :_id => BSON::ObjectId.new, :name => 'Europe' } ]) ``` 使用`insert_many`方法将六个记录的数组插入到新集合中。 `BSON::ObjectId.new()`创建一个新的`ObjectID`,这是用于标识文档的唯一值,而不是整数。 ```ruby puts "#{result.inserted_count} documents were inserted" ``` 返回结果的`inserted_count`给出成功插入的文档数。 ```ruby > db.continents.find() { "_id" : ObjectId("57263c0f81365b266b17358c"), "name" : "Africa" } { "_id" : ObjectId("57263c0f81365b266b17358d"), "name" : "America" } { "_id" : ObjectId("57263c0f81365b266b17358e"), "name" : "Antarctica" } { "_id" : ObjectId("57263c0f81365b266b17358f"), "name" : "Australia" } { "_id" : ObjectId("57263c0f81365b266b173590"), "name" : "Asia" } { "_id" : ObjectId("57263c0f81365b266b173591"), "name" : "Europe" } ``` `continents`集合已成功创建。 ## 修改文档 `delete_one`方法用于删除文档,`update_one`用于更新文档。 `mofify.js` ```ruby #!/usr/bin/ruby require 'mongo' Mongo::Logger.logger.level = ::Logger::FATAL client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb') client[:cars].delete_one({:name => "Skoda"}) client[:cars].update_one({:name => "Audi"}, '$set' => {:price => 52000}) `client.close` ``` 该示例删除包含 Skoda 的文档并更新 Audi 的价格。 ```ruby client[:cars].delete_one({:name => "Skoda"}) ``` `delete_one`删除`Skoda`的文档。 ```ruby client[:cars].update_one({:name => "Audi"}, '$set' => {:price => 52000}) ``` 通过`update_one`方法将 Audi 的价格更改为 52,000。 `$set`运算符用于更改价格。 ```ruby > db.cars.find() { "_id" : 1, "name" : "Audi", "price" : 52000 } { "_id" : 2, "name" : "Mercedes", "price" : 57127 } { "_id" : 4, "name" : "Volvo", "price" : 29000 } { "_id" : 5, "name" : "Bentley", "price" : 350000 } { "_id" : 6, "name" : "Citroen", "price" : 21000 } { "_id" : 7, "name" : "Hummer", "price" : 41400 } { "_id" : 8, "name" : "Volkswagen", "price" : 21600 } { "_id" : 9, "name" : "Toyota", "price" : 37600 } ``` 我们使用`mongo`工具确认更改。 在本教程中,我们使用了 MongoDB 和 Ruby。