mongod小结

文档和集合

文档

文档是Mongodb中的最基本数据单元,类似于关系数据库中的行。

在mongodb中,文档的键通常都是字符串。Mongodb对文档的键是区分大小写的,对键值是区分数据类型的

例如:

{username:”admin”}和{userName:”admin”}  {age:20}和{age:”20”}是不同的文档

特别注意:{username:”admin”,username:”非法键”},同一文档中 键值是不能重复的。


集合

集合是文档组成的,在关系型数据库中就是表。

在mongodb中,对集合中存储的文档是非常开放的,一个集合中可以存放各式各样的文档。

例如:

{username:”admin”} , {role:”admin”} (强烈反对)

{username:”admin”},{username:”pp”} (强烈推荐)


子集合

  组织子集合的一种惯例是使用“.”字符分开的按命名空间划分的子集合。在MongoDB中使用子集合来组织数据是很好的方法。

例如:

  用户与用户详细信息包含两个集合,分别是user.user和user.userinfo。这样做的目的只是为了使组织结构更好些,也就是说 user这个集合(这里根本就不需要存在)及其子集合没有任何关系。把数据库的名字放到集合名前面,得到就是集合的完全限定名,称为命名空间。


数据库

admin

  从权限的角度来看,这是“root”数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。

local

这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合

config

当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。

命名规则

1、不能是“”空字符串

2、不可以含有空格,在mongodb中 空格代表结束字符。

3、文档的键不可以有“.”和“$”符号,集合名中不可以包含“$”

4、集合不能以 “system.”开头,mongodb中system是系统保留前缀

5、集合名长度不得超过121字节,在实际使用当中应该小于100字节;数据库名最多不超过64个字节

(mongodb最终是以文件方式存储的,操作系统中的非法文件名,在mongodb中就是非法的,这样便于理解与记忆)

数据类型

    MongoDB的文件存储格式为BSON,同JSON一样支持往其它文档对象和数组中再插入文档对象和数组,同时扩展了JSON的数据类型.与数据库打交 道的那些应用。

String                    字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。

Integer                  整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。

Boolean                布尔值。用于存储布尔值(真/假)。

Double                  双精度浮点值。用于存储浮点值。

Array                     用于将数组或列表或多个值存储为一个键。

Timestamp            时间戳。记录文档修改或添加的具体时间。

Object                   用于嵌入式的文档,即一个值为一个文档

Null                       用于创建空值。

Date                      日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。

Object ID               对象 ID。用于创建文档的 ID。

Binary Data           二进制数据。用于存储二进制数据。

insert

db.集合名称.insert(document)

这个操作是向mydb.user集合中增加“_id”建,并添加到MongoDB中。检验是否含有“_id”键和文档不超过16M,除之,不做任何数据验证。


save

db.mydb.save({name:”test2”})

这个操作也是向mydb.user集合中增加“_id”建,并添加到MongoDB中。save函数实际就是根据参数条件,调用了insert或update函数.如果想插入的数据对象存在,insert函数会报错,而save函数是改变原来的对象;如果想插入的对象不存在,那么它们执行相同的插入操作.这里可以用几个字来概括它们两的区别,即所谓"有则改之,无则加之".


update

1. db.mydb.user.update({name:”test1”} , {name:”test1”,age:20})

2. 使用findOne()函数: user=db.mydb.user.findOne({name:”test1”})

user.name=“test1”

user.age++

db.mydb.user.update({_id:user._id},user)


修改器

$inc修改器

update({键:值},{$inc:{键:值}})

db.mydb.user.update({users:"dsm"},{$inc:{age:1}})

age自增1(age必须为数字类型)


$set修改器

update({键:值},{$set:{键:值}})

set为该文档设置一条属性,如果没有则创建一条属性

db.mydb.user.update({users:"dsm"},{$set:{hobby:"皮"}})

也可以修改内嵌文档

db.mydb.user.update({users:"dsm"},{$set:{"skills.name":["正方形打野","边缘OB","假设性原则"]}})

db.mydb.user.update({users:"dsm"},{$set:{"skills.发动结果":["队友崩盘","永不团灭","马半仙模式"]}})

修改内嵌文档不同于修改属性,不会覆盖。


$unset修改器

    update({键:值},{$unset:{键:-1/0/1}})

    -1/0/1都表示删除

删除该文档的一条属性

db.mydb.user.update({users:"dsm"},{$unset:{"skills.基地爆炸":-1}})


$push数组修改器

  update({…},{$push:{键:值}}) 

  $push修改器是会往键已有的数组中追加值,如果数组不存在,则创建新的数组并更新键值。

  db.mydb.user.update({users:"dsm"},{$push:{hobby:"养大象"}})


$push + $ne数组修改器

update({键:{$ne:值}},{$push:{键:值}})

$push+$ne 组合键使用于如果追加值不在数组中则追加进去。

db.mydb.user.update({users:"dsm",hobby:{$ne:"折磨王"}},{$push:{hobby:"折磨王"}})


addToSet数组修改器

update({…},{$addToSet:{键:值}})

相当于$push+$ne

db.mydb.user.update({users:"dsm"},{$addToSet:{hobby:"折磨王"}})

db.mydb.user.update({users:"dsm"},{$addToSet:{hobby:"拳皇"}})


$addToSet + $each数组修改器

update({…},{$addToSet:{键:{$each:[…]}}})

当我们一次要追加多个值得时候,而且需要判断数组中是否存在,这时$push+$ne 组合就不能实现了,需求用到$addToSet+$each组合键。

db.mydb.user.update({users:"dsm"},{$addToSet:{hobby:{$each:["马氏跑动杀","葵花三式","折磨王"]}}})

只加入了马氏跑动杀和葵花三式,折磨王没有加入


$pop数组修改器

{$pop:{键:1}}  - 从数组尾部删除一个元素

{$pop:{键:-1}} - 从数组头部删除一个元素

“$pop”修改器用于删除数组里面值,如果把数组看成一个队列或者栈的话,可以从数组任何一端删除元素。

db.mydb.user.update({users:"dsm"},{$pop:{hobby:1}})


$pull数组修改器

{$pull:{键:值}}

“$pull”修改器也是用于删除数组里面值,它可以删除数组中任意位置的值,并且删除所有匹配到的值

db.mydb.user.update({users:"dsm"},{$pull:{hobby:"折磨王"}})


$定位修改器

“$”定位修改器也是用于数组里面值的数据类型为内嵌文档,可以使用$实行定位修改。

db.mydb.user.update({users:"dsm"},{$set:{"skills.name":["萧峰","胡里亚","马化腾"]}})

db.mydb.user.update({"skills.test" :11},{$set:{"skills.name":["跑之小跳"]}})


upsert

update({匹配文档},{更新文档},true)

Upsert 可以理解为 update与insert的缩写 ,它是update函数的第三个参数,其实际含义就是更新或插入。

Update参数upsert默认值是fasle,它是一种特殊的更新。根据这个参数值,update函数判断对匹配不到的文档,将更新文档基于匹配文档之上以一个新的文档是否增加到集合中。

db.mydb.user.update({users:"pdd"},{users:"pddd"},true)


mutli

update({…},{…}, false, true)

它是update函数的第四个参数,其实际含义就是是否实现多更新操作。

update函数的mutli默认值是false, 代表只对第一个匹配到的文档进行更新操作;需要更新多个符合匹配条件的文档,则要设置mutli值为true.

例如:所有名称为test3的年龄加2

db.mydb.user.update({name:”test3”},{$inc:{age:2}, false, true})

db.runCommand({getLastError:1})可以查看受影响的文档数


返回更新文档

用法:db.集合名.findAndModify({

    query:{匹配文档},

    update:{更新文档}

    [,remove:布尔值,sort:{排序文档},new:布尔值]

    })

    query: 匹配文档,也就是查询条件

    sort:  排序匹配文档的条件

    update: 修改器文档,执行文档更新操作

    remove: true/false,是否对匹配到的文档进行删除

    new: true/false, 表示返回的是更新前还是更新后的文档,默认值是false

update 与remove 必须而且只能存在一个。

它一次只能操作一个文档,不能进行upsert操作,只能更新已存在的文档。

findAndModify 执行效率有点低,话虽这么说,不代表避免使用,mongo每一个函数的存在,都有其实际存在的价值。它的执行效率相当于 一次查询、更新外加getLastError 顺序执行的时间。

db.mydb.user.findAndModify({query:{users:"dsm"},update:{$pop:{hobby:1}}})


安全操作

    mongoDB 开发者采用不安全模式作为默认选择,这是由于他们与关系型数据库打交道的经验所致的,很多构建在关系型数据库的应用,都不关心返回的代码,也不会处理这个返回码,但又得苦苦等待这个返回码,这会造成性能极大的下降。mongoDB可以让用户来选择采用何种方式。有些操作可以使用不安全模式(速度快),有些操作使用安全模式。

    安全操作是在执行完操作后立即执行getLastError命令,来检查是否成功执行。然后适当的处理数据库返回的错误,一般情况下数据库会抛出一个可捕获的错误,我们可以采用自己的开发语言来捕获和处理。如果执行成功,getLastError会给出额外的信息作为响应(比如:更新或删除操作给出的更新数)。


请求和连接

    数据库会为每个mongoDB连接创建一个独立的队列,来存放连接的请求,当客户端发送请求,会被存放到该连接队列的末尾,当队列的请求都执行完毕后,才会执行后续的请求。对于实际应用的交错插入、查询,会产生秒级的延迟。


查询

查询 find

查询就是返回一个集合中文档的子集,子集合的范围从0个文档到整个集合。

例如:

db.mydb.user.find({name:”test1”})


指定返回值

有时并不需要返回文档中的所有键和值,遇到这样的情况,使用find 的第二个参数来指定返回键,这样做既可以节省传输的数据量,也可以节省客户端解码文档的时间和内存开销。

例如: db.mydb.user.find({},{age:1,_id:0})

1代表显示,0代表不显示


限制

查询还是有些限制的,数据库所关心的查询文档的值必须是常量,也就是所不可以使用文档的其他键值


条件查询

查询条件

类型 描述 举例

< $t (小于) db.mydb.user.find({age:{$lt:35}})

<=$lte (小于等于) db.mydb.user.find({age:{$lte:35}})

> $gt (大于) db.mydb.user.find({age:{$gt:31}})

>=$gte (大于等于) db.mydb.user.find({age:{$gte:31}})

≠$ne (不等于) db.mydb.user.find({name:{$ne:”test3”}})

模糊查询 /^…/ db.mydb.user.find({name:/^test/})

$OR和$not查询

$in 用来查询一个键的多个值 相对的是$nin

db.mydb.user.find({users:{$in:["dsm","pddd"]}})

db.mydb.user.find({users:{$nin:["dsm","pddd"]}})

$or:比$in更通用一些,是用来查询多个键的任意给定键值,其值是一个数组形式

db.mydb.user.find({$or:[{users:"dsm"},{name:"aaa"}]})

db.mydb.user.find({$or:[{users:{$in:["dsm","pddd"]}},{name:"aaa"}]})

$not是元条件句,就是可以用在任意的其他查询条件上。

$not:是用来查询与特定模式不相符的文档。

db.mydb.user.find({age:{$not:{$mod:[5,0]}}})

$not 与正值表达是联合使用的时候极为有用。


条件句规则

在查询中,类似$lt的键处在内层文档,如修改器$inc则处在外层文档。

如:{age:{$lt:30}} 与  {$inc:{age:1}}

而且一个键可以含有多个条件,但不可以含有多个修改器:

{age:{$lt:30,$gt:20}}  √   

{$inc:{age:1},$set:{age:40}}  × 不能在同一行修改同一个对age的修改


数组查询

$all

对于数组查询中,多个元素的匹配时,需要用到关键键$all. 如下:

db.mydb.insert({shop:”B”,fruit:[“apple”,” peach”,”orange”],size:3})

db.mydb.insert({shop:”C”,fruit:[“mango”,”banana”,” apple”],size:3})

查询既有”apple”又有”banana”的文档:

db.mydb.find({fruit:{$all:[“apple”,”banana”]}})

注:$all 查询不考虑键值的先后顺序问题。


精确匹配

使用[ ]精确匹配数组元素,既要考虑键值的个数,也要考虑元素位置:

db.mydb.find({fruit:[“apple”,”banana”,”orange”]})


下标查询

Key: 代表键。

Index:代表数组下标。

数组键值下标是从0开始。如下:

db.mydb.find({“fruit.1”:“banana”})

查询数组中第二的元素为“banana”的文档。


$size

在数组查询中,$size的查询意义非凡,顾名思义,该键就是查询指定长度的数组。

如:db.mydb.find({fruit:{$size:3}})

但是很不幸的是,它不可以与其他查询子句组合使用(”$lt“、”$gt“);

如:db.mydb.find({fruit:{$size:{$gt:3}}})  是非法的。

但是这种查询可以通过在文档中增加一个size键来实现。

如:db.mydb.update({shop:”A”},{“$push”:{fruit:“Watermelon”},$inc:{size:1}})

db.mydb.find({size:{“$lt”:4}})


$slice

$slice 是用于子集查询,其返回值是一个子集合。如:

db.mydb.find({shop:”A”},{fruit:{$slice:2}})

上面查询表示查询数组的前2个子集。

也可以返回后2个子集:

db.mydb.find({shop:”A”},{fruit:{$slice:-2}})

它也可以接受偏移量[m,n]:

db.mydb.find({shop:”A”},{fruit:{$slice:[1,2]}})

表示跳过第一个,查询2个子集。


内嵌文档查询

单个内嵌文档

db.mydb.km.find({“person.name”:”zhangsan”,”person.age”:25})

这种点的查询方式就是区别于其他普通文档的主要特点,而且为什么对于键名不能使用.这个符号做出了最好的诠释。

注:键值匹配查询,对于内嵌文档值多个或者顺序未知的情况下,是有效的。


复杂内嵌文档

$where查询

需求:查询apple和banana值相等的文档。(就是如何匹配键值相等?)

普通查询是满足不了的。Mongo也没有提供这样的$关键键。只能通过$where表达式来执行:

db.mydb.fruit.find({“$where”:function(){

      if(this.apple==this.banana) return true;

      return false;

}})

等价db.mydb.fruit.find({“$where”:”this.apple==this.banana”})

$where 查询其返回值是表达式返回reture的当前文档。

优点:就是由于它可以使用javascript表达式,可想而知,查询非常灵活、多样。

缺点:使用$where查询,比起普通的查询速度要慢的多。因为其查询原理是将被查询文档转化成javacript对象,然后通过$where表达式去比较,而且还不能使用索引。所以不到万不得已尽量避免使用$where查询。


limit、skip和sort 使用

limit

limit 是限制返回结果集的数量,在find函数后使用该函数。

limit(number): 返回匹配number个文档。这里的number是上限,不是下限。

例如:

db.mydb.fruit.find().limit(3) // 返回匹配到的3个文档

如果结果少于3个,则全部返回。


skip

skip 类似于limit,区别在于:

skip(number): 略过匹配到的前number个文档,返回剩下的文档。

例如:

db.mydb.fruit.find().skip(3)  //略过匹配到的前3个文档,返回余下的所有文档。

如果结果少于3个,则返回空。


sort

sort 是排序函数,它的参数一个文档对象(键、值),键是集合中的键,值是1或-1;

1 代表升序;-1 代表降序。

例如:

db.mydb.fruit.find().sort({apple:1,banana:-1})

由于文档型数据库的数据类型是不规则的,但mongo预定义了数据类型的排序规则。如:{a:[1,2]} 、{a:true}

从小到大 :

1、最小值                  7、二进制                    13、最大值

2、null                      8、对象ID

3、数字                      9、布尔型

4、字符串                  10、日期

5、文档                      11、时间戳

6、数组                      12、正则表达式

实际开发中,三个函数组合使用的情况比较多。

例如(分页:第一页):

  db.mydb.fruit.find().limit(20).sort({apple:1})

第二页:

  db.mydb.fruit.find().limit(20).skip(20).sort({apple:1})


随机抽取文档

方法一

在实际应用中,随机抽取一个或多个文档是非常常见的需求,在mongo中实现起来有点繁琐:

最简单的实现方法:

先计算出一个从0到记录总数之间的随机数,然后采用skip(随机数)方法 。

var total=db.mydb.fruit.count();

var random=Math.floor(Math.random()*total);

  db.mydb.fruit.find().skip(random).limit(1);


方法二

当数据量很大时,skip操作会变的很慢,应该避免使用skip来跳过大量的数据 。

可以采用另一种查询方式:

为每一条记录增设random字段,并赋值为Math.random(),查询时采用$gte和$lte。

db.mydb.fruit.update({banana:1},{$set:{random: Math.random()}})

var rand=Math.random();

db.mydb.fruit.find({random:{$gte:rand}});


方法三

高大上:借助Mongodb对地理空间索引(geospatial indexes)的支持,从而可以在上一个方法的基础上来实现随机记录的获取。

创建地理空间索引

db.mydb.fruit.ensureIndex({random:”2d”})

db.mydb.fruit.update({banana:1},{random:[Math.random,0]})

db. mydb.fruit.find ({random: { $near: [Math.random(), 0] } })


null

在查询中,null有点奇怪,它不仅可以匹配键值为null的文档,而且还可以匹配“不存在”的键。

如果仅仅想要匹配键值为null的文档,既要判断该键值是否为null,还有通过“$exists”判断该键是否存在。

例如:

db.mydb.test.find({z:{$in:[null],$exist:true}})


正则表达式

正值表达式能更灵活有效的匹配字符串。MongoDB使用Perl兼容的正值表达式(PCRE)库来匹配正值表达式,PCRE所支持的正值表达式都能被MongoDB接受。正值表达式也可以匹配自身。

例如:

{name:/jack/}    全匹配

{name:/jack/i}  忽略大小写

{name:/jac?/i}  相似匹配

{name:/^ja/}    模糊查询


聚合查询

count

    最简单的聚合查询就是count查询,它的查询方式跟find是一样的,但是返回值不一样。Find 返回值是文档集,count 返回值是文档数。

  例如:

  db.mydb.fruit.count()    ->查询文档总数

  db.mydb.fruit.count({banana:1}) ->查询限定文档总数


distinct

distinct 是键值去重。其返回值是一个数组。

用法:

db.mydb.fruit.distinct(“键”[,查询条件])

如:

db.mydb.fruit.distinct(“apple”)

db.mydb.fruit.distinct(“apple”,{banana:1})


group

在mongodb里面做group操作有点小复杂,利用group可以将集合中的记录按一个或多个键分组,然后可以聚合每个分组内的文档产生新的结果。

用法:db.mydb.fruit.group({‘key’:{},'$reduce':function(doc,prev){},'initial':{}}) 

key:分组的键;

initial:累加器初始值,分组之后,每一组的reduce函数会调用这个初始文档,并在组内传递累加器;

$reduce:分组处理函数,分组之后会对每组元素遍历处理,该函数两个参数,第一个参数是当前的文档对象和第二个参数是上一次function操作的累计对象;

结果返回值为文档数组:

[{分组键,累加器}]

例如:

db.mydb.fruit.db.group({key:{apple:1},$reduce:function(doc,pre){

    pre.bananaArr.push(doc.banana)

},initial:{bananaArr:[]}})

你可能感兴趣的:(mongod小结)