概念
MongoDB是面向文档的数据库,不是关系型数据库。放弃关系模型的主要原因就是为了获得更加方便的扩展性。
基本思路就是将原来“行”的概念换成更加灵活的“文档”模型。面向文档的一条记录就可以表示非常复杂的层次关系方式可以将文档或者数组内嵌进来,所以用一条记录就可以表示非常复杂的层次关系。
功能
索引,存储JavaScript,聚合,固定集合,文件存储
文档
文档是MongoDB的核心概念。多个键及其关联的值有序地放置在一起就是文档
文档不能有重复的键
区分大小写
集合
集合就是一组文档。类似于关系型数据库里的表
启动MongoDB
windows:进入到MongoDB下面的bin文件夹,运行mongod.exe
查看数据库
show dbs
选择要使用的数据库
use 数据库名
查看集合
show tables
创建集合
db.createCollection(集合名)
删除集合
db.drop_collection(集合名)
查看文档
db.集合名.find()
查看一条文档
db.集合名.findOne()
插入文档
db.集合名.insert({"键":"值"})
更新文档
db.集合名.update({要更新文档的限定条件},{新的文档})
删除文档
db.集合名.remove({要删除文档的限定条件})
使用修改器
通常文档只会有一部分要更新。利用原子的更新修改器,可以使得这种部分更新极为高效。
$set修改器入门
$unset 删除键
"$set"用来指定一个键的值,如果这个键不存在,则创建它,存在就修改
> db.analytics.find()
{ "_id" : ObjectId("5a654d25e2602fccd336b767"), "url" : "www.example.com", "pageviews" : 53 }
> db.analytics.update({"url":"www.example.com"},{"$set":{"message":"python"}})
> db.analytics.find()
{ "_id" : ObjectId("5a654d25e2602fccd336b767"), "url" : "www.example.com", "pageviews" : 53, "message" : "python" }
> db.blog.find()
{ "_id" : ObjectId("5a6550f2e2602fccd336b768"), "title" : "A Blog Post", "content" : "...", "author" : { "name" : "joe", "email" : "joe@example.com" } }
> db.blog.update({"author.name":"joe"},{"$set":{"author.name":"joe schmoe"}})
> db.blog.find()
{ "_id" : ObjectId("5a6550f2e2602fccd336b768"), "title" : "A Blog Post", "content" : "...", "author" : { "name" : "joe schmoe", "email" : "joe@example.com" } }
$inc增加和减少
"inc"修改器用来增加已有键的值,或者在键不存在时创建一个键
> db.games.find()
{ "_id" : ObjectId("5a65544ce2602fccd336b769"), "game" : "pinball", "user" : "joe" }
> db.games.update({"game":"pinball",{"$inc":{"score":50}}})
> db.games.find()
{ "_id" : ObjectId("5a65544ce2602fccd336b769"), "game" : "pinball", "user" : "joe", "score" : 50 }
增加次数$inc,只针对数字类型,如果键存在,则增加,不存在,则创建
{ "_id" : ObjectId("5a654d25e2602fccd336b767"), "url" : "www.example.com", "pageviews" : 52 }
db.analytics.update({"url":"www.example.com"},{"$inc":{"pageviews":1}})
> db.analytics.find()
{ "_id" : ObjectId("5a654d25e2602fccd336b767"), "url" : "www.example.com", "pageviews" : 53 }
数组修改器
数组操作,顾名思义,只能用在值为数组的键上。例如不能对整数做push,也不能对字符串做pop。使用"$set"或"$inc"来修改标量值
如果指定的键已经存在,"push"会向已有的数组末尾加入一个元素,要是没有就会创建一个新的数组。
> db.games.find()
{ "_id" : ObjectId("5a65544ce2602fccd336b769"), "game" : "pinball", "user" : "joe", "score" : 51 }
> db.games.update({"game":"pinball"},{$push:{"comments":{"name":"joe","content":"nice post."}}})
> db.games.find()
{ "_id" : ObjectId("5a65544ce2602fccd336b769"), "game" : "pinball", "user" : "joe", "score" : 51, "comments" : [ { "name" : "joe", "content" : "nice post." } ] }
经常会有这种情况,如果一个值不在数组里面就把它加进去。keyi在查询文档中用"ne"来实现。例如,要是作者不在引文列表中就添加进去,可以这样做
> db.papers.find()
{ "_id" : ObjectId("5a655a0ce2602fccd336b76a"), "authors cited" : "joe" }
> db.papers.update({"authors cited":{"$ne":"Richie"}},{$set:{"authors cited":"Richie"}})
> db.papers.find()
{ "_id" : ObjectId("5a655a0ce2602fccd336b76a"), "authors cited" : "Richie" }
用$addToSet可以避免重复
将"$addToSet"和"$each"组合起来,可以添加多个不同的值,而用"ne"和"push"组合就不能实现。
有几个从数组中删除元素的方法。若是把数组看成队列或栈,可以用"$pop",这个修改器可以从数组任何一端删除元素。
{$pop:{key:1}}从数组末尾删除一个元素,
{$pop:{key:-1}}则从头部删除
有时需要基于特定条件来删除元素,而不仅仅是依据位置,"$pull"可以做到。
> db.lists.find()
{ "_id" : ObjectId("5a6580f9e2602fccd336b76b"), "todo" : [ "dishes", "laundry", "dry cleaning" ] }
> db.lists.update({},{"$pull":{"todo":"laundry"}})
> db.lists.find()
{ "_id" : ObjectId("5a6580f9e2602fccd336b76b"), "todo" : [ "dishes", "dry cleaning" ] }
save Shell帮助程序
save是一个shell函数,可以在文档不存在时插入,存在时更新。它只有一个参数:文档。要是这个文档含有"_id"键,save会调用upsert。否则,会调用插入。
> var x = db.foo.findOne()
> x.num = 42
42
> db.foo.find()
{ "_id" : ObjectId("5a6588e7e2602fccd336b76c"), "num" : 58 }
> db.foo.save(x)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.foo.find()
{ "_id" : ObjectId("5a6588e7e2602fccd336b76c"), "num" : 42 }
更新多个文档
默认情况下,更新只能对符合匹配条件的第一个文档执行操作。要是有多个文档符合条件,其余的文档就没有变化。要使所有匹配到的文档都得到更新,可以设置update的第4个参数为true。
查询
指定返回的键
如果只对某一个键感兴趣,可以使用如下查询返回这些键,需要指定第二个参数
> db.users.find({},{"name":1,"age":1})
{ "_id" : ObjectId("5a61932e438e12ffb5d98bba"), "name" : "joe", "age" : 30 }
也可以用第二个参数来剔除查询结果的某个键。例如,文档中有很多键,但是不希望结果中含有"age"键
> db.users.find({},{"age":0})
{ "_id" : ObjectId("5a61932e438e12ffb5d98bba"), "name" : "joe", "sex" : "male", "location" : "Wisconsin", "favorite book" : "war and peace" }
也可以剔除_id
> db.users.find({},{"_id":0})
{ "name" : "joe", "age" : 30, "sex" : "male", "location" : "Wisconsin", "favorite book" : "war and peace" }
限制
查询哪种商品的数量为0
db.stock.find({"in_stock":0})
查询条件
$lt | < |
$lte | <= |
$gt | > |
$gte | >= |
查询18~30岁之间的用户
> db.users.find({"age":{"$gte":18,"$lte":30}})
OR查询
MongoDB中有两个方式进行OR查询。"$in"可以用来查询一个键的多个值。"$or"更通用一些,用来完成多个键值的任意给定值。"$or"更通用一些,用来完成多个键值的给定值。
$in
> db.users.find({"age":{"$in":[30,18,20]}})
{ "_id" : ObjectId("5a61932e438e12ffb5d98bba"), "name" : "joe", "age" : 30, "sex" : "male", "location" : "Wisconsin", "favorite book" : "war and peace" }
{ "_id" : ObjectId("5a6592e2e2602fccd336b76e"), "name" : "bob", "age" : 18 }
{ "_id" : ObjectId("5a6592ede2602fccd336b76f"), "name" : "lsc", "age" : 20 }
{ "_id" : ObjectId("5a6592f7e2602fccd336b770"), "name" : "jg", "age" : 30 }
与$in相对的是$nin
> db.users.find({"age":{"$nin":[36,20]}})
{ "_id" : ObjectId("5a61932e438e12ffb5d98bba"), "name" : "joe", "age" : 30, "sex" : "male", "location" : "Wisconsin", "favorite book" : "war and peace" }
{ "_id" : ObjectId("5a6592e2e2602fccd336b76e"), "name" : "bob", "age" : 18 }
{ "_id" : ObjectId("5a6592f7e2602fccd336b770"), "name" : "jg", "age" : 30 }
$or
> db.users.find({"$or":[{"age":30},{"name":"lsc"}]})
{ "_id" : ObjectId("5a61932e438e12ffb5d98bba"), "name" : "joe", "age" : 30, "sex" : "male", "location" : "Wisconsin", "favorite book" : "war and peace" }
{ "_id" : ObjectId("5a6592ede2602fccd336b76f"), "name" : "lsc", "age" : 20 }
{ "_id" : ObjectId("5a6592f7e2602fccd336b770"), "name" : "jg", "age" : 30 }
$not
"$not"是元条件句,即可以用在任何其他条件之上。例如,就拿取模运算符"$mod"来说。"$mod"会将查询的值除以第一个给定值,若余数等于第二个给定值则返回该结果。
db.users.find({"id_num":{"mod":[5,1]})
该查询将返回"id_num"值为1,6,11,16等的用户。但要想返回"id_num"为2,3,4,6,7,8,9,10等的用户,就要用到$not了
db.users.find({"id_num":{"$not":{"mod":[5,1]}}})
匹配z值为null的数据
db.c.find({"z":{"$in":[null],"$exists":true}})
$all
如果需要通过多个元素来匹配数组,就要用"$all"了。这样就会匹配一组元素。
> db.food.find()
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
{ "_id" : 2, "fruit" : [ "apple", "kumquat", "orange" ] }
{ "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
> db.food.find({"fruit":{"$all":["apple","banana"]}})
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
{ "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
$size
> db.food.find({"fruit":{"$size":4}})
{ "_id" : 4, "fruit" : [ "cherry", "banana", "apple", "pick" ] }
$slice
假设现在有一个博客文章的文档,要想返回前10条评论。可以:
db.post.findOne(crit,{"comments":{"$slice":10}})
返回后10条评论,可以:
db.post.findOne(crit,{"comments":{"$slice":-10}})
也可以跳过前N个元素,返回后几个元素
db.post.findOne(crit,{"comment":{"$slice":[23,10]}})
这个操作会跳过前23个元素,返回第24~第33个元素。如果数组不够33个元素,则返回第23个元素之后的所有元素
查看前两条文档
> db.users.find().limit(2)
查看第二条之后的文档
> db.users.find().skip(2)
排序,倒序
> db.users.find().sort({age:-1})
正序
> db.users.find().sort({age:1})
索引
创建索引
db.users.ensureIndex({"name":1})
创建唯一索引
db.users.ensureIndex({"name":1},{"unique":true})
找出给定键的所有不同的值。使用时必须指定集合和键
> db.runCommand({"distinct":"集合名","key":"键"})
{ "values" : [ 30, 36, 18, 20 ], "ok" : 1 }