1. 开始 1.1 使用gem 通过kernel方法使用mongo gem require 'rubygems' #ruby1.9以上版本不需要 require 'mongo' include Mongo模块使得Mongo类一直可见而不用指定Mongo命名空间。 1.2 创建一个连接 一个MongoClient呈现一个MongoDB的连接 mongo_client = MongoClient.new("localhost", 27017) 这个驱动在每次写操作后都会发送一个getlasterror命令来确保写成功。1.8版本以前是没有指定 ':safe => true'来实现写保护的。 可以选定mongodb的地址和端口号来连接实例: mongo_client = MongoClient.new # (optional host/port args) mongo_client = MongoClient.new("localhost") mongo_client = MongoClient.new("localhost", 27017) 1.3 列出所有的数据库 mongo_client.database_names # lists all database names mongo_client.database_info.each { |info| puts info.inspect } database_info返回一个数据库名和数据大小的哈希映射。 2. 使用数据库 可以使用Mongo::MongoClient实例来获取Mongo::DB实例(返回数据库名称)。数据库可以不存在,如果不存在,Mongodb会创建它。 db = mongo_client.db("mydb") db = MongoClient.new("localhost", 27017).db("mydb") 此时,db对象将会连接mongodb服务器指定数据库,每个数据库实例使用服务器一个不同的套接字。 2.1 认证 mongodb可以通过使用用户名和密码工作在一个安全模式。 当工作在这个模式下,客户端需要提供一个用户名和密码完成连接,否则将会报错。 2.2 使用一个集合 可以连接一个集合通过collection方法: coll = db.collection("testCollection") 这和[]方法一样: coll = db["testCollection"] 一旦获取集合对象,就可以在上面做create, read, update, and delete (CRUD) 等操作。 2.3 利用insert创建一个集合 一旦获取collection对象,就可以向集合创建或插入文档,文档格式是JSON格式的。 { "name" : "MongoDB", "type" : "database", "count" : 1, "info" : { x : 203, y : 102 } } 上面的文档有内嵌数据,要实现这个,需要使用哈希或者有序哈希来完成。 doc = {"name" => "MongoDB", "type" => "database", "count" => 1, "info" => {"x" => 203, "y" => '102'}} id = coll.insert(doc) 返回结果: => BSON::ObjectId('5358775858e53d20b0000001') 2.4 获取集合列表 每个数据有一个或多个集合。可以获取他们呢的列表。 db.collection_names 返回结果: => ["system.indexes", "testData3", "test"] 2.5 插入多个文档 为了示范更多有趣的查询,需要向集合添加多个文档,文档格式如下: { "i" : value } 100.times { |i| coll.insert("i" => i) } 注意可以向同一集合插入格式不同的文档,这就是mongodb的模式自由概念。 3. 利用find和find_one读取文档 3.1 用find_one读取集合中的一条文档 获取集合中的一条文档记录,适应findOne方法,这个方法返回一个文档。 coll.find_one 返回结果: => {"_id"=>BSON::ObjectId('5358775858e53d20b0000001'), "name"=>"MongoDB", "type"=>"database", "count"=>1, "info"=>{"x"=>203, "y"=>"102"}} _id元素是mongodb自动添加的。 3.2 利用find方法从一个游标读取所有文档 为了获取集合所有文档,可以使用find方法返回游标对象,可以允许迭代匹配到的结果文档。 ruby驱动的游标是可列举的,可以使用Enumerable#each,Enumerable#map等方法。例如: coll.find.each { |row| puts row.inspect } 这样可以返回集合中的101条文档,也可以使用Enumerable#to_a。 puts coll.find.to_a 也可以使用 #each_slice来获取文档块以便成批处理。 # retrieve and process 10 documents at a time from cursor coll.find.each_slice(10) do |slice| puts slice.inspect end 提示:to_s方法可以把所有结果写入内存中,如果处理每个文档是无效的。为了更加有效利用内存,使用each方法处理代码块来处理游标。 3.3 指定查询 可以使用find一个哈希集合来查找满足条件的文档。 coll.find("_id" => id).to_a 选定条件: coll.find("i" => 71).to_a 返回结果: => [{"_id"=>BSON::ObjectId('5358786a58e53d20b0000049'), "i"=>71}] 3.4 排序集合中的文档 排序文档使用sort方法,这个方法可以利用一个key或者[key, direction]对。 方向默认是升序的,由Mongo::ASCENDING,:ascending,或:asc指定,然而也可以使用降序,由Mongo::DESCENDING,:descending,或:desc来指定。 # Sort in ascending order by :i coll.find.sort(:i) # Sort in descending order by :i coll.find.sort(:i => :desc) 二者都返回游标对象。 3.5 集合文档数目统计 可以使用count方法 coll.count => 101 3.6 得到一个查询文档的集合 如果查询"i" > 50的文档: puts coll.find("i" => {"$gt" => 50}).to_a 如果查询20 < "i" <= 30并且的文档: puts coll.find("i" => {"$gt" => 20, "$lte" => 30}).to_a 返回结果: {"_id"=>BSON::ObjectId('5358786958e53d20b0000017'), "i"=>21} {"_id"=>BSON::ObjectId('5358786958e53d20b0000018'), "i"=>22} {"_id"=>BSON::ObjectId('5358786958e53d20b0000019'), "i"=>23} {"_id"=>BSON::ObjectId('5358786958e53d20b000001a'), "i"=>24} {"_id"=>BSON::ObjectId('5358786958e53d20b000001b'), "i"=>25} {"_id"=>BSON::ObjectId('5358786958e53d20b000001c'), "i"=>26} {"_id"=>BSON::ObjectId('5358786958e53d20b000001d'), "i"=>27} {"_id"=>BSON::ObjectId('5358786958e53d20b000001e'), "i"=>28} {"_id"=>BSON::ObjectId('5358786958e53d20b000001f'), "i"=>29} {"_id"=>BSON::ObjectId('5358786958e53d20b0000020'), "i"=>30} => nil 3.7 返回查询的映射域 使用:fields选项指定返回域。 puts coll.find({"_id" => id}, :fields => ["name", "type"]).to_a puts coll.find({"_id" => "5358786958e53d20b0000017"}, :fields => ["i"]).to_a 3.8 使用正则表达式查询 puts coll.find({"name" => /^M/}).to_a 也可以动态的构建一个正在表达式: params = {'search' => 'DB'} search_string = params['search'] # Constructor syntax puts coll.find({"name" => Regexp.new(search_string)}).to_a # Literal syntax puts coll.find({"name" => /#{search_string}/}).to_a 尽管mongodb不会受到SQL注入攻击,但是也需要检查恶意的字符串。 4. 更新文档 可以使用很多update方法更新文档。 doc["name"] = "MongoDB Ruby" coll.update({"_id" => id}, doc) 或者使用原子操作来改变一个单个值: coll.update({"_id" => id}, {"$set" => {"name" => "MongoDB Ruby"}}) 验证更新: puts coll.find("_id" => id).to_a 5. 删除文档 使用remove来删除文档。 coll.count coll.remove("i" => 71) coll.count puts coll.find("i" => 71).to_a 上面的例子展示了总数减少,相关文档查询不到。 如果没有参数,delete方法会删除所有文档: coll.remove coll.count 在程序中需要谨慎使用 6. 索引 6.1 创建索引 mongodb支持索引,为了创建一个索引,你需要指定索引名称和一组或一个域被索引: # create_index assumes ascending order; see method docs # for details coll.create_index("i") 如果要指定复合索引或者缩减索引需要使用稍微复杂点的语法。索引指定必须是[filed name, direction]对。 方向应该指定为Mongo::ASCENDING 或 Mongo::DESCENDING。 # Explicit "ascending" coll.create_index([["i", Mongo::ASCENDING]]) # ruby 1.8 coll.create_index(:i => Mongo::ASCENDING) # ruby 1.9 and greater 使用游标上的explain方法来展示mongodb如何通过索引查找数据。 coll.find("_id" => id).explain coll.find("i" => 71).explain coll.find("type" => "database").explain 上面的通过_id和i的查询会使用比较快的BtreeCursor,type查询会使用比较慢的BasicCursor。 6.2 获取集合的索引列表 coll.index_information 6.3 创建和查询地理信息索引 首先在一个拥有long-lat值的域上创建一个索引: # ruby 1.8 people.create_index([["loc", Mongo::GEO2D]]) # ruby 1.9 and greater people.create_index(:loc => Mongo::GEO2D) 获取最接近坐标50,50的20个位置: people.find({"loc" => {"$near" => [50, 50]}}, {:limit => 20}).each do |p| puts p.inspect end 7. Dropping 7.1 删除索引 删除一个次级索引使用drop_index方法: coll.drop_index("i_1") coll.index_information 已经删除的索引不会列出来。 7.2 删除所有索引 coll.drop_indexes coll.index_information 只有主索引"_id"会保留。 7.2 删除集合 coll.drop db.collection_names 也可以使用drop_collection方法代替: db.drop_collection("testCollection") 7.3 删除数据库 在mongo客户端使用drop_databases来删除数据库: mongo_client.drop_database("mydb") mongo_client.database_names 8. 数据库管理 一个数据库可以有下面三个级别中一个profiling级别: 关闭(:off),慢查询(:slow_only),所有查询(:all)。查看级别: puts db.profiling_level # => off (the symbol :off printed as a string) db.profiling_level = :slow_only 验证数据库会在一切正常或者因为问题而抛出异常产生一个有趣的哈希。 p db.validate_collection('coll_name')