MongDB数据库的使用离不开CRUD操作。什么是CRUD,就是创建文档,读取文档信息,更新文档和删除文档。
key-value键值对标记
在MongoDB的Ruby驱动中,Key_value键值多次出现。而且有时会出现语法上的巧合,这取决于在使用的Ruby版本中如何申明。
在文档创建步骤中,1.9及之后版本支持以下语法:
document={name:"Tom",age:20}。
但是如果你使用的是2.2或者更高的版本,你可以用双引号将你的key包起来。如:
document={"name":"Tom","age":36}
如果你需要使用以"$"开始的MongoDB操作符,例如$set,$gte或者$near,你就必须使用双引号将其闭合包裹。如果你使用2.2或者更好的Ruby版本,可使用如下写法:
collection.update_one({name:"Tom"},{"$set":{age:42}})
如果你使用了更早的版本,使用HashRocket符号写法
collection.update_one({name:"Tom"},{"$set"=>{age:42}})
使用strings和hashrockets来描述键值对在任意版本都适用
collection.update_one({"name"=>"Tom"},{"$set"=>{"age":42}})
2. 文档创建-类比关系型数据库的表格创建
这边首先讲述下,MongoDB中的文档创建与关系型数据库中表格创建的区别。在MongoDB中插入数据到集合的时候会自动创建文档,而关系型数据库表格的使用必须基于预先定义好表结构。MongoDB这种机制的好处在于可以不用预先知道文档的结构。具有更好的兼容性。
在MongoDB中,在指定了具体的集合名字后,我们使用insert_one()和insert_many()两个方法来向集合中插入文档信息。插入操作返回一个包含了插入信息的Mongo::Operation::Result对象。在2.6及之后的MongoDB版本中,由于使用了写命令,如果插入失败,会抛出异常。2.4版本的MongoDB中,只有在插入黑白且写的结果大于等于1时才会抛出异常。
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
result=client[:actors].insert_one({:name=>"TK"})
result.n #返回成功插入的文档数
result=client[:actors].insert_many([
{:name=>"April"},{:name=>'Tom'}
])
result.insert_count #此处返回2,插入两个文档
3. Decimal128类型数字
在3.4版本中,Decimal128是一个BSON数据类型,它是基于decimal类型使用128比特的浮点数值,可以模拟精确的小数舍入,主要用于处理货币型数据,诸如金融和税收的计算。
下面的例子在inventory集合中插入了一个包含Decimal128类型price域的文档。
client=Mongo::Client.new(['127.0.0.1:27017'],:databse=>'test')
price=BSON::Decimal128.new("428.59")
client[:inventory].insert_one({ "_id"=>1,
"item"=>"26 inch moitor"
"price"=>price
)
成功执行上述语句后,会生成下述文档
{"_id":1,"item":"26 inch monitor","price":NumberDecimal("428.59")}
你也可以通过Ruby的BigDecimal对象创建一个Decimal128的对象,或者通过Decimal128.from_string().
big_decimal=BigDecimal.new(428.79,5)
price=BSON::Decimal128.new(big_decimal)
或者
price=BSON::Decimal128.from_string("428.79")
4. 文档读取 - 类比数据库查询数据
Ruby驱动类型通过find方法为集合的查询提供了一个流畅的接口。find方法也有多个可用参数。查询方法对于服务器来说是一个懒执行的方式。也就是说只有在迭代到对应结果时,在这时查询才会被分配,并得到一个Mongo::Curor的返回。要想找出满足查询规则的所有文档集合,通过find方法加上对应的过滤条件。
client = Mongo::Client.new(['127.0.0.1:27017'],:database="film")
client[:actors].find(:name=>"Tom").each do |document|
end
查询参数,为了增加查询时的参数,将一系列合适的方法串在find方法之后。Mongo::Collection::View是一个每次方法调用后会新生成的而且不可变的对象。
下表是当使用查询方法时,可以使用的参数列表信息,还有相应方法的例子
参数 | 描述 |
allow_patrial_results | 共享集群模式下使用。如果集群中一个碎片宕机了,查询出的结果就是从当前存活的碎片中获取到的,这样就可能只获取到了结果的一部分。 |
batch_size(Integer) | 设置了每执行一次GETMORE操作,游标返回的每批次的文档个数 |
commont(String) | 查询的注释 |
hint(Hash) | 运行查询时使用index hint优化查询速度 |
limit(Integer) | 将返回的文档的数量限制为所提供的值 |
max_scan(Integer) | 如果要进行全集扫描,设定文档扫描的最大数值 |
no_cursor_timeout | MongoDB在十分钟间隔后自动关闭非活动的游标,通过这个参数可以在服务器上让游标永久存活 |
projection(Hash) | 设定结果中需要包含哪些信息,剔除哪些信息。例如client[:actors].find.projection(:name=>1) |
read(Hash) |
仅仅为当前查询设定读取首选项 client[:actors].find.read(:mode=>:secondary_preferred) |
show_disk_loc(Boolean) | 让结果信息包含文档的位置信息 |
skip(Integer) | 在查询结果中跳过指定数目的文档 |
snapshot | 使用快照模式进行查询 |
sort(Hash) |
确定结果的排序规则 client[:actors].find.sort(:name=>-1) |
附件的查询参数
4.1 count
获取文档操作返回的文档总数目
client=Mongo::Client.new(['127.0.0.1:27017'],:database='film')
client[:actors].find(:name=>"Tom").count
4.2 distinct
去除结果中的重复值。可以类比SQL中的distinct操作
client=Mongo::Client.new(['127.0.0.1:27017'],:database='film')
client[:actors].find.distinct(:name)
4.3 tailable cursor
对于获取到的结果集合,你可能需要在当前游标已遍历完所有结果后保持tailable cursor的打开状态。下面的例子展示的是tailable cursor的使用方法。
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
client[:actors].drop
client[:actors,capped:true,size:512].create
result=client[:actors].insert_many([{:name=>"Tom"},{:name=>"Alex"}])
enum=client[:actors].find({},:cursor_type=>:tailable_wait).to_enum
while true
doc=enum.text
end
4.4 读取首选项read preference
该参数设定了在副本集结构中,查询或相应的命令操作应该发送给哪个候选成员。它由一个标识特定符号的节点,名为tag_sets的hashes数组,两个时间选项(local_threshold,server_selection_timeout)组成。
local_threshold:最近的服务器和可以发送指令操作的可用服务器之间的时间延迟窗口的上限值(单位为秒)。默认值为0.015s或15ms。
server_selection_timeout:服务器选择时,抛出异常前的阻塞时间。默认是30s,也就是30000ms。
更对关于服务器选择算法,请参考后续博文。
读取首选项参数可以作为客户端连接的一个参数,也可以作为运行在数据库之上的命令的参数
#客户端连接时设定read preference参数,应用于所有的操作上
client = Mongo::Client.new(['127.0.0.1:27017'],read:{:mode=>:secondary,:tag_sets=>[{'dc'=>'nyc'}]})
#对于给定的命令设定读取首选项参数
client.database.command({:collstats=>'test'},:read=>{:mode=>:secondary,:tag_sets=>[{'dc'=>'nyc'}]})
4.4.1 mode参数
模式参数的取值包含五种,也就是:primary,:secondary,:primary_prefered,:secondary_prefered,:nearest。具体的模式含义,请参考后续博文。
4.4.2 tag_sets参数
tag_sets参数是一串排序的标签集合,用于控制服务器选举时限制服务器的选举资格。读取首选项的标签集(T)需要匹配服务器的标签集(S);如果T是S的子集,也可是相应的服务器标签集(S)匹配读取首选项的标签集(T).
例如,读取首选项标签集{dc:'ny',rack:2}匹配了拥有标签集{dc:'ny',rack:2,size:'large'}的备选服务器。空的文档标签集可以匹配任何服务器,这是由于空的标签集是任意标签集的子集。这也意味着标签集参数是[{}]时匹配所有的服务器。
5.文档更新-类似于关系型数据库的update操作
文档更新可以选择单个更新或多个一起更新方式,也可以选择使用findAndModify()命令
5.1 update_one
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
actors=client[:actors]
#find后再modify
result=actors.find(:name=>'Alex').update_one("$inc"=>{:plays=>1})
result.n
#直接update_one
reslut=actors.update_one({:name=>"Alex"},{"$inc"=>{:palys=>1}})
result.n
5.2 update_many
#find后再modify
result =actors.find([:label=>'Hospital']).update_many("$inc"=>{:plays=>1})
result.modified_count
#直接update_many
reslut=actors.update_many({:label=>'Hospital'},{"$inc"=>{:plays=>1}})
result.modified_count
5.3 replace_one
#find后再replace
result =actors.find(:name=>'Aphex Twin').replace_one(:name=>'Richard')
result.modified_count
#直接replace_one
result=actors.replace_one({:name=>'Aphex Twin'},{:name=>'Richard'})
result.modified_count
通过$findAndModify方法来进行文档更新和返回,可以使用find_one_and_delete,find_one_and_replace,find_one_and_update三个方法中的任意一个。你可以在更新操作发生前后均能等到对应的文档信息。
5.4 find_one_and_delete
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
actors=client[:actors]
actors.find(:name=>'Jose James').find_one_and_delete
5.5 find_one_and_replace
doc=actors.find(:name=>Jose James').find_one_and_replace(:name=>'Jose')
doc
doc=actors.find_one_and_replace({:name=>'Jose James'},{:name=>'Jose'})
doc
doc=actors.find(:name=>'Jose James').find_one_and_replace({:name=>'Jose'},:return_document=>:after)
doc
5.6 find_one_and_update
doc=actors.find(:name='Jose James').find_one_and_update('$set'=>{:name=>'Jose'})
doc
doc=actors.find_one_and_update({:name=>'Jose James'},{'$set'=>{:name=>'Jose'}})
doc
5.7 find_one_and_replace
doc=actors.find(:name=>'Jose James').find_one_and_replace({'$set'=>{:name=>'Jose'}},:return_document=>:after)
doc
doc=actors.find_one_and_replace({:name=>'Jose James'},{'$set'=>{:name=>'Jose'}},return_document=>:after)
doc
6 文档删除操作Deleting
6.1 delete_one 单个删除
client=Mongo::Client.new(['127.0.0.1:27017'],:database=>'film')
actors=client[:actors]
#find后再删除
result=actors.find(:name=>'Bob').delete_one
result.deleted_count
#直接delete
result=actors.delete_one({:name=>'Bob'})
result.deleted_count
6.2 delete_many 多个删除
result=actors.find(:label=>'Mute').delete_many
result.deleted_count
result=actors.delete_many({:label=>'Mute'})
result.deleted_count
至此,Ruby操作MongoDB的CRUD操作。该部分是数据库的基础部分。