跳转至

MongoDB Ruby 教程

原文: http://zetcode.com/db/mongodbruby/

在本教程中,我们展示了如何在 Ruby 中使用 MongoDB。 在 ZetCode 上有一个简洁的 Ruby 教程

Tweet

MongoDB 是 NoSQL 跨平台的面向文档的数据库。 它是可用的最受欢迎的数据库之一。 MongoDB 由 MongoDB Inc.开发,并作为免费和开源软件发布。

MongoDB 中的记录是一个文档,它是由字段和值对组成的数据结构。 MongoDB 文档与 JSON 对象相似。 字段的值可以包括其他文档,数组和文档数组。 MongoDB 将文档存储在集合中。 集合类似于关系数据库中的表以及行中的文档。

安装 MongoDB

以下命令可用于在基于 Debian 的 Linux 上安装 MongoDB。

$ sudo apt-get install mongodb

该命令将安装 MongoDB 随附的必要包。

$ sudo service mongodb status
mongodb start/running, process 975

使用sudo service mongodb status命令,我们检查mongodb服务器的状态。

$ sudo service mongodb start
mongodb start/running, process 6448

mongodb服务器由sudo service mongodb start命令启动。

$ sudo gem install mongo

MongoDB Ruby 驱动程序通过sudo gem install mongo命令安装。

建立数据库

mongo工具是 MongoDB 的交互式 JavaScript Shell 界面,它为系统管理员提供了一个界面,并为开发者提供了一种直接测试数据库查询和操作的方法。

$ 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::Clientcollections方法列出可用的集合。

list_collections.rb

#!/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数据库并检索其所有集合。

require 'mongo'

我们包含mongo驱动程序。

Mongo::Logger.logger.level = ::Logger::FATAL

默认日志记录级别为::Logger::DEBUG,其中包含许多调试信息。 为了使输出更具可读性,我们选择::Logger::FATAL调试级别。

client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'testdb')

Mongo::Client用于连接到 MongoDB 服务器。 我们指定 URL 和数据库名称。 27017 是 MongoDB 服务器监听的默认端口。

client.collections.each { |coll| puts coll.name }

我们遍历集合列表,并将其名称打印到控制台。

`client.close`

最后,我们关闭连接。 通常,不建议应用调用close。 连接很昂贵,正在重用。 但是,由于它是一个一次性程序,而不是长时间运行的可重用连接的应用,因此我们确实调用了该方法。

$ ./list_collections.rb 
test
cars

这是list_collections.rb程序的示例输出。

服务器选择超时

:server_selection_timeout是选择操作服务器的超时时间(以秒为单位)。 当我们无法连接到数据库服务器时,将引发Mongo::Error::NoServerAvailable

server_selection_timeout.rb

#!/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

该示例的端口号错误。 默认情况下,服务器选择超时为三十秒。 我们将其设置为五秒钟。

rescue Mongo::Error::NoServerAvailable => e

未建立连接且超时已过期时,抛出Mongo::Error::NoServerAvailable

$ ./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

#!/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方法用于执行命令。

db = client.use("testdb")

use方法选择testdb数据库。

db.command({"dbstats" => 1}).documents[0].each do |key, value|

    puts "#{key}: #{value}"
end

command方法执行dbstats命令并解析返回的哈希值。

$ ./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

#!/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集合的所有数据。

client[:cars].find.each { |doc| puts doc }

传递空查询将返回所有文档。 我们使用each方法遍历:cars集合的文档。

$ ./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

#!/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集合中的文档数。

docs = client[:cars].find

我们从cars集合中检索所有文档。

puts "There are #{docs.count} documents"

我们打印退回文档的数量。

$ ./count_documents.rb 
There are 8 documents

cars集合中有八个文档。

读取文档

find方法采用可选的filter参数,该参数用于过滤传入的数据。

read_one.rb

#!/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集合中读取一个文档。

client[:cars].find(:name => 'Volkswagen').each do |doc|

find方法仅显示包含大众汽车的文档。

$ ./read_one.rb 
{"_id"=>8, "name"=>"Volkswagen", "price"=>21600}

这是示例的输出。

查询运算符

可以使用 MongoDB 查询运算符(例如$gt$lt$ne)过滤数据。

read_op.rb

#!/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 的文档。

puts client[:cars].find("price" => {'$lt' => 30000}).to_a

$lt运算符用于获取价格低于 30,000 的汽车。

$ ./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

#!/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运算符。

puts client[:cars].find('$or' => [{:name => "Audi"}, {:name => "Skoda" }]).to_a

$or运算符用于返回名称为 Audi 或 Skoda 的文档。

puts client[:cars].find('$and' => [{:price => {'$gt' => 20000}}, 
    {:price => {'$lt' => 50000 }}]).to_a

$and运算符检索价格介于 20,000 和 50,000 之间的汽车。

$ ./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

#!/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字段。

cursor = client[:cars].find({}, { :projection => {:_id => 0} })

我们在find方法的第二个参数中指定:projection选项。

$ ./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

#!/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集合中读取,跳过前两个文档,并将输出限制为五个文档。

docs = client[:cars].find().skip(2).limit(5)

skip方法跳过前两个文档,limit方法将输出限制为五个文档。

$ ./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

#!/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 }

该示例计算集合中所有汽车的价格。

agr = [{"$group" => {:_id => 1, :all => { "$sum" => "$price" } }}];

$sum运算符计算并返回数值的总和。 $group运算符通过指定的标识符表达式对输入文档进行分组,并将累加器表达式(如果指定)应用于每个组。

client[:cars].aggregate(agr).each { |doc| puts doc }

aggregate方法将聚合操作应用于cars集合。

$ ./sum_all_cars.rb 
{"_id"=>1, "all"=>609727}

所有价格的总和是 619,369。

我们可以使用$match运算符来选择要汇总的特定汽车。

sum_two_cars.rb

#!/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`

该示例计算奥迪和沃尔沃汽车的价格总和。

agr = [{"$match" => {"$or" => [ { :name => "Audi" }, { :name => "Volvo" }]}}, 
       {"$group" => {:_id => 1, :sumOfTwo => { "$sum" => "$price" } }}];

该表达式使用$match$or$group$sum运算符执行任务。

$ ./sum_two_cars.rb 
{"_id"=>1, "sumOfTwo"=>81000}

两辆车的价格之和为 81,642。

插入文档

insert_one方法将单个文档插入到集合中。

insert_doc.rb

#!/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集合。

doc = { :_id => 9, :name => "Toyota", :price => 37600 } 

这是要插入的文档。

client[:cars].insert_one doc 

insert_one方法将文档插入到集合中。

> db.cars.find({_id:9})
{ "_id" : 9, "name" : "Toyota", "price" : 37600 }

我们用mongo工具确认插入。

插入许多文档

insert_many方法将多个文档插入一个集合中。

create_collection.rb

#!/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`

该示例创建一个大洲集合并将六个文档插入其中。

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,这是用于标识文档的唯一值,而不是整数。

puts "#{result.inserted_count} documents were inserted"

返回结果的inserted_count给出成功插入的文档数。

> 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

#!/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 的价格。

client[:cars].delete_one({:name => "Skoda"})

delete_one删除Skoda的文档。

client[:cars].update_one({:name => "Audi"}, '$set' => {:price => 52000})

通过update_one方法将 Audi 的价格更改为 52,000。 $set运算符用于更改价格。

> 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。


我们一直在努力

apachecn/AiLearning

【布客】中文翻译组